| C:\eclipse\workspace\Epsilon_01\src\GameCanvas.java |
1 /**
2 * GameCanvas contains the Canvas for the Epsilon game.
3 * Epsilon is a simple space-shooter-vertical-scroller game.
4 *
5 * Epsilon is available for non-commercial use only!
6 * You can learn from this sources and you can modify them
7 * for learning purposes.
8 *
9 * @author Ziga Hajdukovic
10 * @version 1.0
11 */
12
13 import java.util.*;
14 import javax.microedition.lcdui.*;
15
16 import com.nokia.mid.ui.FullCanvas;
17
18 class GameCanvas extends FullCanvas implements Runnable
19 //class GameCanvas extends Canvas implements Runnable
20 {
21 private final Game midlet;
22
23 public static int canvasWidth;
24 public static int canvasHeight;
25
26 public static boolean gameRunning;
27
28 public static final int SOFTKEY_1 = -6;
29 public static final int SOFTKEY_2 = -7;
30
31 public static boolean menu_command_1;
32 public static boolean menu_command_2;
33
34 public static boolean command_up;
35 public static boolean command_down;
36 public static boolean command_left;
37 public static boolean command_right;
38 public static boolean command_fire;
39
40 public static byte mode;
41 public static final byte MODE_INTRO = 0;
42 public static final byte MODE_GAME = 1;
43 public static final byte MODE_MENU = 2;
44
45 public static int loadingCounter;
46
47 public static Image imgIntro;
48 public static Image imgBackground;
49 public static Image imgPlayer;
50 public static Image imgPlayerFire;
51 public static Image imgEnemy;
52
53 public static int menuScreen;
54 public static final byte MENU_SCR_MAIN = 0;
55 public static final byte MENU_SCR_TEXT_ABOUT = 1;
56 public static final byte MENU_SCR_TEXT_HELP = 2;
57 public static final byte MENU_SCR_TEXT_GAME_OVER = 3;
58
59 public static int menuSelectedOption;
60 public static final byte MENU_OPTION_MAIN_NEW_GAME = 0;
61 public static final byte MENU_OPTION_MAIN_ABOUT = 1;
62 public static final byte MENU_OPTION_MAIN_HELP = 2;
63 public static final byte MENU_OPTION_MAIN_MAX = 2;
64
65 public static final String[] menuScreenMainOptions = { "New game", "About", "Help"};
66
67 public static final String[][] menuScreensTextLines = {
68 { "" },
69 { "About", "", "Epsilon v0.1", "(c) 2005 zigah.", "GFX by Geci." },
70 { "Help", "", "Press LEFT, RIGHT, ", "UP or DOWN", "to move and", "FIRE to shoot." },
71 { "Game Over", "", "Well done!"},
72 };
73
74 public static GameSprite player;
75 public static GameSprite player_fire;
76 public static int player_score;
77
78 public static final byte MAX_ENERGY_PLAYER = 100;
79 public static final byte MAX_ENERGY_PLAYER_FIRE = 10;
80 public static final byte MAX_ENERGY_ENEMY = 10;
81
82 public static Vector enemySprites;
83
84 public static byte max_enemy_sprites = 3;
85
86 public static int space_scroll_y;
87 public static int space_scroll_vy;
88
89 public static Random random = new Random();
90
91 GameCanvas(Game midlet)
92 {
93 this.midlet = midlet;
94
95 canvasWidth = this.getWidth();
96 canvasHeight = this.getHeight();
97
98 loadingCounter = 0;
99 menuScreen = MENU_SCR_MAIN;
100 menuSelectedOption = MENU_OPTION_MAIN_NEW_GAME;
101 mode = MODE_INTRO;
102 gameRunning = true;
103 }
104
105 public void run()
106 {
107 while(gameRunning)
108 {
109 repaint();
110 serviceRepaints();
111
112 switch (mode) {
113 case MODE_INTRO:
114
115 try
116 {
117 if (loadingCounter == 0)
118 {
119 imgIntro = Image.createImage("/intro.png");
120 }
121 else if (loadingCounter == 1)
122 {
123 imgPlayer = Image.createImage("/p.png");
124 }
125 else if (loadingCounter == 2)
126 {
127 imgPlayerFire = Image.createImage("/pf.png");
128 }
129 else if (loadingCounter == 3)
130 {
131 imgEnemy = Image.createImage("/e.png");
132 }
133 else if (loadingCounter == 4)
134 {
135 imgBackground = Image.createImage("/bg.png");
136 }
137 else
138 {
139 // view the intro splash image for a while
140 // it would be better to let user skip intro by pressing a key
141 // but, in a full game project, loading would take forever, anyway, so...
142 try {
143 Thread.sleep(1000);
144 } catch (Exception e) {
145 e.printStackTrace();
146 }
147 // switch mode
148 mode = MODE_MENU;
149 }
150 loadingCounter++;
151 }
152 catch (Exception e) {
153 // ignore loading exception
154 };
155 break;
156
157 case MODE_MENU:
158
159 if (command_up) {
160 command_up = false;
161 menuSelectedOption--;
162 if (menuSelectedOption < 0)
163 menuSelectedOption = 0;
164 }
165 if (command_down) {
166 command_down = false;
167 menuSelectedOption++;
168 if ((menuScreen == MENU_SCR_MAIN) &&
169 (menuSelectedOption > MENU_OPTION_MAIN_MAX))
170 menuSelectedOption = MENU_OPTION_MAIN_MAX;
171 }
172
173 if (menu_command_1)
174 {
175 menu_command_1 = false;
176 if (menuScreen == MENU_SCR_MAIN)
177 {
178 switch(menuSelectedOption)
179 {
180 case MENU_OPTION_MAIN_NEW_GAME:
181 startGame();
182 break;
183
184 case MENU_OPTION_MAIN_ABOUT:
185 menuScreen = MENU_SCR_TEXT_ABOUT;
186 break;
187
188 case MENU_OPTION_MAIN_HELP:
189 menuScreen = MENU_SCR_TEXT_HELP;
190 break;
191 }
192 } else {
193 // all other menu screens go to main menu when OK is selected
194 menuScreen = MENU_SCR_MAIN;
195 menuSelectedOption = MENU_OPTION_MAIN_NEW_GAME;
196 }
197 }
198 if (menu_command_2)
199 {
200 menu_command_2 = false;
201
202 // exit when in main menu
203 if (menuScreen == MENU_SCR_MAIN)
204 midlet.exitRequested();
205 }
206
207 // delay, so the keypress events get their turn...
208 try {
209 Thread.sleep(40);
210 } catch (Exception e) {
211 e.printStackTrace();
212 }
213 break;
214
215 case MODE_GAME:
216
217 // update space background
218 space_scroll_y += space_scroll_vy;
219
220 updateEnemySprites();
221
222 updatePlayerSprite();
223
224 updatePlayerFireSprite();
225
226 // check player <-> enemy <-> player fire collision
227 doCollision();
228
229 // check for game end
230 if (menu_command_2 || player.energy == 0)
231 {
232 menu_command_2 = false;
233 // on softkey_2 end game and return to main menu..
234 endGame();
235 }
236
237 // delay
238 try {
239 Thread.sleep(40);
240 } catch (Exception e) {
241 e.printStackTrace();
242 }
243 break;
244 }
245 }
246 }
247
248 public void paint(Graphics g)
249 {
250 switch(mode)
251 {
252 case MODE_INTRO:
253
254 g.setColor(0x000000);
255 g.fillRect(0, 0, canvasWidth, canvasHeight);
256 if (imgIntro != null) {
257 g.drawImage(imgIntro, canvasWidth/2, canvasHeight/2, Graphics.VCENTER | Graphics.HCENTER);
258 }
259
260 // g.setColor(0xFFFFFF);
261 // g.drawString(""+loadingCounter,0,0,Graphics.LEFT | Graphics.TOP);
262
263 break;
264
265 case MODE_MENU:
266
267 paintSpaceBackground(g);
268
269 switch(menuScreen)
270 {
271 case MENU_SCR_MAIN:
272 paintMainMenu(g);
273 break;
274
275 case MENU_SCR_TEXT_ABOUT:
276 case MENU_SCR_TEXT_HELP:
277 case MENU_SCR_TEXT_GAME_OVER:
278 paintTextMenu(g, menuScreen);
279 break;
280 }
281 break;
282
283 case MODE_GAME:
284
285 paintSpaceBackground(g);
286
287 paintSprite( g, player );
288
289 if (player_fire != null)
290 paintSprite( g, player_fire );
291
292 for (int i=0; i < enemySprites.size(); i++)
293 {
294 paintSprite( g, (GameSprite) enemySprites.elementAt(i) );
295 }
296
297 paintStatusBars(g);
298
299 break;
300 }
301 }
302
303 public void keyPressed(int key)
304 {
305 switch(key) {
306 case SOFTKEY_1:
307 menu_command_1 = true;
308 break;
309
310 case SOFTKEY_2:
311 menu_command_2 = true;
312 break;
313 }
314
315 int game_action = getGameAction(key);
316
317 switch(game_action)
318 {
319 case UP:
320 command_up = true;
321 break;
322
323 case DOWN:
324 command_down = true;
325 break;
326
327 case LEFT:
328 command_left = true;
329 break;
330
331 case RIGHT:
332 command_right = true;
333 break;
334
335 case FIRE:
336 command_fire = true;
337 menu_command_1 = true;
338 break;
339 }
340 }
341
342 public void keyReleased(int key)
343 {
344 int game_action = getGameAction(key);
345
346 switch(game_action)
347 {
348 case UP:
349 command_up = false;
350 break;
351
352 case DOWN:
353 command_down = false;
354 break;
355
356 case LEFT:
357 command_left = false;
358 break;
359
360 case RIGHT:
361 command_right = false;
362 break;
363
364 case FIRE:
365 command_fire = false;
366 break;
367 }
368 }
369
370 public void paintSpaceBackground(Graphics g)
371 {
372 // fill the vast space
373 g.setColor(0x000000);
374 g.fillRect(0, 0, canvasWidth, canvasHeight);
375
376 // init scrolling background image tiling
377 int x = 0;
378 int y = space_scroll_y % imgBackground.getHeight() - imgBackground.getHeight();
379
380 // image is wide enough, so we only need to tile it in the vertical (y) direction
381 while (y < canvasHeight)
382 {
383 g.drawImage(imgBackground, x, y, Graphics.TOP | Graphics.LEFT);
384 g.setClip(0, 0, canvasWidth, canvasHeight);
385
386 y += imgBackground.getHeight();
387 }
388 }
389
390 public void paintMainMenu(Graphics g)
391 {
392 // init font
393 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_LARGE));
394 int menu_y = canvasHeight/2 - 45;
395 for(int i=0; i <= MENU_OPTION_MAIN_MAX; i++)
396 {
397 // paint the main menu options
398 if (i == menuSelectedOption) {
399 g.setColor(0xFFCC00);
400 } else {
401 g.setColor(0xFFFFFF);
402 }
403
404 g.drawString(menuScreenMainOptions[i], canvasWidth/2, menu_y, Graphics.HCENTER | Graphics.TOP);
405
406 menu_y += 30;
407 }
408 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_MEDIUM));
409 g.setColor(0xFFFFFF);
410 // paint softkey_1 label
411 g.drawString("Select", 2, canvasHeight-2, Graphics.LEFT | Graphics.BOTTOM);
412 // paint softkey_2 label
413 g.drawString("Exit", canvasWidth-2, canvasHeight-2, Graphics.RIGHT | Graphics.BOTTOM);
414 }
415
416 public void paintTextMenu(Graphics g, int screen)
417 {
418 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_MEDIUM));
419 g.setColor(0xFFFFFF);
420 int text_line_y = 10;
421 for(int line=0; line < menuScreensTextLines[screen].length; line++)
422 {
423 // paint all the lines of text in this menu screen
424 g.drawString(menuScreensTextLines[screen][line], canvasWidth/2, text_line_y, Graphics.HCENTER | Graphics.TOP);
425
426 text_line_y += 15;
427 }
428 if (screen == MENU_SCR_TEXT_GAME_OVER)
429 {
430 // print score in the game over screen
431 text_line_y += 15;
432 g.drawString("Score: "+ player_score, canvasWidth/2, text_line_y, Graphics.HCENTER | Graphics.TOP);
433 }
434
435 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_MEDIUM));
436 // paint softkey_1 label
437 g.drawString("Ok", 1, canvasHeight-1, Graphics.LEFT | Graphics.BOTTOM);
438 }
439
440 public static void paintSprite(Graphics g, GameSprite spr)
441 {
442 // paint the sprites image at its coordinates
443 g.drawImage(spr.img, spr.x, spr.y, Graphics.TOP | Graphics.LEFT);
444 }
445
446 public static void paintStatusBars(Graphics g)
447 {
448 int max_energy_bar_width = canvasWidth/2;
449
450 // paint the energy bar
451 g.setColor(0xFFFFFF);
452 g.drawRect(5, 10, max_energy_bar_width + 1, 4);
453 g.setColor(0xFFCC00);
454 g.fillRect(6, 11, player.energy * max_energy_bar_width / player.energyMax, 3);
455
456 // paint the score count
457 g.setColor(0xFFFFFF);
458 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_SMALL));
459 g.drawString(""+player_score, canvasWidth-4, 8, Graphics.TOP | Graphics.RIGHT);
460 }
461
462 public void startGame()
463 {
464 // switch to game mode
465 mode = MODE_GAME;
466
467 // initialize player sprite
468 player = new GameSprite(imgPlayer, MAX_ENERGY_PLAYER);
469 player.x = canvasWidth / 2;
470 player.y = canvasHeight - player.h - player.h/2;
471 player_score = 0;
472
473 // intialize the scrolling background
474 space_scroll_y = 0;
475 space_scroll_vy = 1;
476
477 // initialize the enemy sprites list
478 enemySprites = new Vector();
479 }
480
481 public void endGame()
482 {
483 // back to menu mode, set the game over text screen
484 mode = MODE_MENU;
485 menuScreen = MENU_SCR_TEXT_GAME_OVER;
486 menuSelectedOption = MENU_OPTION_MAIN_NEW_GAME;
487
488 // clean up
489 player = null;
490 enemySprites = null;
491 }
492
493 public void updateEnemySprites()
494 {
495 // check if a new enemy has to be generated
496 if( enemySprites.size() < max_enemy_sprites )
497 {
498 GameSprite new_enemy;
499
500 // create a new enemy
501 new_enemy = new GameSprite(imgEnemy, MAX_ENERGY_ENEMY);
502
503 new_enemy.x = Math.abs(random.nextInt()) % canvasWidth;
504 new_enemy.y = -new_enemy.h;
505
506 new_enemy.vx = random.nextInt() % 2;
507 new_enemy.vy = 3 + random.nextInt() % 2;
508
509 // add the new enemy to the enemy sprites list
510 enemySprites.addElement(new_enemy);
511 }
512
513 // move enemy sprites
514 for (int i=0; i < enemySprites.size(); i++)
515 {
516 GameSprite enemy = (GameSprite) enemySprites.elementAt(i);
517
518 enemy.x += enemy.vx;
519 enemy.y += enemy.vy;
520
521 // if enemy is out of screen
522 if ( (enemy.x > canvasWidth) || (enemy.x+enemy.w < 0) ||
523 (enemy.y > canvasHeight) || (enemy.y+enemy.h < 0) )
524 {
525 enemySprites.removeElementAt(i);
526 }
527 }
528 }
529
530 public void updatePlayerSprite()
531 {
532 // move player sprite on command, and check player <-> screen edge collision
533 if (command_up)
534 {
535 player.y -= player.vy;
536 if (player.y < 0)
537 player.y = 0;
538 }
539 if (command_down)
540 {
541 player.y += player.vy;
542 if (player.y > canvasHeight - player.h)
543 player.y = canvasHeight - player.h;
544 }
545 if (command_left)
546 {
547 player.x -= player.vx;
548 if (player.x < 0)
549 player.x = 0;
550 }
551 if (command_right)
552 {
553 player.x += player.vx;
554 if (player.x > canvasWidth - player.w)
555 player.x = canvasWidth - player.w;
556 }
557 if (command_fire)
558 {
559 if (player_fire == null)
560 {
561 player_fire = new GameSprite(imgPlayerFire, MAX_ENERGY_PLAYER_FIRE);
562 player_fire.x = player.x + player.w/2 - player_fire.w/2;
563 player_fire.y = player.y;
564 player_fire.vy = -4;
565 }
566 }
567 }
568
569 public void doCollision()
570 {
571 for (int i=0; i < enemySprites.size(); i++)
572 {
573 GameSprite enemy = (GameSprite) enemySprites.elementAt(i);
574
575 // check player <-> enemy collision
576 if (player.collidesWith(enemy))
577 {
578 // player loses energy
579 player.energy -= player.energyMax/4;
580
581 // enemy sprite is destroyed
582 enemySprites.removeElementAt(i);
583 }
584
585 if (player_fire != null && player_fire.collidesWith(enemy))
586 {
587 // destroy player fire
588 player_fire = null;
589
590 // enemy sprite is destroyed
591 enemySprites.removeElementAt(i);
592
593 // increase player score
594 player_score += 10;
595 }
596 }
597 }
598
599 public void updatePlayerFireSprite()
600 {
601 if (player_fire != null)
602 {
603 player_fire.y += player_fire.vy;
604
605 // destroy player fire when out of screen
606 if (player_fire.y + player_fire.h < 0)
607 player_fire = null;
608 }
609 }
610
611 }
612