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