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.*;
|
9
|
12 import javax.imageio.*;
|
7
|
13 import javax.swing.*;
|
1
|
14 import java.util.*;
|
6
|
15 import java.io.*;
|
1
|
16 import game.*;
|
|
17
|
8
|
18 import javax.sound.sampled.*;
|
|
19
|
2
|
20
|
18
|
21 enum Sound {
|
|
22 PIECE_PLACED("placed.wav"),
|
|
23 MUSIC_GAME("gamemusic.wav");
|
|
24
|
|
25 final String name;
|
|
26 private Clip clip;
|
|
27
|
|
28 Sound(String name)
|
|
29 {
|
|
30 this.name = name;
|
|
31 }
|
|
32
|
|
33 public boolean initialized()
|
|
34 {
|
|
35 return clip != null;
|
|
36 }
|
|
37
|
|
38 public static void load(String path) throws IOException
|
|
39 {
|
|
40 for (Sound snd : Sound.values()) {
|
|
41 String filename = path + snd.name;
|
|
42 ResourceLoader res = new ResourceLoader(filename);
|
|
43 if (res == null || res.getStream() == null)
|
|
44 {
|
|
45 throw new IOException("Could not load audio resource '"+filename+"'.\n");
|
|
46 }
|
|
47 try {
|
|
48 AudioInputStream is = AudioSystem.getAudioInputStream(res.getStream());
|
|
49 }
|
|
50 catch (UnsupportedAudioFileException e) {
|
|
51 throw new IOException("Unsupported audio file format for '"+filename+"'.\n");
|
|
52 }
|
|
53 catch (IOException e)
|
|
54 {
|
|
55 throw new IOException("Could not load audio resource '"+filename+"'.\n");
|
|
56 }
|
|
57 }
|
|
58 }
|
|
59
|
|
60 public void play()
|
|
61 {
|
|
62 if (clip == null)
|
|
63 return;
|
|
64
|
|
65 clip.setFramePosition(0);
|
|
66 clip.start();
|
|
67 }
|
|
68
|
|
69 public void loop(int n)
|
|
70 {
|
|
71 if (clip == null)
|
|
72 return;
|
|
73
|
|
74 if (n < 0)
|
|
75 clip.loop(Clip.LOOP_CONTINUOUSLY);
|
|
76 else
|
|
77 clip.loop(n);
|
|
78 }
|
|
79
|
|
80 public void stop()
|
|
81 {
|
|
82 if (clip == null)
|
|
83 return;
|
|
84
|
|
85 if (clip.isRunning())
|
|
86 clip.stop();
|
|
87 }
|
|
88
|
|
89 public boolean isPlaying()
|
|
90 {
|
|
91 if (clip == null)
|
|
92 return false;
|
|
93
|
|
94 return clip.isRunning();
|
|
95 }
|
|
96 }
|
|
97
|
1
|
98 class PathInfo
|
|
99 {
|
2
|
100 public int in, inX, inY, out, outX, outY;
|
1
|
101
|
2
|
102 public PathInfo(int in, int inX, int inY, int out, int outX, int outY)
|
|
103 {
|
|
104 this.in = in;
|
|
105 this.inX = inX;
|
|
106 this.inY = inY;
|
|
107
|
|
108 this.out = out;
|
|
109 this.outX = outX;
|
|
110 this.outY = outY;
|
|
111 }
|
1
|
112 }
|
0
|
113
|
8
|
114 /*
|
|
115 class AnimatedElement
|
|
116 {
|
|
117 float x, y, stime, value;
|
|
118 Interpolate lerp;
|
|
119 boolean active;
|
|
120
|
|
121 public AnimatedElement(float x, float y, )
|
|
122 {
|
|
123 stime = 0;
|
|
124 this.x = x;
|
|
125 this.y = y;
|
|
126
|
|
127 }
|
|
128
|
|
129 public animate(float time)
|
|
130 {
|
|
131 if (!active)
|
|
132 {
|
|
133 active = true;
|
|
134 stime = time;
|
|
135 }
|
|
136
|
|
137 float t = (time - stime) / 10.0f;
|
|
138 if (t < 100)
|
|
139 value = lerp.getValue(t);
|
|
140 else
|
|
141 {
|
|
142
|
|
143 }
|
|
144 }
|
|
145
|
|
146 public paint(Graphics2D g, );
|
|
147 {
|
|
148 }
|
|
149 }
|
|
150 */
|
0
|
151
|
1
|
152 class GameBoard
|
0
|
153 {
|
2
|
154 public static final int boardSize = 9;
|
|
155 public static final int boardMiddle = 4;
|
|
156 Piece[][] board;
|
|
157 Piece current;
|
8
|
158 public boolean flagGameOver;
|
7
|
159
|
|
160 int moveX, moveY, movePoint;
|
9
|
161
|
2
|
162 public GameBoard()
|
|
163 {
|
|
164 board = new Piece[boardSize][boardSize];
|
|
165
|
|
166 board[boardMiddle][boardMiddle] = new Piece(PieceType.START);
|
|
167
|
|
168 moveX = boardMiddle;
|
|
169 moveY = boardMiddle - 1;
|
7
|
170 movePoint = 0;
|
8
|
171
|
9
|
172 pieceFinishTurn();
|
8
|
173
|
|
174 flagGameOver = false;
|
2
|
175 }
|
0
|
176
|
7
|
177 public void paint(Graphics2D g, int sx, int sy, float scale)
|
2
|
178 {
|
|
179 for (int y = 0; y < boardSize; y++)
|
|
180 for (int x = 0; x < boardSize; x++)
|
|
181 if (board[x][y] != null)
|
|
182 {
|
6
|
183 AffineTransform save = g.getTransform();
|
|
184
|
4
|
185 board[x][y].paint(g,
|
|
186 sx + (x * scale),
|
|
187 sy + (y * scale),
|
|
188 scale - scale / 10);
|
6
|
189
|
|
190 g.setTransform(save);
|
2
|
191 }
|
|
192 }
|
9
|
193
|
|
194 public void animate(float time)
|
|
195 {
|
|
196 for (int y = 0; y < boardSize; y++)
|
|
197 for (int x = 0; x < boardSize; x++)
|
|
198 if (board[x][y] != null)
|
|
199 {
|
|
200 board[x][y].animate(time);
|
|
201 }
|
10
|
202
|
9
|
203 }
|
1
|
204
|
2
|
205 private boolean isEmpty(int x, int y)
|
|
206 {
|
|
207 return (x >= 0 && x < boardSize && y >= 0 && y < boardSize && board[x][y] == null);
|
|
208 }
|
1
|
209
|
2
|
210 private Piece getPiece(int x, int y)
|
|
211 {
|
|
212 if (x >= 0 && x < boardSize && y >= 0 && y < boardSize)
|
|
213 return board[x][y];
|
|
214 else
|
|
215 return null;
|
|
216 }
|
7
|
217
|
2
|
218 public void pieceRotate(boolean dir)
|
|
219 {
|
9
|
220 if (current != null)
|
|
221 current.rotate(dir);
|
2
|
222 }
|
1
|
223
|
8
|
224 public PathInfo resolvePath(int startX, int startY, int startPoint, boolean mark)
|
7
|
225 {
|
|
226 int x = startX, y = startY;
|
8
|
227 int point = -1;
|
7
|
228
|
|
229 Piece curr = getPiece(startX, startY);
|
|
230 if (curr == null)
|
|
231 return null;
|
9
|
232
|
|
233 /*
|
7
|
234 while (curr != null)
|
|
235 {
|
8
|
236 // curr.(true);
|
|
237 // elements.spawn("", );
|
7
|
238 }
|
9
|
239 */
|
|
240
|
7
|
241 return new PathInfo(startPoint, startX, startY, point, x, y);
|
|
242 }
|
|
243
|
2
|
244 public void pieceFinishTurn()
|
|
245 {
|
|
246 if (current != null)
|
7
|
247 {
|
6
|
248 current.setType(PieceType.LOCKED);
|
8
|
249 PathInfo i = resolvePath(moveX, moveY, movePoint, true);
|
7
|
250
|
|
251 if (i != null)
|
|
252 {
|
|
253 }
|
|
254 }
|
|
255
|
8
|
256 current = new Piece(PieceType.ACTIVE);
|
7
|
257 if (isEmpty(moveX, moveY))
|
2
|
258 {
|
8
|
259 board[moveX][moveY] = current;
|
|
260 }
|
|
261 else
|
|
262 {
|
|
263 PathInfo i = resolvePath(moveX, moveY, movePoint, true);
|
|
264 if (i != null)
|
|
265 board[moveX][moveY] = current;
|
|
266 else
|
|
267 flagGameOver = true;
|
2
|
268 }
|
1
|
269 }
|
|
270 }
|
|
271
|
|
272
|
9
|
273 public class Engine extends JPanel
|
18
|
274 implements Runnable, KeyListener, MouseListener
|
1
|
275 {
|
8
|
276 Thread animThread;
|
|
277 boolean animEnable = false;
|
4
|
278 GameBoard lauta = null;
|
9
|
279 BufferedImage lautaBG = null, lautaBGScaled = null;
|
|
280 Dimension oldDim;
|
8
|
281 float clock;
|
18
|
282 Sound sounds;
|
1
|
283
|
9
|
284 public Engine()
|
2
|
285 {
|
9
|
286 BufferedImage img;
|
8
|
287 clock = 0;
|
4
|
288
|
9
|
289 System.out.print("Engine() constructor\n");
|
|
290
|
4
|
291 try
|
|
292 {
|
18
|
293 ResourceLoader res = new ResourceLoader("graphics/board.png");
|
|
294 lautaBG = ImageIO.read(res.getStream());
|
|
295 sounds.load("sounds/");
|
4
|
296 }
|
|
297 catch (IOException e)
|
|
298 {
|
18
|
299 /*
|
4
|
300 JOptionPane.showMessageDialog(null,
|
18
|
301 "Could not load some of the resources.",
|
4
|
302 "Initialization error",
|
|
303 JOptionPane.ERROR_MESSAGE);
|
18
|
304 */
|
|
305 System.out.print("Could not load some of the resources.\n");
|
|
306 }
|
|
307
|
|
308 lauta = new GameBoard();
|
|
309 addKeyListener(this);
|
|
310 addMouseListener(this);
|
|
311
|
|
312 // Get initial focus
|
|
313 if (!hasFocus())
|
|
314 {
|
|
315 System.out.print("Engine(): requesting focus\n");
|
|
316 requestFocus();
|
4
|
317 }
|
|
318
|
18
|
319 sounds.MUSIC_GAME.loop(-1);
|
8
|
320 }
|
|
321
|
|
322 public void startThreads()
|
|
323 {
|
9
|
324 System.out.print("startThreads()\n");
|
8
|
325 if (animThread == null)
|
|
326 {
|
|
327 animThread = new Thread(this);
|
|
328 animEnable = true;
|
|
329 animThread.start();
|
|
330 }
|
|
331 }
|
|
332
|
|
333 public void stopThreads()
|
|
334 {
|
9
|
335 System.out.print("stopThreads()\n");
|
8
|
336 if (animThread != null)
|
|
337 {
|
|
338 animThread.interrupt();
|
|
339 animEnable = false;
|
|
340 animThread = null;
|
|
341 }
|
2
|
342 }
|
0
|
343
|
18
|
344 public void mousePressed(MouseEvent e) { }
|
|
345 public void mouseEntered(MouseEvent e) { }
|
|
346 public void mouseExited(MouseEvent e) { }
|
|
347 public void mouseReleased(MouseEvent e) { }
|
|
348
|
|
349 public void mouseClicked(MouseEvent e)
|
|
350 {
|
|
351 System.out.print("mouseClicked()\n");
|
|
352 if (!hasFocus())
|
|
353 {
|
|
354 System.out.print("requesting focus\n");
|
|
355 requestFocus();
|
|
356 }
|
|
357 }
|
|
358
|
9
|
359 public void paintComponent(Graphics g)
|
2
|
360 {
|
|
361 Graphics2D g2 = (Graphics2D) g;
|
10
|
362
|
|
363 // Use antialiasing when rendering the game elements
|
0
|
364 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
|
365 RenderingHints.VALUE_ANTIALIAS_ON);
|
4
|
366
|
10
|
367 // Rescale background if component size has changed
|
9
|
368 Dimension dim = getSize();
|
|
369 if (oldDim == null || !dim.equals(oldDim))
|
|
370 {
|
|
371 lautaBGScaled = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
|
|
372 Graphics2D gimg = lautaBGScaled.createGraphics();
|
|
373 gimg.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
|
374 RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
10
|
375
|
|
376 gimg.drawImage(lautaBG, 0, 0, dim.width, dim.height, null);
|
9
|
377 oldDim = dim;
|
|
378 System.out.print("scale changed\n");
|
|
379 }
|
|
380
|
10
|
381 // Background, pieces
|
9
|
382 g2.drawImage(lautaBGScaled, 0, 0, null);
|
7
|
383 lauta.paint(g2, 100, 150, 60);
|
9
|
384
|
10
|
385 // Other elements
|
0
|
386 }
|
|
387
|
9
|
388 public void keyTyped(KeyEvent e)
|
2
|
389 {
|
|
390 }
|
1
|
391
|
2
|
392 public void keyReleased(KeyEvent e)
|
|
393 {
|
|
394 }
|
1
|
395
|
9
|
396 public void keyPressed(KeyEvent e)
|
2
|
397 {
|
9
|
398 System.out.print("lol\n");
|
7
|
399 switch (e.getKeyCode())
|
2
|
400 {
|
7
|
401 case KeyEvent.VK_LEFT:
|
|
402 case KeyEvent.VK_UP:
|
2
|
403 lauta.pieceRotate(false);
|
|
404 break;
|
0
|
405
|
7
|
406 case KeyEvent.VK_RIGHT:
|
|
407 case KeyEvent.VK_DOWN:
|
2
|
408 lauta.pieceRotate(true);
|
|
409 break;
|
|
410
|
7
|
411 case KeyEvent.VK_ENTER:
|
2
|
412 lauta.pieceFinishTurn();
|
|
413 break;
|
|
414 }
|
|
415 }
|
8
|
416
|
|
417 public void run()
|
|
418 {
|
|
419 while (animEnable)
|
|
420 {
|
|
421 clock++;
|
|
422
|
9
|
423 // System.out.print("clock=" + clock + "\n");
|
|
424
|
|
425 lauta.animate(clock);
|
|
426
|
10
|
427 if (clock % 2 == 1)
|
|
428 repaint();
|
9
|
429
|
|
430 try {
|
|
431 Thread.sleep(10);
|
|
432 }
|
|
433
|
|
434 catch (InterruptedException x) {
|
|
435 }
|
8
|
436 }
|
|
437 }
|
0
|
438 }
|