| C:\__todo__\tecaj.www\src\Epsilon_04\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 * CHANGES (01 --> 02)
13 * + new player sprite, p.png
14 * + added boss sprite boss1.png
15 * + added tileset t04.png
16 * + added enemy sprites e1.png, e2.png, e3.png
17 * + added fire.png, removed pf.png
18 * + added explosion sprite, exp.png
19 * + moved Image objects for sprites to spriteImage array
20 * + added tileImage
21 * + moved image loading to loadImages()
22 * + setClip in paintSprite
23 * + player sprite frames for left and right movement
24 * + multiple fire sprites + fire_cooldown_wait_frames
25 * + 20 FPS fixed frame rate
26 * + Vector explosionSprites
27 * + updateExplosionSprites()
28 * + doCollision() -> add explosion on collision
29 * + paint explosionSprites
30 * + Level class
31 * + loadLevel(), tile map, and sprite positions
32 * + space and tiles y and vy
33 * + load sprites positions
34 * + level paint
35 * + (scrolling background space layer)
36 * + (scrolling tile layer)
37 * + new (but still random) enemies
38 * + player game over explosion
39 *
40 *
41 * CHANGES (02 -> 03)
42 * + run() if(gameRunning)
43 * + run(), + midlet.display.callSerially(this);
44 * + midlet.startApp(), gameCanvas.run()
45 *
46 * + pause game screen
47 * + new menu scr paused game, with 2 softkey labels
48 * + resume on softkey1
49 * + main menu on softkey2
50 * + hidenotify()
51 * + player.vy += Level.tiles_scroll_vy
52 * + removed automatic enemy sprite generation
53 * + updated player screen edge collision detection
54 * + spriteData array
55 * + damage and score added to GameSprite, see doCollision
56 * + EXPLOSION_FRAME_SMOKE_START
57 * + move player with level scroll
58 * + enemy activation zone
59 * + remove out-of-screen enemies, updated!
60 * + doEnemyAI()
61 * + fire_cooldown_frames_counter moved to GameSprite
62 * + collision updated, vector loop inverted...
63 * + enemyFireSprites Vector, updateEnemyFireSprites() paint ...
64 * + doEnemyAI(), shooting enemies!
65 * + enemy fire sprites <-> player collision
66 * + boss big bada boom explosion, like players...
67 * + god_mode
68 * + boss, moving, shooting
69 * + view and enter hiscore screens
70 * + flow for score view and edit
71 * + import javax.microedition.rms.*;
72 * + import java.io.*;
73 * + loadHighscoreFromRMS(), add call to intro mode, when loading
74 * + isQualified(int score)
75 * + addHighscore(int score, String name)
76 * + getHighscoreData(), highscore helper function
77 * + saveHighscores(), highscore helper function
78 *
79 *
80 * CHANGES (03 -> 04)
81 *
82 * + added visible property to GameSprite, used for enemy paint and update optimization
83 * + BUGFIX> menu option after highscore
84 * + BUGFIX> player cannot be killed by enemy fire
85 * + FPS counter
86 * + 1,3,7 and 9 keys for diagonal movement
87 * + all level_scroll and x,y and vx,vy of sprites are now representations of floats, with factor SHIFT_FACTOR
88 * + level paint, used shifting instead of * and /
89 * + paint and run profiling!
90 * + LEVEL_DONE and GAME_DONE, new menu screens
91 * + new enemy3 types, sinusoidal movement, with shooting in players direction
92 * + new boss2 type
93 * + new enemy4 type, gun turret, shooting in players direction
94 * + new image for boss2 and gun turret enemy4
95 * + player_nukes
96 * + nuke status bar indicators
97 * + nuke background fade fx
98 * + playMusic(), loadMusic(), stopMusic()
99 * + hideNotify() added a call to stop music
100 * + showNotify() added to restart music
101 * +
102 *
103 */
104
105 import java.util.*;
106
107 import javax.microedition.lcdui.*;
108
109 import javax.microedition.rms.*;
110 import java.io.*;
111
112 import com.nokia.mid.ui.FullCanvas;
113
114 import javax.microedition.media.*;
115 import javax.microedition.media.control.*;
116
117 class GameCanvas extends FullCanvas implements Runnable
118 //class GameCanvas extends Canvas implements Runnable
119 {
120 private final Game midlet;
121
122 public static int canvasWidth;
123 public static int canvasHeight;
124
125 public static boolean gameRunning;
126
127 public static final int SOFTKEY_1 = -6;
128 public static final int SOFTKEY_2 = -7;
129
130 public static boolean menu_command_1;
131 public static boolean menu_command_2;
132
133 public static boolean command_up;
134 public static boolean command_down;
135 public static boolean command_left;
136 public static boolean command_right;
137 public static boolean command_fire;
138
139 public static byte mode;
140 public static final byte MODE_INTRO = 0;
141 public static final byte MODE_GAME = 1;
142 public static final byte MODE_MENU = 2;
143
144 public static int loadingCounter;
145
146 public static Image imgIntro;
147 public static Image imgBackground;
148
149 public static Image[] spriteImages;
150 public static final byte SPRITE_IMAGE_PLAYER = 0;
151 public static final byte SPRITE_IMAGE_FIRE = 1;
152 public static final byte SPRITE_IMAGE_BOSS1 = 2;
153 public static final byte SPRITE_IMAGE_BOSS2 = 3;
154 public static final byte SPRITE_IMAGE_ENEMY1 = 4;
155 public static final byte SPRITE_IMAGE_ENEMY2 = 5;
156 public static final byte SPRITE_IMAGE_ENEMY3 = 6;
157 public static final byte SPRITE_IMAGE_ENEMY4 = 7;
158 public static final byte SPRITE_IMAGE_EXPLOSION = 8;
159 public static final byte SPRITE_IMAGE_MAX = 9;
160
161 public static final byte SPRITE_FRAME_PLAYER_LEFT = 0;
162 public static final byte SPRITE_FRAME_PLAYER_CENTER = 1;
163 public static final byte SPRITE_FRAME_PLAYER_RIGHT = 2;
164
165 public static final byte PLAYER_FIRE_COOLDOWN_WAIT_FRAMES = 3;
166 public static final byte ENEMY_FIRE_COOLDOWN_WAIT_FRAMES = 40;
167
168 public static Image tileImage;
169
170 public static int menuScreen;
171 public static final byte MENU_SCR_MAIN = 0;
172 public static final byte MENU_SCR_TEXT_ABOUT = 1;
173 public static final byte MENU_SCR_TEXT_HELP = 2;
174 public static final byte MENU_SCR_TEXT_GAME_OVER = 3;
175 public static final byte MENU_SCR_PAUSE_GAME = 4;
176 public static final byte MENU_SCR_HISCORE_ENTER = 5;
177 public static final byte MENU_SCR_HISCORE_VIEW = 6;
178 public static final byte MENU_SCR_TEXT_LEVEL_DONE = 7;
179 public static final byte MENU_SCR_TEXT_GAME_DONE = 8;
180
181 public static int menuSelectedOption;
182 public static final byte MENU_OPTION_MAIN_NEW_GAME = 0;
183 public static final byte MENU_OPTION_MAIN_HISCORES = 1;
184 public static final byte MENU_OPTION_MAIN_MUSIC_ON_OFF = 2;
185 public static final byte MENU_OPTION_MAIN_ABOUT = 3;
186 public static final byte MENU_OPTION_MAIN_HELP = 4;
187 public static final byte MENU_OPTION_MAIN_MAX = 4;
188
189 public static final String TEXT_ON = " on";
190 public static final String TEXT_OFF = " off";
191
192 public static final String[] menuScreenMainOptions = { "New game", "Highscore", "Music", "About", "Help"};
193
194 public static final String[][] menuScreensTextLines = {
195 { "" },
196 { "About", "", "Epsilon v0.5", "(c) 2005 zigah.", "gfx by geci." },
197 { "Help", "", "Press LEFT, RIGHT, ", "UP or DOWN", "to move and", "FIRE to shoot." },
198 { "Game Over", "", "Try harder!"},
199 { "","Paused!"},
200 { },
201 { },
202 { "Stage clear!", "", "Well done!"},
203 { "Game over!", "", "Superb!"},
204 };
205
206
207 // Highscore
208 public static final byte MAX_SCORES = 5;
209 public static final String SCORE_DB_NAME = "EPS";
210 public static String hiNames[] = { "JOE", "DOE", "LAA", "BIG", "MAC" };
211 public static int hiScores[] = { 300, 200, 150, 100, 50 };
212 private static RecordStore db;
213
214 public static final char[] HI_NAME_ENTER_DEFAULT = {"A","A","A"};
215 public static final byte MAX_HI_NAME_LENGTH = 3;
216 public static char[] hi_name_enter = new char[MAX_HI_NAME_LENGTH];
217 public static byte hi_name_enter_char_pos;
218
219
220 // for debug purposes
221 public boolean god_mode;
222
223 public static GameSprite player;
224 public static Vector playerFireSprites;
225 public static int player_score;
226 public static int player_gameover_explosion_counter;
227 public static final byte PLAYER_GAMEOVER_EXPLOSION_COUNTER_MAX = 40;
228
229 public static int player_nukes;
230 public static int player_nuke_counter = 0;
231 public static final byte PLAYER_NUKES_MAX = 3;
232 public static final byte PLAYER_NUKE_COUNTER_MAX = 16;
233
234 public static boolean activate_boss_energy_bar;
235
236 public static int boss_dead_explosion_counter;
237 public static final byte BOSS_DEAD_EXPLOSION_COUNTER_MAX = 80;
238
239 public static final short FIRE_VELOCITY = (8 << GameSprite.SHIFT_FACTOR);
240 public static final byte MAX_ENEMY_FIRE = 6;
241
242 public static Vector enemyFireSprites;
243
244 public static final byte MAX_ENERGY_PLAYER = 100;
245 public static final byte MAX_ENERGY_PLAYER_FIRE = 10;
246 public static final byte MAX_ENERGY_ENEMY = 10;
247
248 public static Vector explosionSprites;
249
250 public static byte max_enemy_sprites = 3;
251
252 public static final short FIXED_FRAME_TIME = 40;
253
254 public static int global_frame_counter;
255
256 public static Random random = new Random();
257
258 public static boolean PROFILE_ON_SCREEN = false; // for all the profiling drawString calls
259
260 GameCanvas(Game midlet)
261 {
262 this.midlet = midlet;
263
264 canvasWidth = this.getWidth();
265 canvasHeight = this.getHeight();
266
267 loadingCounter = 0;
268 menuScreen = MENU_SCR_MAIN;
269 menuSelectedOption = MENU_OPTION_MAIN_NEW_GAME;
270 mode = MODE_INTRO;
271 gameRunning = true;
272 }
273
274 public static int FPS_frame_counter;
275 public static long FPS_time;
276 public static int FPS;
277
278 public synchronized void run()
279 {
280 if(gameRunning)
281 {
282 long frameStartTime = System.currentTimeMillis();
283 global_frame_counter++;
284
285 FPS_frame_counter++;
286 if (FPS_time + 1000 < frameStartTime)
287 {
288 FPS_time = frameStartTime;
289 FPS = FPS_frame_counter;
290 FPS_frame_counter = 0;
291 System.out.println("FPS:"+ FPS);
292 }
293
294 repaint();
295 //serviceRepaints();
296 midlet.display.callSerially(this);
297
298 switch (mode) {
299 case MODE_INTRO:
300
301 try
302 {
303 if (loadingCounter == 0)
304 {
305 imgIntro = Image.createImage("/intro.png");
306 }
307 else if (loadingCounter == 1)
308 {
309 loadImages();
310 loadMusic();
311 loadHighscoreFromRMS();
312 }
313 else
314 {
315 // view the intro splash image for a while
316 // it would be better to let user skip intro by pressing a key
317 // but, in a full game project, loading would take forever, anyway, so...
318 try {
319 Thread.sleep(1000);
320 } catch (Exception e) {};
321 // switch mode
322 mode = MODE_MENU;
323 playMusic();
324 }
325 loadingCounter++;
326 }
327 catch (Exception e) {
328 // ignore loading exception
329 };
330 break;
331
332 case MODE_MENU:
333
334 if (command_up) {
335 command_up = false;
336 menuSelectedOption--;
337 if (menuSelectedOption < 0)
338 menuSelectedOption = 0;
339
340 if (menuScreen == MENU_SCR_HISCORE_ENTER)
341 {
342 if ( hi_name_enter[hi_name_enter_char_pos] > "A")
343 hi_name_enter[hi_name_enter_char_pos]--;
344 }
345 }
346 if (command_down) {
347 command_down = false;
348 menuSelectedOption++;
349 if ((menuScreen == MENU_SCR_MAIN) &&
350 (menuSelectedOption > MENU_OPTION_MAIN_MAX))
351 menuSelectedOption = MENU_OPTION_MAIN_MAX;
352
353 if (menuScreen == MENU_SCR_HISCORE_ENTER)
354 {
355 if ( hi_name_enter[hi_name_enter_char_pos] < "Z")
356 hi_name_enter[hi_name_enter_char_pos]++;
357 }
358 }
359 if (command_left) {
360 command_left = false;
361
362 if (menuScreen == MENU_SCR_HISCORE_ENTER)
363 {
364 if (hi_name_enter_char_pos > 0)
365 hi_name_enter_char_pos--;
366 }
367 }
368 if (command_right) {
369 command_left = false;
370
371 if (menuScreen == MENU_SCR_HISCORE_ENTER)
372 {
373 if (hi_name_enter_char_pos < MAX_HI_NAME_LENGTH-1)
374 hi_name_enter_char_pos++;
375 }
376 }
377
378 if (menu_command_1)
379 {
380 menu_command_1 = false;
381 if (menuScreen == MENU_SCR_MAIN)
382 {
383 switch(menuSelectedOption)
384 {
385 case MENU_OPTION_MAIN_NEW_GAME:
386
387 // init number of nukes available to player
388 player_nukes = PLAYER_NUKES_MAX;
389
390 // init score
391 player_score = 0;
392
393 startGame((byte) 1);
394 break;
395
396 case MENU_OPTION_MAIN_HISCORES:
397 menuScreen = MENU_SCR_HISCORE_VIEW;
398 break;
399
400 case MENU_OPTION_MAIN_ABOUT:
401 menuScreen = MENU_SCR_TEXT_ABOUT;
402 break;
403
404 case MENU_OPTION_MAIN_MUSIC_ON_OFF:
405 musicOn = !musicOn;
406 if (musicOn)
407 playMusic();
408 else
409 stopMusic();
410 break;
411
412 case MENU_OPTION_MAIN_HELP:
413 menuScreen = MENU_SCR_TEXT_HELP;
414 break;
415 }
416 } else if ( menuScreen == MENU_SCR_PAUSE_GAME) {
417 // resume pressed
418 mode = MODE_GAME;
419 } else if ( menuScreen == MENU_SCR_TEXT_LEVEL_DONE) {
420 // load next level
421 startGame( (byte) (Level.levelno+1) );
422
423 } else if ( menuScreen == MENU_SCR_TEXT_GAME_OVER || menuScreen == MENU_SCR_TEXT_GAME_DONE) {
424 // ok pressed
425 if ( isQualified( player_score ) != -1 )
426 {
427 menuScreen = MENU_SCR_HISCORE_ENTER;
428 // init enter name character position
429 hi_name_enter_char_pos = 0;
430 hi_name_enter = HI_NAME_ENTER_DEFAULT;
431 } else {
432 menuScreen = MENU_SCR_HISCORE_VIEW;
433 }
434 } else if ( menuScreen == MENU_SCR_HISCORE_ENTER) {
435 // save highscore
436
437 String name = new String(hi_name_enter);
438 addHighscore(player_score, name);
439
440 menuScreen = MENU_SCR_HISCORE_VIEW;
441 } else {
442 // all other menu screens go to main menu when OK is selected
443 menuScreen = MENU_SCR_MAIN;
444 menuSelectedOption = MENU_OPTION_MAIN_NEW_GAME;
445 }
446 }
447 if (menu_command_2)
448 {
449 menu_command_2 = false;
450
451 // back to main menu, when end game selected
452 if ( menuScreen == MENU_SCR_PAUSE_GAME) {
453 menuScreen = MENU_SCR_MAIN;
454 } else if (menuScreen == MENU_SCR_MAIN)
455 {
456 midlet.exitRequested();
457 }
458 }
459
460 // delay, so the keypress events get their turn...
461 try {
462 Thread.sleep(40);
463 } catch (Exception e) {};
464 break;
465
466 case MODE_GAME:
467
468 // scroll space and tile background
469 Level.space_scroll_y += Level.space_scroll_vy;
470 Level.tiles_scroll_y += Level.tiles_scroll_vy;
471
472 // top of the level (boss) reached, stop scrolling
473 if (Level.tiles_scroll_y < 0) {
474 Level.tiles_scroll_y = 0;
475 Level.tiles_scroll_vy = 0;
476 }
477
478 // int tiles_scroll_x_range = (Level.LEVEL_WIDTH * Level.TILE_SIZE - canvasWidth);
479 // int player_x_range = canvasWidth - player.w;
480 // Level.tiles_scroll_x = player.x * tiles_scroll_x_range / player_x_range;
481
482
483 // update scroll_x
484 Level.tiles_scroll_x = player.x + (player.w/2 << GameSprite.SHIFT_FACTOR) - (canvasWidth/2 << GameSprite.SHIFT_FACTOR);
485 if ((Level.tiles_scroll_x >> GameSprite.SHIFT_FACTOR) > (Level.LEVEL_WIDTH * Level.TILE_SIZE - canvasWidth)) {
486 Level.tiles_scroll_x = (Level.LEVEL_WIDTH * Level.TILE_SIZE - canvasWidth) << GameSprite.SHIFT_FACTOR;
487 }
488
489 if (Level.tiles_scroll_x < 0) {
490 Level.tiles_scroll_x = 0;
491 }
492
493 updatePlayerSprite();
494 updatePlayerFireSprites();
495
496 updateEnemySprites();
497 updateEnemyFireSprites();
498
499 updateExplosionSprites();
500
501 // check player <-> enemy <-> player fire collision
502 doCollision();
503
504 // check for game end
505 checkEndGame();
506
507 if (menu_command_2)
508 {
509 menu_command_2 = false;
510 // on softkey_2 activate pause game menu
511 mode = MODE_MENU;
512 menuScreen = MENU_SCR_PAUSE_GAME;
513 }
514
515 // calc. delay
516 long frameTime = System.currentTimeMillis() - frameStartTime;
517 if (frameTime < FIXED_FRAME_TIME)
518 {
519 try {
520 Thread.sleep( FIXED_FRAME_TIME - frameTime );
521 } catch (Exception e) {};
522 }
523 break;
524 }
525 }
526 }
527
528
529 public byte PAINT_PROFILE_TIMES_MAX = 4;
530 public long[] paint_profile_times = new long[PAINT_PROFILE_TIMES_MAX*2];
531 public String[] paint_profile_labels = { " ", " ", " ", " ", " " };
532 public int paint_profile_times_index_counter;
533
534 public void paint_profileStart(int idx, String label) {
535 paint_profile_times_index_counter = idx*2;
536 paint_profile_times_index_counter = idx*2;
537 paint_profile_labels[paint_profile_times_index_counter / 2] = label;
538 paint_profile_times[paint_profile_times_index_counter] = System
539 .currentTimeMillis();
540 paint_profile_times_index_counter++;
541 }
542
543 public void paint_profileEnd() {
544 paint_profile_times[paint_profile_times_index_counter] = paint_profile_times[paint_profile_times_index_counter]
545 + (System.currentTimeMillis() - paint_profile_times[paint_profile_times_index_counter - 1]);
546 }
547
548 public synchronized void paint(Graphics g)
549 {
550 paint_profile_times_index_counter = 0;
551 switch(mode)
552 {
553 case MODE_INTRO:
554
555 g.setColor(0x000000);
556 g.fillRect(0, 0, canvasWidth, canvasHeight);
557 if (imgIntro != null) {
558 g.drawImage(imgIntro, canvasWidth/2, canvasHeight/2, Graphics.VCENTER | Graphics.HCENTER);
559 }
560
561 // g.setColor(0xFFFFFF);
562 // g.drawString(""+loadingCounter,0,0,Graphics.LEFT | Graphics.TOP);
563
564 break;
565
566 case MODE_MENU:
567
568 Level.paintSpaceBackground(g);
569
570 switch(menuScreen)
571 {
572 case MENU_SCR_MAIN:
573 paintMainMenu(g);
574 break;
575
576 case MENU_SCR_TEXT_ABOUT:
577 case MENU_SCR_TEXT_HELP:
578 case MENU_SCR_TEXT_GAME_OVER:
579 case MENU_SCR_TEXT_GAME_DONE:
580 case MENU_SCR_TEXT_LEVEL_DONE:
581 case MENU_SCR_PAUSE_GAME:
582 paintTextMenu(g, menuScreen);
583 break;
584 case MENU_SCR_HISCORE_VIEW:
585 paintHiscoreView(g);
586 break;
587 case MENU_SCR_HISCORE_ENTER:
588 paintHiscoreEnter(g);
589 break;
590 }
591 break;
592
593 case MODE_GAME:
594
595 paint_profileStart(0,"BG");
596 Level.paintSpaceBackground(g);
597 paint_profileEnd();
598 paint_profileStart(1,"TL");
599 Level.paintTiles(g);
600 paint_profileEnd();
601
602 paint_profileStart(2,"SP");
603 paintSprite( g, player );
604
605 for (int i=0; i < Level.enemySprites.size(); i++)
606 {
607 GameSprite enemy = (GameSprite) Level.enemySprites.elementAt(i);
608 if (enemy.visible)
609 paintSprite( g, enemy );
610 }
611
612 for (int i=0; i < explosionSprites.size(); i++)
613 paintSprite( g, (GameSprite) explosionSprites.elementAt(i) );
614
615 for (int i=0; i < playerFireSprites.size(); i++)
616 paintSprite( g, (GameSprite) playerFireSprites.elementAt(i));
617
618 for (int i=0; i < enemyFireSprites.size(); i++)
619 paintSprite( g, (GameSprite) enemyFireSprites.elementAt(i));
620
621 paint_profileEnd();
622
623 paint_profileStart(3,"ST");
624 paintStatusBars(g);
625 paint_profileEnd();
626
627 if (GameCanvas.PROFILE_ON_SCREEN) {
628 for (int p = 0; p < PAINT_PROFILE_TIMES_MAX; p++) {
629 g.setColor(0x000000);
630 g.drawString(paint_profile_labels[p] + " "
631 + paint_profile_times[p * 2 + 1], 2, 20 + 20 * p,
632 Graphics.LEFT | Graphics.TOP);
633 g.setColor(0xFFFFFF);
634 g.drawString(paint_profile_labels[p] + " "
635 + paint_profile_times[p * 2 + 1], 2 - 1,
636 20 + 20 * p - 1, Graphics.LEFT | Graphics.TOP);
637 }
638 }
639
640
641 break;
642 }
643 }
644
645 public void keyPressed(int key)
646 {
647 switch(key) {
648 case SOFTKEY_1:
649 menu_command_1 = true;
650 break;
651
652 case SOFTKEY_2:
653 menu_command_2 = true;
654 break;
655
656 // TODO: debug, temp, remove
657 case KEY_POUND:
658 god_mode = !god_mode;
659 break;
660 case KEY_STAR:
661 PROFILE_ON_SCREEN = !PROFILE_ON_SCREEN;
662 break;
663 case KEY_NUM1:
664 command_up = true;
665 command_left = true;
666 break;
667 case KEY_NUM3:
668 command_up = true;
669 command_right = true;
670 break;
671 case KEY_NUM7:
672 command_down = true;
673 command_left = true;
674 break;
675 case KEY_NUM9:
676 command_down = true;
677 command_right = true;
678 break;
679 case KEY_NUM0:
680 if (player_nuke_counter == 0 && player_nukes > 0)
681 {
682 player_nukes--;
683 player_nuke_counter = PLAYER_NUKE_COUNTER_MAX;
684 }
685 break;
686 }
687
688 int game_action = getGameAction(key);
689
690 switch(game_action)
691 {
692 case UP:
693 command_up = true;
694 break;
695
696 case DOWN:
697 command_down = true;
698 break;
699
700 case LEFT:
701 command_left = true;
702 break;
703
704 case RIGHT:
705 command_right = true;
706 break;
707
708 case FIRE:
709 command_fire = true;
710 menu_command_1 = true;
711 break;
712 }
713 }
714
715 public void keyReleased(int key)
716 {
717 int game_action = getGameAction(key);
718
719 switch(key)
720 {
721 case KEY_NUM1:
722 command_up = false;
723 command_left = false;
724 break;
725 case KEY_NUM3:
726 command_up = false;
727 command_right = false;
728 break;
729 case KEY_NUM7:
730 command_down = false;
731 command_left = false;
732 break;
733 case KEY_NUM9:
734 command_down = false;
735 command_right = false;
736 break;
737 }
738
739 switch(game_action)
740 {
741 case UP:
742 command_up = false;
743 break;
744
745 case DOWN:
746 command_down = false;
747 break;
748
749 case LEFT:
750 command_left = false;
751 break;
752
753 case RIGHT:
754 command_right = false;
755 break;
756
757 case FIRE:
758 command_fire = false;
759 menu_command_1 = false;
760 break;
761 }
762 }
763
764 public void paintMainMenu(Graphics g)
765 {
766 // init font
767 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_LARGE));
768 int menu_y = canvasHeight/2 - 45;
769 for(int i=0; i <= MENU_OPTION_MAIN_MAX; i++)
770 {
771 // paint the main menu options
772 if (i == menuSelectedOption) {
773 g.setColor(0xFFCC00);
774 } else {
775 g.setColor(0xFFFFFF);
776 }
777
778 String option_text = menuScreenMainOptions[i];
779
780 if (i == MENU_OPTION_MAIN_MUSIC_ON_OFF)
781 {
782 option_text = option_text + (musicOn ? TEXT_ON : TEXT_OFF);
783 }
784 g.drawString(option_text, canvasWidth/2, menu_y, Graphics.HCENTER | Graphics.TOP);
785
786 menu_y += 20;
787 }
788 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_MEDIUM));
789 g.setColor(0xFFFFFF);
790 // paint softkey_1 label
791 g.drawString("Select", 2, canvasHeight-2, Graphics.LEFT | Graphics.BOTTOM);
792 // paint softkey_2 label
793 g.drawString("Exit", canvasWidth-2, canvasHeight-2, Graphics.RIGHT | Graphics.BOTTOM);
794 }
795
796 public void paintTextMenu(Graphics g, int screen)
797 {
798 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_MEDIUM));
799 g.setColor(0xFFFFFF);
800 int text_line_y = 10;
801 for(int line=0; line < menuScreensTextLines[screen].length; line++)
802 {
803 // paint all the lines of text in this menu screen
804 g.drawString(menuScreensTextLines[screen][line], canvasWidth/2, text_line_y, Graphics.HCENTER | Graphics.TOP);
805
806 text_line_y += 15;
807 }
808 if (screen == MENU_SCR_TEXT_GAME_OVER || screen == MENU_SCR_TEXT_LEVEL_DONE || screen == MENU_SCR_TEXT_GAME_DONE)
809 {
810 // print score in the game over screen
811 text_line_y += 15;
812 g.drawString("Score: "+ player_score, canvasWidth/2, text_line_y, Graphics.HCENTER | Graphics.TOP);
813 }
814
815 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_MEDIUM));
816
817 if (menuScreen == MENU_SCR_PAUSE_GAME )
818 {
819 // paint softkey_1 label
820 g.drawString("Resume", 1, canvasHeight-1, Graphics.LEFT | Graphics.BOTTOM);
821 // paint softkey_2 label
822 g.drawString("End game", canvasWidth-1, canvasHeight-1, Graphics.RIGHT | Graphics.BOTTOM);
823 }
824 else
825 {
826 // paint softkey_1 label
827 g.drawString("Ok", 1, canvasHeight-1, Graphics.LEFT | Graphics.BOTTOM);
828 }
829 }
830
831 public static void paintHiscoreView(Graphics g)
832 {
833 g.setColor(0xFFFFFF);
834
835 g.drawString("Highscore!", canvasWidth/2, 2, Graphics.HCENTER | Graphics.TOP);
836
837 for (int i=0; i < MAX_SCORES; i++)
838 {
839 g.drawString(hiNames[i], canvasWidth*1/4, 20 + 20*i, Graphics.LEFT | Graphics.TOP);
840 g.drawString(""+hiScores[i], canvasWidth*3/4, 20 + 20*i, Graphics.RIGHT | Graphics.TOP);
841 }
842
843 // paint softkey_1 label
844 g.drawString("Ok", 1, canvasHeight-1, Graphics.LEFT | Graphics.BOTTOM);
845 }
846 public static void paintHiscoreEnter(Graphics g)
847 {
848 g.setColor(0xFFFFFF);
849
850 g.drawString("Enter name:", canvasWidth/2, canvasHeight*1/4, Graphics.HCENTER | Graphics.BOTTOM);
851
852 for (int i=0; i < MAX_HI_NAME_LENGTH; i++)
853 {
854 if (i == hi_name_enter_char_pos)
855 g.setColor(0xFFFF00);
856 else
857 g.setColor(0xFFFFFF);
858 g.drawChar(hi_name_enter[i], canvasWidth/2 - 12 + 12*i, canvasHeight*2/4, Graphics.HCENTER | Graphics.BOTTOM);
859 }
860
861 g.setColor(0xFFFFFF);
862 g.drawString("Score: "+ player_score, canvasWidth/2, canvasHeight*3/4, Graphics.HCENTER | Graphics.BOTTOM);
863
864 // paint softkey_1 label
865 g.drawString("Save", 1, canvasHeight-1, Graphics.LEFT | Graphics.BOTTOM);
866 }
867
868 public static void paintSprite(Graphics g, GameSprite spr)
869 {
870 // set the clip window
871 int dx = (spr.x - Level.tiles_scroll_x) >> GameSprite.SHIFT_FACTOR;
872 int dy = (spr.y - Level.tiles_scroll_y) >> GameSprite.SHIFT_FACTOR;
873 int cx = dx;
874 int cy = dy;
875 int cw = GameSprite.spriteImageFrameWidths[spr.imageId];
876 int ch = spr.h;
877 g.setClip(cx, cy, cw, ch);
878
879 // check clip window coordinates, if out of screen
880 if (cx < 0)
881 {
882 cw += cx;
883 cx = 0;
884 }
885 if (cy < 0)
886 {
887 ch += cy;
888 cy = 0;
889 }
890
891 // calculate the x coordinate of where to start the image paint, so our frame will be seen through the clip window
892 dx = dx - spr.frameId * GameSprite.spriteImageFrameWidths[spr.imageId];
893
894 // paint the sprites image at the calculated coordinates
895 g.drawImage(spriteImages[spr.imageId], dx, dy, Graphics.TOP | Graphics.LEFT);
896
897 // restore the clip window
898 g.setClip(0, 0, canvasWidth, canvasHeight);
899 }
900
901 public static void paintStatusBars(Graphics g)
902 {
903 int max_energy_bar_width = canvasWidth/2;
904
905 // paint the energy bar
906 g.setColor(0xFFFFFF);
907 g.drawRect(5, 5, max_energy_bar_width + 1, 4);
908 g.setColor(0xFFCC00);
909 g.fillRect(6, 6, player.energy * max_energy_bar_width / player.energyMax, 3);
910
911 if ( activate_boss_energy_bar)
912 {
913 // paint the energy bar
914 g.setColor(0xFFFFFF);
915 g.drawRect(5, 12, max_energy_bar_width + 1, 4);
916 g.setColor(0xFF9900);
917 g.fillRect(6, 13, Level.boss.energy * max_energy_bar_width / Level.boss.energyMax, 3);
918 }
919
920 // paint the score count
921 g.setColor(0xFFFFFF);
922 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_SMALL));
923 g.drawString(""+player_score, canvasWidth-4, 8, Graphics.TOP | Graphics.RIGHT);
924
925 // paint number of nukes
926 for (int i=0; i < PLAYER_NUKES_MAX; i++)
927 {
928 g.setColor(0xFFFF00);
929 int x = canvasWidth - (3-i) * (5+3);
930 int y = canvasHeight - 8;
931 if ((3-i) <= player_nukes)
932 {
933 g.fillRect(x,y,5,5);
934 }
935 g.setColor(0xFFFFFF);
936 g.drawRect(x,y,5,5);
937 }
938
939 if (PROFILE_ON_SCREEN)
940 {
941 // paint the FPS
942 g.setColor(0xFFFFFF);
943 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_SMALL));
944 g.drawString("FPS: "+FPS, 1, canvasHeight-2, Graphics.BOTTOM | Graphics.LEFT);
945 }
946 }
947
948 public void startGame(byte load_level_no)
949 {
950 player_gameover_explosion_counter = -1;
951 player_nuke_counter = 0;
952
953 activate_boss_energy_bar = false;
954 boss_dead_explosion_counter = -1;
955
956 // initialize the explosion sprite list
957 explosionSprites = new Vector();
958
959 // initialize the player fire list
960 playerFireSprites = new Vector();
961
962 // initialize the enemy fire list
963 enemyFireSprites = new Vector();
964
965 // init level tiles position to horizontal center and vertical bottom
966 Level.tiles_scroll_x = (Level.LEVEL_WIDTH * Level.TILE_SIZE / 2 - canvasWidth /2) << GameSprite.SHIFT_FACTOR;
967 Level.tiles_scroll_y = (Level.LEVEL_HEIGHT * Level.TILE_SIZE - canvasHeight - 1) << GameSprite.SHIFT_FACTOR;
968
969 Level.loadLevel( load_level_no );
970
971 // switch to game mode
972 mode = MODE_GAME;
973 }
974
975 public static final byte GAME_END_NONE = 0;
976 public static final byte GAME_END_LOSE = 1;
977 public static final byte GAME_END_WIN = 2;
978
979 public void checkEndGame()
980 {
981 byte game_end = GAME_END_NONE;
982 // check for game end
983 if ( (player.energy <= 0) && (player_gameover_explosion_counter == 0) )
984 {
985 game_end = GAME_END_LOSE;
986 } else if ( (Level.boss.energy <= 0) && (boss_dead_explosion_counter == 0) )
987 {
988 game_end = GAME_END_WIN;
989 }
990 if (game_end > GAME_END_NONE)
991 {
992 // back to menu mode, set the game or lever over text screen
993 mode = MODE_MENU;
994 if (game_end == GAME_END_LOSE)
995 {
996 menuScreen = MENU_SCR_TEXT_GAME_OVER;
997 } else {
998 if (Level.levelno == Level.MAX_LEVELS)
999 menuScreen = MENU_SCR_TEXT_GAME_DONE;
1000 else
1001 menuScreen = MENU_SCR_TEXT_LEVEL_DONE;
1002 }
1003
1004 // clean up
1005 player = null;
1006 Level.enemySprites = null;
1007 }
1008 }
1009
1010 public void updateEnemySprites()
1011 {
1012 // move enemy sprites
1013 int i = Level.enemySprites.size()-1;
1014 while (i >= 0)
1015 {
1016 GameSprite enemy = (GameSprite) Level.enemySprites.elementAt(i);
1017
1018 if ( (enemy.y - Level.tiles_scroll_y > (canvasHeight << GameSprite.SHIFT_FACTOR)) )
1019 {
1020 // remove out-of-screen enemies
1021 Level.enemySprites.removeElementAt(i);
1022 i--;
1023 }
1024 else
1025 {
1026 //System.out.println(enemy.y +"-"+ Level.tiles_scroll_y +">"+ Level.ENEMY_AI_ACTIVATION_ZONE_Y);
1027 // do the AI move, shoot and other tricks
1028 if ( enemy.y - Level.tiles_scroll_y > (Level.ENEMY_AI_ACTIVATION_ZONE_Y << GameSprite.SHIFT_FACTOR) )
1029 {
1030 enemy.visible = true;
1031 doEnemyAI( enemy );
1032 i--;
1033 } else {
1034 enemy.visible = false;
1035 // optimization
1036 // but enemySprites must be ordered by the sprites" y coordinate !
1037 // they are in this case, because of loadLevel
1038 break;
1039 }
1040 }
1041 }
1042 if (boss_dead_explosion_counter > 0)
1043 {
1044 boss_dead_explosion_counter--;
1045 }
1046 }
1047
1048 public void doEnemyAI( GameSprite sprite )
1049 {
1050
1051 // System.out.println("doing enemy ai for "+sprite.spriteId);
1052
1053 switch (sprite.spriteId)
1054 {
1055 case Level.SPRITE_ID_ENEMY1:
1056 break;
1057 case Level.SPRITE_ID_ENEMY1_SHOOTING:
1058
1059 shootEnemyFire(sprite, Level.SPRITE_ID_FIRE2, (byte) 1);
1060
1061 break;
1062 case Level.SPRITE_ID_ENEMY2:
1063 break;
1064 case Level.SPRITE_ID_ENEMY2_SHOOTING:
1065
1066 shootEnemyFire(sprite, Level.SPRITE_ID_FIRE2, (byte) 1);
1067
1068 break;
1069 case Level.SPRITE_ID_ENEMY4_SHOOTING:
1070
1071 shootEnemyFireTowardPlayer(sprite, Level.SPRITE_ID_FIRE3, (byte) 2);
1072
1073 break;
1074 case Level.SPRITE_ID_ENEMY3:
1075 case Level.SPRITE_ID_ENEMY3_SINUS:
1076 case Level.SPRITE_ID_ENEMY3_SINUS_SHOOTING:
1077
1078 // animate sprite to next sprite frame every 3 frames
1079 if (global_frame_counter % 3 == 0)
1080 sprite.frameId = (byte) ( (sprite.frameId + 1) % (sprite.frameIdMax+1));
1081
1082 // sinusoidal movement
1083 if (sprite.spriteId == Level.SPRITE_ID_ENEMY3_SINUS || sprite.spriteId == Level.SPRITE_ID_ENEMY3_SINUS_SHOOTING)
1084 {
1085 int tx = Math.abs( (sprite.y >> 1) % 360);
1086 sprite.vx = sin[tx] >> 4;
1087
1088 // int ty = Math.abs(global_frame_counter % 360);
1089 // sprite.vy = - sin[ty] >> 5;
1090 }
1091 if (sprite.spriteId == Level.SPRITE_ID_ENEMY3_SINUS)
1092 {
1093 shootEnemyFireTowardPlayer(sprite, Level.SPRITE_ID_FIRE3, (byte) 2);
1094 }
1095
1096 break;
1097 case Level.SPRITE_ID_BOSS1:
1098
1099 activate_boss_energy_bar = true;
1100
1101 // boss fire
1102 if (sprite.fire_cooldown_frames_counter <= 0)
1103 {
1104 GameSprite new_fire;
1105
1106 new_fire = new GameSprite(Level.SPRITE_ID_FIRE2);
1107 new_fire.frameId = 1;
1108 new_fire.x = sprite.x + ((sprite.w - 5 - new_fire.w) << GameSprite.SHIFT_FACTOR);
1109 new_fire.y = sprite.y + (sprite.h << GameSprite.SHIFT_FACTOR);
1110 new_fire.vx = 0;
1111 new_fire.vy = sprite.vy + FIRE_VELOCITY/2;
1112 enemyFireSprites.addElement(new_fire);
1113
1114 new_fire = new GameSprite(Level.SPRITE_ID_FIRE2);
1115 new_fire.frameId = 1;
1116 new_fire.x = sprite.x + (5 << GameSprite.SHIFT_FACTOR);
1117 new_fire.y = sprite.y + (sprite.h << GameSprite.SHIFT_FACTOR);
1118 new_fire.vx = 0;
1119 new_fire.vy = sprite.vy + FIRE_VELOCITY/2;
1120 enemyFireSprites.addElement(new_fire);
1121
1122 new_fire = new GameSprite(Level.SPRITE_ID_FIRE3);
1123 new_fire.frameId = 2;
1124 new_fire.x = sprite.x + ((sprite.w / 2 - new_fire.w / 2) << GameSprite.SHIFT_FACTOR);
1125 new_fire.y = sprite.y + (sprite.h << GameSprite.SHIFT_FACTOR);
1126 new_fire.vx = 0;
1127 new_fire.vy = sprite.vy + FIRE_VELOCITY;
1128 enemyFireSprites.addElement(new_fire);
1129
1130 sprite.fire_cooldown_frames_counter = ENEMY_FIRE_COOLDOWN_WAIT_FRAMES;
1131 } else {
1132 // extra cooldown, boss only
1133 sprite.fire_cooldown_frames_counter--;
1134 }
1135
1136 // boss move
1137 if (sprite.x + (sprite.w << GameSprite.SHIFT_FACTOR) > (((Level.LEVEL_WIDTH * Level.TILE_SIZE) - (Level.TILE_SIZE/2)) << GameSprite.SHIFT_FACTOR) )
1138 sprite.vx = -(1 << GameSprite.SHIFT_FACTOR);
1139 if (sprite.x < (Level.TILE_SIZE/2 << GameSprite.SHIFT_FACTOR) )
1140 sprite.vx = 1 << GameSprite.SHIFT_FACTOR;
1141
1142 break;
1143
1144 case Level.SPRITE_ID_BOSS2:
1145 // boss move
1146 if (sprite.x + (sprite.w << GameSprite.SHIFT_FACTOR) > (((Level.LEVEL_WIDTH * Level.TILE_SIZE) - (Level.TILE_SIZE/2)) << GameSprite.SHIFT_FACTOR) )
1147 sprite.vx = -(1 << GameSprite.SHIFT_FACTOR);
1148 if (sprite.x < (Level.TILE_SIZE/2 << GameSprite.SHIFT_FACTOR) )
1149 sprite.vx = 1 << GameSprite.SHIFT_FACTOR;
1150
1151 int ty = Math.abs(sprite.x % 360);
1152 sprite.vy = - sin[ty] >> 5;
1153 break;
1154 }
1155
1156 // move the sprite
1157 sprite.x += sprite.vx;
1158 sprite.y += sprite.vy;
1159
1160 if (sprite.fire_cooldown_frames_counter > 0)
1161 sprite.fire_cooldown_frames_counter--;
1162 }
1163
1164 public GameSprite shootEnemyFire(GameSprite sprite, byte fire_sprite_id, byte fire_sprite_frame_id)
1165 {
1166 GameSprite new_fire = null;
1167 if (enemyFireSprites.size() < MAX_ENEMY_FIRE && sprite.fire_cooldown_frames_counter <= 0)
1168 {
1169 // System.out.println("adding fire sprite ... ");
1170 new_fire = new GameSprite(fire_sprite_id);
1171 new_fire.frameId = fire_sprite_frame_id;
1172 new_fire.x = sprite.x + (sprite.w / 2 << GameSprite.SHIFT_FACTOR);
1173 new_fire.y = sprite.y + (sprite.h << GameSprite.SHIFT_FACTOR);
1174 new_fire.vx = 0;
1175 new_fire.vy = sprite.vy + FIRE_VELOCITY/2;
1176 enemyFireSprites.addElement(new_fire);
1177
1178 sprite.fire_cooldown_frames_counter = ENEMY_FIRE_COOLDOWN_WAIT_FRAMES;
1179
1180 }
1181 return new_fire;
1182 }
1183 public GameSprite shootEnemyFireTowardPlayer(GameSprite sprite, byte fire_sprite_id, byte fire_sprite_frame_id)
1184 {
1185 GameSprite new_fire = shootEnemyFire(sprite, fire_sprite_id, fire_sprite_frame_id);
1186 if (new_fire != null)
1187 {
1188 int pdx = player.x - new_fire.x;
1189 int pdy = player.y - new_fire.y;
1190
1191 // we dont have a tangens function (yet!), so for now this will do...
1192 int approx_dist = Math.abs(pdx) + Math.abs(pdy);
1193 int approx_velocity_step = approx_dist / 40;
1194 new_fire.vx = pdx / approx_velocity_step;
1195 new_fire.vy = pdy / approx_velocity_step;
1196 }
1197
1198 return new_fire;
1199 }
1200
1201 public void updatePlayerSprite()
1202 {
1203 // nuke
1204 if (player_nuke_counter == PLAYER_NUKE_COUNTER_MAX)
1205 {
1206 // activate nuke, destroy all visible enemy sprites
1207 int i = Level.enemySprites.size() - 1;
1208 while (i >= 0 )
1209 {
1210 GameSprite enemy = (GameSprite) Level.enemySprites.elementAt(i);
1211
1212 if ( enemy.visible )
1213 {
1214 System.out.println("destroying opponent: "+i+" / "+Level.enemySprites.size());
1215 enemy.energy = 0;
1216 addExplosion(enemy);
1217 }
1218 i--;
1219 }
1220 }
1221 if (player_nuke_counter > 0)
1222 {
1223 player_nuke_counter--;
1224 }
1225
1226 // move player with level scroll
1227 player.y += Level.tiles_scroll_vy;
1228
1229 if (player_gameover_explosion_counter > 0)
1230 {
1231 player_gameover_explosion_counter--;
1232 }
1233 else
1234 {
1235 if (player.energy <= 0)
1236 {
1237 player_gameover_explosion_counter = PLAYER_GAMEOVER_EXPLOSION_COUNTER_MAX;
1238 }
1239
1240 // move player sprite on command, and check player <-> screen edge collision
1241 if (command_up)
1242 {
1243 player.y -= player.vy;
1244 if (player.y < Level.tiles_scroll_y)
1245 player.y = Level.tiles_scroll_y;
1246 }
1247 if (command_down)
1248 {
1249 player.y += player.vy;
1250 // level edge collision
1251 if (player.y - Level.tiles_scroll_y > ((canvasHeight - player.h) << GameSprite.SHIFT_FACTOR))
1252 player.y = Level.tiles_scroll_y + ((canvasHeight - player.h) << GameSprite.SHIFT_FACTOR);
1253 }
1254 player.frameId = SPRITE_FRAME_PLAYER_CENTER;
1255 if (command_left)
1256 {
1257 player.x -= player.vx;
1258 if (player.x < Level.tiles_scroll_x)
1259 player.x = Level.tiles_scroll_x;
1260 player.frameId = SPRITE_FRAME_PLAYER_LEFT;
1261 }
1262 if (command_right)
1263 {
1264 player.x += player.vx;
1265 if (player.x - Level.tiles_scroll_x > ((canvasWidth - player.w) << GameSprite.SHIFT_FACTOR))
1266 player.x = Level.tiles_scroll_x + ((canvasWidth - player.w) << GameSprite.SHIFT_FACTOR);
1267 player.frameId = SPRITE_FRAME_PLAYER_RIGHT;
1268 }
1269 if (command_fire)
1270 {
1271 if (player.fire_cooldown_frames_counter <= 0)
1272 {
1273 GameSprite fire = new GameSprite(Level.SPRITE_ID_FIRE1);
1274 fire.x = player.x + ((player.w/2 - fire.w/2) << GameSprite.SHIFT_FACTOR);
1275 fire.y = player.y;
1276 fire.vy = -FIRE_VELOCITY + Level.tiles_scroll_vy;
1277 playerFireSprites.addElement(fire);
1278
1279 player.fire_cooldown_frames_counter = PLAYER_FIRE_COOLDOWN_WAIT_FRAMES;
1280 }
1281 }
1282 if (player.fire_cooldown_frames_counter > 0)
1283 player.fire_cooldown_frames_counter--;
1284 if ( god_mode )
1285 player.fire_cooldown_frames_counter -= 2;
1286 }
1287 }
1288
1289 public void doCollision()
1290 {
1291 int i = Level.enemySprites.size() - 1;
1292 while (i >= 0 )
1293 {
1294 GameSprite enemy = (GameSprite) Level.enemySprites.elementAt(i);
1295
1296 if ( enemy.visible )
1297 {
1298 // check player <-> enemy collision
1299 if (player.collidesWith(enemy))
1300 {
1301 // add explosion
1302 addExplosion(enemy);
1303 addExplosion(player);
1304
1305 // player loses energy
1306 if ( !god_mode )
1307 player.energy -= enemy.damage;
1308
1309 // level boss does not take damage from colliding with player
1310 if (enemy != Level.boss)
1311 enemy.energy -= player.damage;
1312
1313 }
1314
1315 // check the player fire sprites <-> enemy collision
1316 int j = playerFireSprites.size() - 1;
1317 while (j >= 0)
1318 {
1319 GameSprite fire = (GameSprite) playerFireSprites.elementAt(j);
1320 if (fire.collidesWith(enemy))
1321 {
1322 enemy.energy -= fire.damage;
1323
1324 // add explosions
1325 addExplosion(enemy);
1326
1327 // destroy player fire
1328 playerFireSprites.removeElementAt(j);
1329 j--;
1330 }
1331 j--;
1332 }
1333 // remove dead enemies
1334 if (enemy.energy <= 0)
1335 {
1336 Level.enemySprites.removeElementAt(i);
1337 i--;
1338 // increase player score
1339 player_score += enemy.score;
1340
1341 // if boss sprite
1342 if (enemy.spriteId == Level.SPRITE_ID_BOSS1 || enemy.spriteId == Level.SPRITE_ID_BOSS2)
1343 {
1344 boss_dead_explosion_counter = BOSS_DEAD_EXPLOSION_COUNTER_MAX;
1345 }
1346 }
1347 }
1348 i--;
1349 }
1350 // check the enemy fire sprites <-> player collision
1351 int j = enemyFireSprites.size() - 1;
1352 while (j >= 0)
1353 {
1354 GameSprite fire = (GameSprite) enemyFireSprites.elementAt(j);
1355 if (fire.collidesWith(player))
1356 {
1357 if ( !god_mode ) {
1358 player.energy -= fire.damage;
1359 System.out.println("player.energy "+ player.energy);
1360 }
1361
1362 // add explosions
1363 addExplosion(player);
1364
1365 // destroy enemy fire
1366 enemyFireSprites.removeElementAt(j);
1367 j--;
1368 }
1369 j--;
1370 }
1371 }
1372
1373 public void updatePlayerFireSprites()
1374 {
1375 for (int i=0; i < playerFireSprites.size(); i++)
1376 {
1377 GameSprite fire = (GameSprite) playerFireSprites.elementAt(i);
1378 fire.y += fire.vy;
1379
1380 // destroy player fire when out of screen
1381 if ( (fire.y + (fire.h << GameSprite.SHIFT_FACTOR)) < Level.tiles_scroll_y)
1382 {
1383 playerFireSprites.removeElementAt(i);
1384 // only increase counter, if not removed from list
1385 i--;
1386 }
1387 }
1388 }
1389
1390 public void updateEnemyFireSprites()
1391 {
1392 for (int i=0; i < enemyFireSprites.size(); i++)
1393 {
1394 // System.out.println("updating enemy fire sprite...");
1395
1396 GameSprite fire = (GameSprite) enemyFireSprites.elementAt(i);
1397 fire.x += fire.vx;
1398 fire.y += fire.vy;
1399
1400 // destroy enemy fire when out of screen
1401 if ( fire.y > Level.tiles_scroll_y + (canvasHeight << GameSprite.SHIFT_FACTOR))
1402 {
1403 enemyFireSprites.removeElementAt(i);
1404 // only increase counter, if not removed from list
1405 i--;
1406 }
1407 }
1408 }
1409
1410 public void updateExplosionSprites()
1411 {
1412 for (int i=0; i < explosionSprites.size(); i++)
1413 {
1414 GameSprite exp = (GameSprite) explosionSprites.elementAt(i);
1415
1416 // animate explosion!
1417 exp.frameId++;
1418
1419 if (exp.frameId > exp.frameIdMax)
1420 {
1421 explosionSprites.removeElementAt(i);
1422 // only increase counter, if not removed from list
1423 i--;
1424 }
1425 }
1426 // create a big bada boom player gameover explosion
1427 // 7 - max explosion frames
1428 // 2 - add an explosion every 2nd frame
1429 if (player_gameover_explosion_counter > 7 &&
1430 player_gameover_explosion_counter % 2 == 0
1431 )
1432 {
1433 GameSprite new_exp = addExplosion(player);
1434 new_exp.x += random.nextInt() % (player.w << GameSprite.SHIFT_FACTOR);
1435 new_exp.y += random.nextInt() % (player.h << GameSprite.SHIFT_FACTOR);
1436 }
1437 // create a big bada boom boss gameover explosion
1438 // 7 - max explosion frames
1439 // 2 - add an explosion every 2nd frame
1440 if (boss_dead_explosion_counter > 7 &&
1441 boss_dead_explosion_counter % 2 == 0
1442 )
1443 {
1444 GameSprite new_exp = addExplosion(Level.boss);
1445 new_exp.x += random.nextInt() % (Level.boss.w << GameSprite.SHIFT_FACTOR);
1446 new_exp.y += random.nextInt() % (Level.boss.h << GameSprite.SHIFT_FACTOR);
1447 }
1448 }
1449
1450 public static void loadImages()
1451 {
1452 try {
1453
1454 spriteImages = new Image[SPRITE_IMAGE_MAX];
1455 spriteImages[SPRITE_IMAGE_PLAYER] = Image.createImage("/p.png");
1456 spriteImages[SPRITE_IMAGE_FIRE] = Image.createImage("/fire.png");
1457 spriteImages[SPRITE_IMAGE_BOSS1] = Image.createImage("/boss1.png");
1458 spriteImages[SPRITE_IMAGE_BOSS2] = Image.createImage("/boss2.png");
1459 spriteImages[SPRITE_IMAGE_ENEMY1] = Image.createImage("/e1.png");
1460 spriteImages[SPRITE_IMAGE_ENEMY2] = Image.createImage("/e2.png");
1461 spriteImages[SPRITE_IMAGE_ENEMY3] = Image.createImage("/e3.png");
1462 spriteImages[SPRITE_IMAGE_ENEMY4] = Image.createImage("/e4.png");
1463 spriteImages[SPRITE_IMAGE_EXPLOSION] = Image.createImage("/exp.png");
1464
1465 tileImage = Image.createImage("/t04.png");
1466
1467 imgBackground = Image.createImage("/bg.png");
1468
1469 } catch (Exception e) {};
1470 }
1471
1472 public static GameSprite addExplosion(GameSprite exp_spr)
1473 {
1474 // add explosion
1475 GameSprite exp = new GameSprite(Level.SPRITE_ID_EXPLOSION);
1476 // center the explosion position on the exploded sprite
1477 exp.x = exp_spr.x + ((exp_spr.w/2 - exp.w/2) << GameSprite.SHIFT_FACTOR);
1478 exp.y = exp_spr.y + ((exp_spr.h/2 - exp.h/2) << GameSprite.SHIFT_FACTOR);
1479 exp.vx = exp_spr.vx;
1480 exp.vy = exp_spr.vy;
1481 explosionSprites.addElement(exp);
1482
1483 if (exp_spr.energy > 0)
1484 exp.frameId = GameSprite.EXPLOSION_FRAME_SMOKE_START;
1485
1486 return exp;
1487 }
1488
1489 public void hideNotify()
1490 {
1491 // hideNotify method of Canvas is called on external events, which hide the Canvas
1492 // this method can be used to handle such events (battery warnings, incoming phone calls...)
1493 if (mode == MODE_GAME)
1494 {
1495 mode = MODE_MENU;
1496 menuScreen = MENU_SCR_PAUSE_GAME;
1497 stopMusic();
1498 }
1499 }
1500
1501 public void showNotify()
1502 {
1503 if (musicOn)
1504 playMusic();
1505 }
1506
1507
1508 // loads the highscores from RMS - the internal phone database
1509 // also saves default scores, if no scores exist.
1510 public static void loadHighscoreFromRMS()
1511 {
1512 try
1513 {
1514 db = RecordStore.openRecordStore(SCORE_DB_NAME, true);
1515
1516 byte[] score_data = null;
1517 // initialize scores
1518 if (db.getNumRecords() == 0)
1519 {
1520 // add record with initial default scores
1521 score_data = getHighscoreData();
1522 db.addRecord(score_data, 0, score_data.length);
1523 }
1524 // load highscore
1525 score_data = db.getRecord(1);
1526 ByteArrayInputStream in = new ByteArrayInputStream(score_data);
1527 DataInputStream dis = new DataInputStream(in);
1528 for (byte i = 0; i < MAX_SCORES; i++)
1529 {
1530 hiScores[i] = dis.readInt();
1531 hiNames[i] = dis.readUTF();
1532 }
1533 dis.close();
1534 in.close();
1535 db.closeRecordStore();
1536 dis = null;
1537 in = null;
1538 db = null;
1539 // System.gc();
1540 } catch (Exception ex) {
1541 ex.printStackTrace();
1542 }
1543 }
1544
1545 // prepares data in a byte array, ready for saving to a RMS record
1546 public static byte[] getHighscoreData() throws IOException
1547 {
1548 ByteArrayOutputStream out = new ByteArrayOutputStream();
1549 DataOutputStream dos = new DataOutputStream(out);
1550 for (byte i = 0; i < MAX_SCORES; i++)
1551 {
1552 dos.writeInt(hiScores[i]);
1553 dos.writeUTF(hiNames[i]);
1554 }
1555 dos.close();
1556 out.close();
1557
1558 return out.toByteArray();
1559 }
1560
1561 // saves highscores to RMS
1562 public static void saveHighscores()
1563 {
1564 try
1565 {
1566 db = RecordStore.openRecordStore(SCORE_DB_NAME, true);
1567
1568 byte[] data = getHighscoreData();
1569
1570 db.setRecord(1, data, 0, data.length);
1571 db.closeRecordStore();
1572 } catch (Exception ex) {
1573 ex.printStackTrace();
1574 }
1575 }
1576
1577 // returns -1 if not qualified, highscore position otherwise
1578 public static int isQualified(int score)
1579 {
1580 for (byte i = 0; i < MAX_SCORES; i++)
1581 if (hiScores[i] < score)
1582 return i;
1583 return -1;
1584 }
1585
1586 // add a score to the scores array and to the rms
1587 public static void addHighscore(int score, String name)
1588 {
1589 int i = isQualified(score);
1590
1591 // move others down 1 place
1592 for (byte k = (byte) (MAX_SCORES - 1); k > i; k--) {
1593 hiScores[k] = hiScores[k - 1];
1594 hiNames[k] = hiNames[k - 1];
1595 }
1596 // insert score
1597 hiScores[i] = score;
1598 hiNames[i] = name;
1599
1600 saveHighscores();
1601 return;
1602 }
1603
1604 public static final short SIN_FACTOR = 1024;
1605 public static final short[] sin = {
1606 0, 18, 36, 54, 71, 89, 107, 125, 143, 160,
1607 178, 195, 213, 230, 248, 265, 282, 299, 316, 333,
1608 350, 367, 384, 400, 416, 433, 449, 465, 481, 496,
1609 512, 527, 543, 558, 573, 587, 602, 616, 630, 644,
1610 658, 672, 685, 698, 711, 724, 737, 749, 761, 773,
1611 784, 796, 807, 818, 828, 839, 849, 859, 868, 878,
1612 887, 896, 904, 912, 920, 928, 935, 943, 949, 956,
1613 962, 968, 974, 979, 984, 989, 994, 998, 1002, 1005,
1614 1008, 1011, 1014, 1016, 1018, 1020, 1022, 1023, 1023, 1024,
1615 1024, 1024, 1023, 1023, 1022, 1020, 1018, 1016, 1014, 1011,
1616 1008, 1005, 1002, 998, 994, 989, 984, 979, 974, 968,
1617 962, 956, 949, 943, 935, 928, 920, 912, 904, 896,
1618 887, 878, 868, 859, 849, 839, 828, 818, 807, 796,
1619 784, 773, 761, 749, 737, 724, 711, 698, 685, 672,
1620 658, 644, 630, 616, 602, 587, 573, 558, 543, 527,
1621 512, 496, 481, 465, 449, 433, 416, 400, 384, 367,
1622 350, 333, 316, 299, 282, 265, 248, 230, 213, 195,
1623 178, 160, 143, 125, 107, 89, 71, 54, 36, 18,
1624 0, -18, -36, -54, -71, -89, -107, -125, -143, -160,
1625 -178, -195, -213, -230, -248, -265, -282, -299, -316, -333,
1626 -350, -367, -384, -400, -416, -433, -449, -465, -481, -496,
1627 -512, -527, -543, -558, -573, -587, -602, -616, -630, -644,
1628 -658, -672, -685, -698, -711, -724, -737, -749, -761, -773,
1629 -784, -796, -807, -818, -828, -839, -849, -859, -868, -878,
1630 -887, -896, -904, -912, -920, -928, -935, -943, -949, -956,
1631 -962, -968, -974, -979, -984, -989, -994, -998, -1002, -1005,
1632 -1008, -1011, -1014, -1016, -1018, -1020, -1022, -1023, -1023, -1024,
1633 -1024, -1024, -1023, -1023, -1022, -1020, -1018, -1016, -1014, -1011,
1634 -1008, -1005, -1002, -998, -994, -989, -984, -979, -974, -968,
1635 -962, -956, -949, -943, -935, -928, -920, -912, -904, -896,
1636 -887, -878, -868, -859, -849, -839, -828, -818, -807, -796,
1637 -784, -773, -761, -749, -737, -724, -711, -698, -685, -672,
1638 -658, -644, -630, -616, -602, -587, -573, -558, -543, -527,
1639 -512, -496, -481, -465, -449, -433, -416, -400, -384, -367,
1640 -350, -333, -316, -299, -282, -265, -248, -230, -213, -195,
1641 -178, -160, -143, -125, -107, -89, -71, -54, -36, -18,
1642 };
1643
1644
1645 public static boolean musicOn = true;
1646 public static javax.microedition.media.Player musicPlayer;
1647
1648 public static void loadMusic()
1649 {
1650 InputStream inputstream;
1651
1652 try
1653 {
1654 inputstream = new Object().getClass().getResourceAsStream("/music.mid");
1655 musicPlayer = Manager.createPlayer(inputstream, "audio/midi");
1656 musicPlayer.realize();
1657 musicPlayer.setLoopCount(-1);
1658 }
1659 catch (Exception e) {
1660 }
1661 }
1662
1663 public static void playMusic()
1664 {
1665 try
1666 {
1667 VolumeControl volume = (VolumeControl) musicPlayer
1668 .getControl("javax.microedition.media.control.VolumeControl");
1669 volume.setLevel(20);
1670
1671 musicPlayer.realize();
1672 musicPlayer.start();
1673 }
1674 catch (Exception e) {
1675 }
1676 }
1677
1678 public static void stopMusic() {
1679 try
1680 {
1681 if (musicPlayer != null) {
1682 musicPlayer.stop();
1683 musicPlayer.setMediaTime(-1);
1684 }
1685 }
1686 catch (Exception e) {
1687 }
1688
1689 }
1690
1691 }
1692