Mercurial > hg > ristipolku
annotate game/Engine.java @ 26:3d4cc47df31a
Cleanups, fix piece rendering and rotation.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 01 Feb 2011 19:18:25 +0200 |
parents | bbac3e4a4b9b |
children | 26adc2827983 |
rev | line source |
---|---|
0 | 1 /* |
9 | 2 * Ristipolku Game Engine |
0 | 3 * (C) Copyright 2011 Matti 'ccr' Hämäläinen <ccr@tnsp.org> |
4 */ | |
9 | 5 package game; |
6 | |
0 | 7 import java.awt.*; |
8 import java.awt.geom.*; | |
1 | 9 import java.awt.event.*; |
7 | 10 import java.awt.image.*; |
11 import java.awt.event.*; | |
25 | 12 import java.awt.font.*; |
9 | 13 import javax.imageio.*; |
7 | 14 import javax.swing.*; |
1 | 15 import java.util.*; |
6 | 16 import java.io.*; |
1 | 17 import game.*; |
18 | |
21 | 19 |
1 | 20 class PathInfo |
21 { | |
2 | 22 public int in, inX, inY, out, outX, outY; |
1 | 23 |
2 | 24 public PathInfo(int in, int inX, int inY, int out, int outX, int outY) |
25 { | |
26 this.in = in; | |
27 this.inX = inX; | |
28 this.inY = inY; | |
29 | |
30 this.out = out; | |
31 this.outX = outX; | |
32 this.outY = outY; | |
33 } | |
1 | 34 } |
0 | 35 |
8 | 36 /* |
37 class AnimatedElement | |
38 { | |
39 float x, y, stime, value; | |
40 Interpolate lerp; | |
41 boolean active; | |
42 | |
43 public AnimatedElement(float x, float y, ) | |
44 { | |
45 stime = 0; | |
46 this.x = x; | |
47 this.y = y; | |
48 | |
49 } | |
50 | |
51 public animate(float time) | |
52 { | |
53 if (!active) | |
54 { | |
55 active = true; | |
56 stime = time; | |
57 } | |
58 | |
59 float t = (time - stime) / 10.0f; | |
60 if (t < 100) | |
61 value = lerp.getValue(t); | |
62 else | |
63 { | |
64 | |
65 } | |
66 } | |
67 | |
68 public paint(Graphics2D g, ); | |
69 { | |
70 } | |
71 } | |
72 */ | |
0 | 73 |
1 | 74 class GameBoard |
0 | 75 { |
2 | 76 public static final int boardSize = 9; |
77 public static final int boardMiddle = 4; | |
78 Piece[][] board; | |
79 Piece current; | |
8 | 80 public boolean flagGameOver; |
7 | 81 |
82 int moveX, moveY, movePoint; | |
9 | 83 |
2 | 84 public GameBoard() |
85 { | |
86 board = new Piece[boardSize][boardSize]; | |
87 | |
88 board[boardMiddle][boardMiddle] = new Piece(PieceType.START); | |
89 | |
90 moveX = boardMiddle; | |
91 moveY = boardMiddle - 1; | |
7 | 92 movePoint = 0; |
8 | 93 |
9 | 94 pieceFinishTurn(); |
8 | 95 |
96 flagGameOver = false; | |
2 | 97 } |
0 | 98 |
7 | 99 public void paint(Graphics2D g, int sx, int sy, float scale) |
2 | 100 { |
101 for (int y = 0; y < boardSize; y++) | |
102 for (int x = 0; x < boardSize; x++) | |
103 if (board[x][y] != null) | |
104 { | |
6 | 105 AffineTransform save = g.getTransform(); |
106 | |
4 | 107 board[x][y].paint(g, |
108 sx + (x * scale), | |
109 sy + (y * scale), | |
110 scale - scale / 10); | |
6 | 111 |
112 g.setTransform(save); | |
2 | 113 } |
114 } | |
9 | 115 |
116 public void animate(float time) | |
117 { | |
118 for (int y = 0; y < boardSize; y++) | |
119 for (int x = 0; x < boardSize; x++) | |
120 if (board[x][y] != null) | |
121 { | |
122 board[x][y].animate(time); | |
123 } | |
10 | 124 |
9 | 125 } |
1 | 126 |
2 | 127 private boolean isEmpty(int x, int y) |
128 { | |
129 return (x >= 0 && x < boardSize && y >= 0 && y < boardSize && board[x][y] == null); | |
130 } | |
1 | 131 |
2 | 132 private Piece getPiece(int x, int y) |
133 { | |
134 if (x >= 0 && x < boardSize && y >= 0 && y < boardSize) | |
135 return board[x][y]; | |
136 else | |
137 return null; | |
138 } | |
7 | 139 |
2 | 140 public void pieceRotate(boolean dir) |
141 { | |
9 | 142 if (current != null) |
143 current.rotate(dir); | |
2 | 144 } |
1 | 145 |
8 | 146 public PathInfo resolvePath(int startX, int startY, int startPoint, boolean mark) |
7 | 147 { |
148 int x = startX, y = startY; | |
8 | 149 int point = -1; |
7 | 150 |
151 Piece curr = getPiece(startX, startY); | |
152 if (curr == null) | |
153 return null; | |
9 | 154 |
155 /* | |
7 | 156 while (curr != null) |
157 { | |
8 | 158 // curr.(true); |
159 // elements.spawn("", ); | |
7 | 160 } |
9 | 161 */ |
162 | |
7 | 163 return new PathInfo(startPoint, startX, startY, point, x, y); |
164 } | |
165 | |
2 | 166 public void pieceFinishTurn() |
167 { | |
168 if (current != null) | |
7 | 169 { |
6 | 170 current.setType(PieceType.LOCKED); |
8 | 171 PathInfo i = resolvePath(moveX, moveY, movePoint, true); |
7 | 172 |
173 if (i != null) | |
174 { | |
175 } | |
176 } | |
177 | |
8 | 178 current = new Piece(PieceType.ACTIVE); |
7 | 179 if (isEmpty(moveX, moveY)) |
2 | 180 { |
8 | 181 board[moveX][moveY] = current; |
182 } | |
183 else | |
184 { | |
185 PathInfo i = resolvePath(moveX, moveY, movePoint, true); | |
186 if (i != null) | |
187 board[moveX][moveY] = current; | |
188 else | |
189 flagGameOver = true; | |
2 | 190 } |
1 | 191 } |
192 } | |
193 | |
194 | |
9 | 195 public class Engine extends JPanel |
18 | 196 implements Runnable, KeyListener, MouseListener |
1 | 197 { |
25 | 198 long startTime; |
199 float gameClock, gameFrames; | |
8 | 200 Thread animThread; |
201 boolean animEnable = false; | |
25 | 202 |
203 Font fontMain, font1, font2; | |
4 | 204 GameBoard lauta = null; |
9 | 205 BufferedImage lautaBG = null, lautaBGScaled = null; |
25 | 206 Dimension lautaDim; |
22 | 207 |
21 | 208 SoundElement[] sounds; |
25 | 209 |
21 | 210 public SoundElement snd(Sound snd) |
211 { | |
212 return sounds[snd.ordinal()]; | |
213 } | |
1 | 214 |
9 | 215 public Engine() |
2 | 216 { |
25 | 217 // Initialize globals |
218 System.out.print("Engine() constructor\n"); | |
219 | |
220 gameClock = 0; | |
221 gameFrames = 0; | |
222 startTime = new Date().getTime(); | |
4 | 223 |
9 | 224 |
25 | 225 // Load resources |
4 | 226 try |
227 { | |
24 | 228 ResourceLoader res = new ResourceLoader("graphics/board.jpg"); |
18 | 229 lautaBG = ImageIO.read(res.getStream()); |
21 | 230 |
25 | 231 try { |
232 res = new ResourceLoader("graphics/font.ttf"); | |
233 fontMain = Font.createFont(Font.TRUETYPE_FONT, res.getStream()); | |
234 font1 = fontMain.deriveFont(24f); | |
235 font2 = fontMain.deriveFont(32f); | |
236 } | |
237 catch (FontFormatException e) | |
238 { | |
239 System.out.print("Could not initialize fonts.\n"); | |
240 } | |
241 | |
21 | 242 sounds = new SoundElement[16]; |
243 for (Sound s : Sound.values()) | |
244 { | |
245 System.out.print(s +" = "+ s.ordinal() +"\n"); | |
23
0741dc117808
Remove sound code for later refactoring.
Matti Hamalainen <ccr@tnsp.org>
parents:
22
diff
changeset
|
246 sounds[s.ordinal()] = new SoundElement("sounds/" + s.getName(), s.isStreaming()); |
21 | 247 } |
4 | 248 } |
249 catch (IOException e) | |
250 { | |
18 | 251 /* |
4 | 252 JOptionPane.showMessageDialog(null, |
21 | 253 e.getMessage(), |
4 | 254 "Initialization error", |
255 JOptionPane.ERROR_MESSAGE); | |
18 | 256 */ |
21 | 257 System.out.print(e.getMessage()); |
18 | 258 } |
259 | |
260 lauta = new GameBoard(); | |
261 addKeyListener(this); | |
262 addMouseListener(this); | |
263 | |
264 // Get initial focus | |
265 if (!hasFocus()) | |
266 { | |
267 System.out.print("Engine(): requesting focus\n"); | |
268 requestFocus(); | |
4 | 269 } |
22 | 270 |
21 | 271 snd(Sound.MUSIC_GAME1).loop(-1); |
8 | 272 } |
273 | |
25 | 274 |
275 public void paintComponent(Graphics g) | |
276 { | |
277 Graphics2D g2 = (Graphics2D) g; | |
278 | |
279 // Use antialiasing when rendering the game elements | |
280 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, | |
281 RenderingHints.VALUE_ANTIALIAS_ON); | |
282 | |
283 g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, | |
284 RenderingHints.VALUE_TEXT_ANTIALIAS_ON); | |
285 | |
286 // Rescale background if component size has changed | |
287 Dimension dim = getSize(); | |
288 if (lautaDim == null || !dim.equals(lautaDim)) | |
289 { | |
290 lautaBGScaled = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB); | |
291 Graphics2D gimg = lautaBGScaled.createGraphics(); | |
292 gimg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, | |
293 RenderingHints.VALUE_INTERPOLATION_BICUBIC); | |
294 | |
295 gimg.drawImage(lautaBG, 0, 0, dim.width, dim.height, null); | |
296 lautaDim = dim; | |
297 | |
298 System.out.print("scale changed\n"); | |
299 } | |
300 | |
301 // Background, pieces | |
302 g2.drawImage(lautaBGScaled, 0, 0, null); | |
303 lauta.paint(g2, 100, 150, 60); | |
304 | |
305 // Scores | |
306 g2.setFont(font1); | |
307 g2.setPaint(Color.white); | |
308 | |
309 | |
310 // Other elements | |
311 long currTime = new Date().getTime(); | |
312 g2.drawString("fps = "+ ((currTime - startTime) / gameFrames), dim.width - 120, 20); | |
313 } | |
314 | |
8 | 315 public void startThreads() |
316 { | |
9 | 317 System.out.print("startThreads()\n"); |
8 | 318 if (animThread == null) |
319 { | |
320 animThread = new Thread(this); | |
321 animEnable = true; | |
322 animThread.start(); | |
323 } | |
324 } | |
325 | |
326 public void stopThreads() | |
327 { | |
9 | 328 System.out.print("stopThreads()\n"); |
8 | 329 if (animThread != null) |
330 { | |
331 animThread.interrupt(); | |
332 animEnable = false; | |
333 animThread = null; | |
334 } | |
22 | 335 |
336 for (Sound s : Sound.values()) | |
337 { | |
338 if (snd(s) != null) | |
339 snd(s).stop(); | |
340 } | |
2 | 341 } |
0 | 342 |
18 | 343 public void mousePressed(MouseEvent e) { } |
344 public void mouseEntered(MouseEvent e) { } | |
345 public void mouseExited(MouseEvent e) { } | |
346 public void mouseReleased(MouseEvent e) { } | |
347 | |
348 public void mouseClicked(MouseEvent e) | |
349 { | |
350 System.out.print("mouseClicked()\n"); | |
351 if (!hasFocus()) | |
352 { | |
353 System.out.print("requesting focus\n"); | |
354 requestFocus(); | |
355 } | |
356 } | |
357 | |
9 | 358 public void keyTyped(KeyEvent e) |
2 | 359 { |
360 } | |
1 | 361 |
2 | 362 public void keyReleased(KeyEvent e) |
363 { | |
364 } | |
1 | 365 |
9 | 366 public void keyPressed(KeyEvent e) |
2 | 367 { |
26
3d4cc47df31a
Cleanups, fix piece rendering and rotation.
Matti Hamalainen <ccr@tnsp.org>
parents:
25
diff
changeset
|
368 // Handle keyboard input |
7 | 369 switch (e.getKeyCode()) |
2 | 370 { |
7 | 371 case KeyEvent.VK_LEFT: |
372 case KeyEvent.VK_UP: | |
2 | 373 lauta.pieceRotate(false); |
374 break; | |
0 | 375 |
7 | 376 case KeyEvent.VK_RIGHT: |
377 case KeyEvent.VK_DOWN: | |
2 | 378 lauta.pieceRotate(true); |
379 break; | |
380 | |
7 | 381 case KeyEvent.VK_ENTER: |
2 | 382 lauta.pieceFinishTurn(); |
23
0741dc117808
Remove sound code for later refactoring.
Matti Hamalainen <ccr@tnsp.org>
parents:
22
diff
changeset
|
383 snd(Sound.PIECE_PLACED).stop(); |
0741dc117808
Remove sound code for later refactoring.
Matti Hamalainen <ccr@tnsp.org>
parents:
22
diff
changeset
|
384 snd(Sound.PIECE_PLACED).play(); |
2 | 385 break; |
386 } | |
387 } | |
8 | 388 |
389 public void run() | |
390 { | |
391 while (animEnable) | |
392 { | |
26
3d4cc47df31a
Cleanups, fix piece rendering and rotation.
Matti Hamalainen <ccr@tnsp.org>
parents:
25
diff
changeset
|
393 // Progress game animation clock |
25 | 394 gameClock++; |
9 | 395 |
26
3d4cc47df31a
Cleanups, fix piece rendering and rotation.
Matti Hamalainen <ccr@tnsp.org>
parents:
25
diff
changeset
|
396 // Animate components |
25 | 397 lauta.animate(gameClock); |
9 | 398 |
26
3d4cc47df31a
Cleanups, fix piece rendering and rotation.
Matti Hamalainen <ccr@tnsp.org>
parents:
25
diff
changeset
|
399 // Repaint with a frame limiter |
25 | 400 if (gameClock % 3 == 1) |
24 | 401 { |
10 | 402 repaint(); |
25 | 403 gameFrames++; |
24 | 404 } |
26
3d4cc47df31a
Cleanups, fix piece rendering and rotation.
Matti Hamalainen <ccr@tnsp.org>
parents:
25
diff
changeset
|
405 |
3d4cc47df31a
Cleanups, fix piece rendering and rotation.
Matti Hamalainen <ccr@tnsp.org>
parents:
25
diff
changeset
|
406 // Sleep for a moment |
9 | 407 try { |
408 Thread.sleep(10); | |
409 } | |
410 catch (InterruptedException x) { | |
411 } | |
8 | 412 } |
413 } | |
0 | 414 } |