Chris Dick
/
Gameduino_Asteroids_game
Asteroids game using a Gameduino
Embed:
(wiki syntax)
Show/hide line numbers
main.cpp
00001 #include "mbed.h" 00002 #include "GD.h" 00003 #include "shield.h" 00004 00005 GDClass GD(ARD_MOSI, ARD_MISO, ARD_SCK, ARD_D9, USBTX, USBRX) ; 00006 SPI spimain(ARD_MOSI, ARD_MISO, ARD_SCK); // mosi, miso, sclk 00007 DigitalIn down(ARD_A2);//0 00008 DigitalIn up(ARD_A3);//1 00009 DigitalIn left(ARD_A1);//2 00010 DigitalIn right(ARD_A0);//3 00011 00012 // ---------------------------------------------------------------------- 00013 // qrand: quick random numbers 00014 // ---------------------------------------------------------------------- 00015 00016 static uint16_t lfsr = 1; 00017 00018 static void qrandSeed(int seed) { 00019 if (seed) { 00020 lfsr = seed; 00021 } else { 00022 lfsr = 0x947; 00023 } 00024 } 00025 00026 static byte qrand1() { // a random bit 00027 lfsr = (lfsr >> 1) ^ (-(lfsr & 1) & 0xb400); 00028 return lfsr & 1; 00029 } 00030 00031 static byte qrand(byte n) { // n random bits 00032 byte r = 0; 00033 while (n--) 00034 r = (r << 1) | qrand1(); 00035 return r; 00036 } 00037 00038 // ---------------------------------------------------------------------- 00039 // controller: buttons on Arduino pins 3,4,5,6 00040 // ---------------------------------------------------------------------- 00041 00042 static void controller_init() { 00043 // Configure input pins with internal pullups 00044 00045 down.mode(PullUp); 00046 up.mode(PullUp); 00047 left.mode(PullUp); 00048 right.mode(PullUp); 00049 00050 } 00051 00052 #define CONTROL_LEFT 1 00053 #define CONTROL_RIGHT 2 00054 #define CONTROL_UP 4 00055 #define CONTROL_DOWN 8 00056 00057 00058 static byte controller_sense(uint16_t clock) { 00059 byte r = 0; 00060 00061 00062 if (!down) 00063 r |= CONTROL_DOWN; 00064 if (!up) 00065 r |= CONTROL_UP; 00066 if (!left) 00067 r |= CONTROL_LEFT; 00068 if (!right) 00069 r |= CONTROL_RIGHT; 00070 00071 return r; 00072 } 00073 00074 // Swap color's red and blue channels 00075 uint16_t swapRB(uint16_t color) { 00076 byte r = 31 & (color >> 10); 00077 byte g = 31 & (color >> 5); 00078 byte b = 31 & color; 00079 return (color & 0x8000) | (b << 10) | (g << 5) | r; 00080 } 00081 00082 // Swap color's red and green channels 00083 uint16_t swapRG(uint16_t color) { 00084 byte r = 31 & (color >> 10); 00085 byte g = 31 & (color >> 5); 00086 byte b = 31 & color; 00087 return (color & 0x8000) | (g << 10) | (r << 5) | b; 00088 } 00089 00090 #include "asteroidgraphics.h" 00091 #include "splitscreen.h" 00092 00093 static void update_score(); 00094 00095 // [int(127 * math.sin(math.pi * 2 * i / 16)) for i in range(16)] 00096 static PROGMEM signed char charsin[16] = {0, 48, 89, 117, 127, 117, 89, 48, 0, -48, -89, -117, -127, -117, -89, -48}; 00097 char qsin(int a) { 00098 //har)pgm_read_byte_near(charsin + ((a) & 15)) 00099 return charsin[(a & 15)]; 00100 } 00101 #define qcos(a) qsin((a) + 4) 00102 00103 static char spr2obj[256]; // Maps sprites to owning objects 00104 00105 /* 00106 00107 The general idea is that an object table ``objects`` has an entry for 00108 each drawn thing on screen (e.g. player, missile, rock, explosion). 00109 Each class of object has a ``handler`` function that does the necessary 00110 housekeeping and draws the actual sprites. 00111 00112 As part of the behavior, some classes need to know if they have collided 00113 with anything. In particular the rocks need to know if they have collided 00114 with the player or a missile. The `collide` member points to the 00115 colliding sprite. 00116 00117 */ 00118 00119 struct object { 00120 int x, y; 00121 byte handler, state; 00122 byte collide; 00123 } objects[128]; 00124 #define COORD(c) ((c) << 4) 00125 00126 static signed char explosions = -1; 00127 static signed char enemies = -1; 00128 static signed char missiles = -1; 00129 00130 static void push(signed char *stk, byte i) { 00131 objects[i].state = *stk; 00132 *stk = i; 00133 } 00134 00135 static char pop(signed char *stk) { 00136 signed char r = *stk; 00137 if (0 <= r) { 00138 *stk = objects[r].state; 00139 } 00140 return r; 00141 } 00142 00143 byte rr[4] = { 0,3,6,5 }; 00144 00145 static struct { 00146 byte boing, boom, pop; 00147 byte thrust; 00148 byte bass; 00149 } sounds; 00150 00151 static int player_vx, player_vy; // Player velocity 00152 static int player_invincible, player_dying; 00153 static byte lives; 00154 static long score; 00155 static byte level; 00156 00157 // Move object po by velocity (vx, vy), optionally keeping in 00158 // player's frame. 00159 // Returns true if the object wrapped screen edge 00160 static bool move(struct object *po, char vx, char vy, byte playerframe = 1) { 00161 bool r = 0; 00162 if (playerframe) { 00163 po->x += (vx - player_vx); 00164 po->y += (vy - player_vy); 00165 } else { 00166 po->x += vx; 00167 po->y += vy; 00168 } 00169 00170 if (po->x > COORD(416)) 00171 r = 1, po->x -= COORD(432); 00172 else if (po->x < COORD(-16)) 00173 r = 1, po->x += COORD(432); 00174 00175 if (po->y > COORD(316)) 00176 r = 1, po->y -= COORD(332); 00177 else if (po->y < COORD(-16)) 00178 r = 1, po->y += COORD(332); 00179 return r; 00180 } 00181 00182 00183 #define HANDLE_NULL 0 00184 #define HANDLE_ROCK0 1 00185 #define HANDLE_ROCK1 2 00186 #define HANDLE_BANG0 3 00187 #define HANDLE_BANG1 4 00188 #define HANDLE_PLAYER 5 00189 #define HANDLE_MISSILE 6 00190 00191 // Expire object i, and return it to the free stk 00192 static void expire(signed char *stk, byte i) { 00193 objects[i].handler = HANDLE_NULL; 00194 push(stk, i); 00195 } 00196 00197 static void handle_null(byte i, byte state, uint16_t clock) { 00198 } 00199 00200 static void handle_player(byte i, byte state, uint16_t clock) { 00201 struct object *po = &objects[i]; 00202 byte angle = (po->state & 15); 00203 byte rot1 = (angle & 3); 00204 byte rot2 = rr[3 & (angle >> 2)]; 00205 if (!player_dying && (player_invincible & 1) == 0) 00206 draw_player(200, 150, rot1, rot2); 00207 00208 static byte prev_control; 00209 byte control = controller_sense(clock); 00210 00211 char thrust_x, thrust_y; 00212 if (!player_dying && control & CONTROL_DOWN) { // thrust 00213 byte flame_angle = angle ^ 8; 00214 byte d; 00215 for (d = 9; d > 5; d--) { 00216 int flamex = 201 - (((d + (clock&3)) * qsin(flame_angle)) >> 5); 00217 int flamey = 150 - (((d + (clock&3)) * qcos(flame_angle)) >> 5); 00218 if ((player_invincible & 1) == 0) 00219 draw_sparkr(flamex, flamey, rot1, rot2, 1); // collision class K 00220 } 00221 thrust_x = -qsin(angle); 00222 thrust_y = -qcos(angle); 00223 sounds.thrust = 1; 00224 } else { 00225 thrust_x = thrust_y = 0; 00226 sounds.thrust = 0; 00227 } 00228 00229 player_vx = ((31 * player_vx) + thrust_x) / 32; 00230 player_vy = ((31 * player_vy) + thrust_y) / 32; 00231 00232 po->x += player_vx; 00233 po->y += player_vy; 00234 00235 if (clock & 1) { 00236 char rotate = (512) / 400; 00237 if (control & CONTROL_LEFT) 00238 rotate++; 00239 if (control & CONTROL_RIGHT) 00240 rotate--; 00241 po->state = ((angle + rotate) & 15); 00242 } 00243 00244 if (!player_dying && 00245 !(prev_control & CONTROL_UP) && 00246 (control & CONTROL_UP)) { // shoot! 00247 signed char e = pop(&missiles); 00248 if (0 <= e) { 00249 objects[e].x = COORD(200); 00250 objects[e].y = COORD(150); 00251 objects[e].state = po->state; 00252 objects[e].handler = HANDLE_MISSILE; 00253 } 00254 sounds.boing = 1; 00255 } 00256 prev_control = control; 00257 if (player_invincible) 00258 --player_invincible; 00259 if (player_dying) { 00260 if (--player_dying == 0) { 00261 --lives; 00262 update_score(); 00263 if (lives != 0) { 00264 player_invincible = 48; 00265 } 00266 } 00267 } 00268 } 00269 00270 static void handle_missile(byte i, byte state, uint16_t clock) { 00271 struct object *po = &objects[i]; 00272 byte angle = (po->state & 15); 00273 byte rot1 = (angle & 3); 00274 byte rot2 = rr[3 & (angle >> 2)]; 00275 draw_sparkr(po->x >> 4, po->y >> 4, rot1, rot2); 00276 char vx = -qsin(po->state), vy = -qcos(po->state); 00277 if (move(po, vx, vy, 0)) { 00278 expire(&missiles, i); 00279 } 00280 } 00281 00282 static void explodehere(struct object *po, byte handler, uint16_t clock) { 00283 signed char e = pop(&explosions); 00284 if (0 <= e) { 00285 objects[e].x = po->x; 00286 objects[e].y = po->y; 00287 objects[e].handler = handler; 00288 objects[e].state = clock; 00289 } 00290 } 00291 00292 static void killplayer(uint16_t clock) { 00293 if (!player_invincible && !player_dying) { 00294 signed char e = pop(&explosions); 00295 if (0 <= e) { 00296 objects[e].x = COORD(200); 00297 objects[e].y = COORD(150); 00298 objects[e].handler = HANDLE_BANG1; 00299 objects[e].state = clock; 00300 } 00301 player_dying = 2 * 36; 00302 sounds.boom = 1; 00303 sounds.pop = 1; 00304 } 00305 } 00306 00307 static byte commonrock(uint16_t clock, byte i, byte speed, void df(int x, int y, byte anim, byte rot, byte jk)) { 00308 struct object *po = &objects[i]; 00309 00310 byte move_angle = po->state >> 4; 00311 char vx = (speed * -qsin(move_angle)) >> 6, vy = (speed * -qcos(move_angle)) >> 6; 00312 move(po, vx, vy); 00313 00314 byte angle = (clock * speed) >> 4; 00315 if (po->state & 1) 00316 angle = ~angle; 00317 byte rot1 = (angle & 3); 00318 byte rot2 = rr[3 & (angle >> 2)]; 00319 df(po->x >> 4, po->y >> 4, rot1, rot2, 1); 00320 if (po->collide != 0xff) { 00321 struct object *other = &objects[po->collide]; 00322 switch (other->handler) { 00323 case HANDLE_PLAYER: 00324 killplayer(clock); 00325 break; 00326 case HANDLE_MISSILE: 00327 expire(&missiles, po->collide); // missile is dead 00328 expire(&enemies, i); 00329 return 1; 00330 } 00331 } 00332 return 0; 00333 } 00334 00335 static void handle_rock0(byte i, byte state, uint16_t clock) { 00336 struct object *po = &objects[i]; 00337 byte speed = 12 + (po->state & 7); 00338 if (commonrock(clock, i, speed, draw_rock0r)) { 00339 explodehere(po, HANDLE_BANG0, clock); 00340 score += 10; 00341 sounds.pop = 1; 00342 } 00343 } 00344 00345 static void handle_rock1(byte i, byte state, uint16_t clock) { 00346 struct object *po = &objects[i]; 00347 byte speed = 6 + (po->state & 3); 00348 if (commonrock(clock, i, speed, draw_rock1r)) { 00349 int j; 00350 for (j = 0; j < 4; j++) { 00351 char e = pop(&enemies); 00352 if (0 < e) { 00353 objects[e].x = po->x; 00354 objects[e].y = po->y; 00355 objects[e].handler = HANDLE_ROCK0; 00356 objects[e].state = (j << 6) + qrand(6); // spread fragments across 4 quadrants 00357 } 00358 } 00359 explodehere(po, HANDLE_BANG1, clock); 00360 score += 30; 00361 sounds.boom = 1; 00362 } 00363 } 00364 00365 static void handle_bang0(byte i, byte state, uint16_t clock) { 00366 struct object *po = &objects[i]; 00367 move(po, 0, 0); 00368 byte anim = ((0xff & clock) - state) >> 1; 00369 if (anim < EXPLODE16_FRAMES) 00370 draw_explode16(po->x >> 4, po->y >> 4, anim, 0); 00371 else 00372 expire(&explosions, i); 00373 } 00374 00375 static void handle_bang1(byte i, byte state, uint16_t clock) { 00376 struct object *po = &objects[i]; 00377 move(po, 0, 0); 00378 byte anim = ((0xff & clock) - state) >> 1; 00379 byte rot = 7 & i; 00380 if (anim < EXPLODE32_FRAMES) 00381 draw_explode32(po->x >> 4, po->y >> 4, anim, rot); 00382 else 00383 expire(&explosions, i); 00384 } 00385 00386 typedef void (*handler)(byte, byte, uint16_t); 00387 static handler handlers[] = { 00388 handle_null, 00389 handle_rock0, 00390 handle_rock1, 00391 handle_bang0, 00392 handle_bang1, 00393 handle_player, 00394 handle_missile 00395 }; 00396 00397 00398 // uncompress one line of the title banner into buffer dst 00399 // title banner lines are run-length encoded 00400 static void titlepaint(char *dst, byte src, byte mask) { 00401 if (src != 0xff) { 00402 PROGMEM prog_uchar *psrc = title_runs + 2 * src; 00403 byte a, b; 00404 do { 00405 a = *psrc++; 00406 b = *psrc++; 00407 while (a < (b & 0x7f)) 00408 dst[a++] |= mask; 00409 } while (!(b & 0x80)); 00410 } 00411 } 00412 00413 // draw a title banner column src (0-511) to screen column dst (0-63). 00414 static void column(byte dst, byte src) { 00415 static char scratch[76]; 00416 memset(scratch, 0, sizeof(scratch)); 00417 //PROGMEM prog_uchar* titleadd = title + 2 * src; 00418 prog_uchar line = title[2 * src];//*titleadd++;//pgm_read_byte_near(title + 2 * src); 00419 titlepaint(scratch, line, 1); 00420 line = title[2 * src+1];//*titleadd;//pgm_read_byte_near(title + 2 * src + 1); 00421 titlepaint(scratch, line, 2); 00422 00423 byte j; 00424 for (j = 0; j < 38; j++) { 00425 GD.wr(dst + (j << 6), 00426 (((dst + j) & 15) << 4) + 00427 scratch[2 * j] + 00428 (scratch[2 * j + 1] << 2)); 00429 } 00430 } 00431 00432 static void setup_sprites() { 00433 GD.copy(PALETTE16A, palette16a, sizeof(palette16a)); 00434 GD.copy(PALETTE4A, palette4a, sizeof(palette4a)); 00435 GD.copy(PALETTE16B, palette16b, sizeof(palette16b)); 00436 00437 // Use the first two 256-color palettes as pseudo-16 color palettes 00438 int i; 00439 for (i = 0; i < 256; i++) { 00440 00441 // palette 0 decodes low nibble, hence (i & 15) 00442 //PROGMEM prog_uchar* pallow = palette256a + ((i & 15) << 1); 00443 uint16_t rgb = palette256a[((i & 15) << 1)]; 00444 GD.wr16(RAM_SPRPAL + (i << 1), rgb); 00445 00446 // palette 1 decodes nigh nibble, hence (i >> 4) 00447 //PROGMEM prog_uchar* palhigh = palette256a + ((i >> 4) << 1); 00448 rgb = palette256a[((i >> 4) << 1)]; 00449 GD.wr16(RAM_SPRPAL + 512 + (i << 1), rgb); 00450 } 00451 00452 GD.uncompress(RAM_SPRIMG, asteroid_images_compressed); 00453 GD.wr(JK_MODE, 1); 00454 } 00455 00456 // Run the object handlers, keeping track of sprite ownership in spr2obj 00457 static void runobjects(uint16_t r) { 00458 int i; 00459 GD.__wstartspr(((r & 1) ? 256 : 0)); // write sprites to other frame 00460 for (i = 0; i < 128; i++) { 00461 struct object *po = &objects[i]; 00462 handler h = (handler)handlers[po->handler]; 00463 byte loSpr = GD.spr; 00464 (*h)(i, po->state, r); 00465 while (loSpr < GD.spr) { 00466 spr2obj[loSpr++] = i; 00467 } 00468 } 00469 // Hide all the remaining sprites 00470 do 00471 GD.xhide(); 00472 while (GD.spr); 00473 GD.__end(); 00474 } 00475 00476 // ---------------------------------------------------------------------- 00477 // map 00478 // ---------------------------------------------------------------------- 00479 00480 static byte loaded[8]; 00481 static byte scrap; 00482 00483 // copy a (w,h) rectangle from the source image (x,y) into picture RAM 00484 static void rect(unsigned int dst, byte x, byte y, byte w, byte h) { 00485 PROGMEM prog_uchar *src = bg_pic + (16 * y) + x; 00486 while (h--) { 00487 GD.copy(dst, src, w); 00488 dst += 64; 00489 src += 16; 00490 } 00491 } 00492 00493 static void map_draw(byte strip) { 00494 strip &= 63; // Universe is finite but unbounded: 64 strips 00495 byte s8 = (strip & 7); // Destination slot for this strip (0-7) 00496 if (loaded[s8] != strip) { 00497 qrandSeed(level ^ (strip * 77)); // strip number is the hash... 00498 00499 // Random star pattern is made from characters 1-15 00500 GD.__wstart(s8 * (8 * 64)); 00501 int i; 00502 for (i = 0; i < (8 * 64); i++) { 00503 byte r; 00504 if (qrand(3) == 0) 00505 r = qrand(4); 00506 else 00507 r = 0; 00508 spimain.write(r); 00509 } 00510 GD.__end(); 00511 00512 // Occasional planet, copied from the background char map 00513 if (qrand(2) == 0) { 00514 uint16_t dst = (qrand(3) * 8) + (s8 * (8 * 64)); 00515 switch (qrand(2)) { 00516 case 0: 00517 rect(dst, 0, 1, 6, 6); 00518 break; 00519 case 1: 00520 rect(dst, 7, 1, 6, 6); 00521 break; 00522 case 2: 00523 rect(dst, 0, 7, 8, 4); 00524 break; 00525 case 3: 00526 rect(dst, 8, 7, 5, 5); 00527 break; 00528 } 00529 } 00530 loaded[s8] = strip; 00531 } 00532 } 00533 00534 static void map_coldstart() { 00535 memset(loaded, 0xff, sizeof(loaded)); 00536 scrap = 0xff; 00537 byte i; 00538 for (i = 0; i < 8; i++) 00539 map_draw(i); 00540 } 00541 00542 static int atxy(int x, int y) { 00543 return (y << 6) + x; 00544 } 00545 00546 static void update_score() { 00547 unsigned long s = score; 00548 uint16_t a = atxy(49, scrap << 3); 00549 byte i; 00550 //void* code; 00551 for (i = 0; i < 6; i++) { 00552 PROGMEM prog_uchar* digitcodes = (bg_pic + (16 * 30))+(s % 10); 00553 00554 //code = &digitcodes + (s % 10); 00555 GD.wr(a--, *digitcodes);//pgm_read_byte_near(digitcodes + (s % 10)) ; 00556 s /= 10; 00557 } 00558 PROGMEM prog_uchar* digitcodes = bg_pic + (16 * 30) + lives; 00559 //code = &digitcodes + lives; 00560 GD.wr(atxy(0, scrap << 3), *digitcodes);// pgm_read_byte_near(digitcodes + lives)); 00561 } 00562 00563 static void map_refresh(byte strip) { 00564 byte i; 00565 byte newscrap = 7 & (strip + 7); 00566 if (scrap != newscrap) { 00567 scrap = newscrap; 00568 00569 uint16_t scrapline = scrap << 6; 00570 GD.wr16(COMM+2, 0x8000 | scrapline); // show scrapline at line 0 00571 GD.wr16(COMM+14, 0x8000 | (0x1ff & ((scrapline + 8) - 291))); // show scrapline+8 at line 291 00572 00573 GD.fill(atxy(0, scrap << 3), 0, 50); 00574 update_score(); 00575 00576 GD.fill(atxy(0, 1 + (scrap << 3)), 0, 64); 00577 rect(atxy(0, 1 + (scrap << 3)), 0, 31, 16, 1); 00578 rect(atxy(32, 1 + (scrap << 3)), 0, 31, 16, 1); 00579 00580 loaded[scrap] = 0xff; 00581 } 00582 wait_ms(1); // wait for raster to pass the top line before overwriting it 00583 for (i = 0; i < 6; i++) 00584 map_draw(strip + i); 00585 } 00586 00587 static void start_level() { 00588 int i; 00589 00590 for (i = 0; i < 128; i++) 00591 objects[i].handler = 0; 00592 00593 player_vx = 0; 00594 player_vy = 0; 00595 player_invincible = 0; 00596 player_dying = 0; 00597 00598 objects[0].x = 0; 00599 objects[0].y = 0; 00600 objects[0].state = 0; 00601 objects[0].handler = HANDLE_PLAYER; 00602 00603 // Set up the pools of objects for missiles, enemies, explosions 00604 missiles = 0; 00605 enemies = 0; 00606 explosions = 0; 00607 for (i = 1; i < 16; i++) 00608 push(&missiles, i); 00609 for (i = 16; i < 80; i++) 00610 push(&enemies, i); 00611 for (i = 80; i < 128; i++) 00612 push(&explosions, i); 00613 00614 // Place asteroids in a ring around the edges of the screen 00615 int x; 00616 if ((level + 3) < 32) { 00617 x = level + 3; 00618 } else { 00619 x = 32; 00620 } 00621 for (i = 0; i < x; i++) { 00622 char e = pop(&enemies); 00623 if (rand()%2 == 0) { 00624 objects[e].x = rand()%2 ? COORD(32) : COORD(400-32); 00625 objects[e].y = rand()%COORD(300); 00626 } else { 00627 objects[e].x = rand()%COORD(400); 00628 objects[e].y = rand()%2 ? COORD(32) : COORD(300-32); 00629 } 00630 objects[e].handler = HANDLE_ROCK1; 00631 objects[e].state = qrand(8); 00632 } 00633 00634 GD.copy(PALETTE16B, palette16b, sizeof(palette16b)); 00635 for (i = 0; i < 16; i++) { 00636 uint16_t a = PALETTE16B + 2 * i; 00637 uint16_t c = GD.rd16(a); 00638 if (level & 1) 00639 c = swapRB(c); 00640 if (level & 2) 00641 c = swapRG(c); 00642 if (level & 4) 00643 c = swapRB(c); 00644 GD.wr16(a, c); 00645 } 00646 00647 map_coldstart(); 00648 } 00649 00650 void setup() { 00651 00652 GD.begin(); 00653 controller_init(); 00654 00655 } 00656 00657 static void title_banner() { 00658 GD.fill(VOICES, 0, 64 * 4); 00659 GD.wr(J1_RESET, 1); 00660 GD.wr(SPR_DISABLE, 1); 00661 GD.wr16(SCROLL_X, 0); 00662 GD.wr16(SCROLL_Y, 0); 00663 GD.fill(RAM_PIC, 0, 4096); 00664 setup_sprites(); 00665 00666 uint16_t i; 00667 uint16_t j; 00668 00669 GD.__wstart(RAM_CHR); 00670 for (i = 0; i < 256; i++) { 00671 // bits control lit segments like this: 00672 // 0 1 00673 // 2 3 00674 byte a = (i & 1) ? 0x3f : 0; 00675 byte b = (i & 2) ? 0x3f : 0; 00676 byte c = (i & 4) ? 0x3f : 0; 00677 byte d = (i & 8) ? 0x3f : 0; 00678 for (j = 0; j < 3; j++) { 00679 spimain.write(a); 00680 spimain.write(b); 00681 } 00682 spimain.write(0); 00683 spimain.write(0); 00684 for (j = 0; j < 3; j++) { 00685 spimain.write(c); 00686 spimain.write(d); 00687 } 00688 spimain.write(0); 00689 spimain.write(0); 00690 } 00691 00692 GD.__end(); 00693 00694 for (i = 0; i < 256; i++) { 00695 GD.setpal(4 * i + 0, RGB(0,0,0)); 00696 //prog_uchar* colptr = title_ramp + 2 * (i >> 4); 00697 prog_uchar color = title_ramp[(i >> 4)];//pgm_read_word_near(title_ramp + 2 * (i >> 4)); 00698 GD.setpal(4 * i + 3, color); 00699 } 00700 00701 for (i = 0; i < 64; i++) { 00702 column(i, i); 00703 } 00704 00705 for (i = 0; i < 128; i++) { 00706 objects[i].handler = 0; 00707 objects[i].collide = 0xff; 00708 } 00709 00710 for (i = 0; i < 128; i++) 00711 push(&enemies, i); 00712 00713 for (i = 0; i < 40; i++) { 00714 char e = pop(&enemies); 00715 objects[e].x = COORD(rand()%400); 00716 objects[e].y = COORD(rand()%300); 00717 objects[e].handler = qrand1() ? HANDLE_ROCK1 : HANDLE_ROCK0; 00718 objects[e].state = qrand(8); 00719 } 00720 00721 byte startgame = 0; 00722 for (i = 0; startgame < 50; i++) { 00723 for (j = 0; j < 256; j++) { 00724 byte index = 15 & ((-i >> 2) + (j >> 4)); 00725 prog_uchar* colour = title_ramp + 2 * index; 00726 prog_uchar color = *colour;// pgm_read_word_near(title_ramp + 2 * index); 00727 GD.setpal(4 * j + 3, color); 00728 } 00729 00730 if (!startgame && 00731 (controller_sense(i) || (i == (2048 - 400)))) { 00732 // explode all rocks! 00733 for (j = 0; j < 128; j++) { 00734 byte h = objects[j].handler; 00735 if ((h == HANDLE_ROCK0) || (h == HANDLE_ROCK1)) 00736 objects[j].handler = HANDLE_BANG1; 00737 objects[j].state = i; 00738 } 00739 startgame = 1; 00740 } 00741 00742 if (startgame){ 00743 startgame++; 00744 } 00745 00746 //runobjects(i); 00747 00748 GD.waitvblank(); 00749 GD.wr(SPR_PAGE, (i & 1)); 00750 GD.wr(SPR_DISABLE, 0); 00751 GD.wr16(SCROLL_X, i); 00752 if ((i & 7) == 0) { 00753 byte x = ((i >> 3) + 56); 00754 column(63 & x, 255 & x); 00755 } 00756 } 00757 00758 for (i = 0; i < 32; i++) { 00759 for (j = 0; j < 256; j++) { 00760 uint16_t a = RAM_PAL + (8 * j) + 6; 00761 uint16_t pal = GD.rd16(a); 00762 byte r = 31 & (pal >> 10); 00763 byte g = 31 & (pal >> 5); 00764 byte b = 31 & pal; 00765 if (r) r--; 00766 if (g) g--; 00767 if (b) b--; 00768 pal = (r << 10) | (g << 5) | b; 00769 GD.wr16(a, pal); 00770 } 00771 GD.waitvblank(); 00772 GD.waitvblank(); 00773 00774 } 00775 00776 GD.fill(RAM_PIC, 0, 4096); 00777 00778 } 00779 00780 #define SOUNDCYCLE(state) ((state) = v ? ((state) + 1) : 0) 00781 00782 int main() { 00783 00784 setup(); 00785 while (1) { 00786 00787 title_banner(); 00788 00789 GD.uncompress(RAM_CHR, bg_chr_compressed); 00790 GD.uncompress(RAM_PAL, bg_pal_compressed); 00791 00792 GD.wr16(COMM+0, 0); 00793 GD.wr16(COMM+2, 0x8000); 00794 GD.wr16(COMM+4, 8); // split at line 8 00795 GD.wr16(COMM+6, 177); 00796 GD.wr16(COMM+8, 166); 00797 GD.wr16(COMM+10, 291); // split at line 291 00798 GD.wr16(COMM+12, 0); 00799 GD.wr16(COMM+14, 0x8000 | (0x1ff & (8 - 291))); // show line 8 at line 292 00800 GD.microcode(splitscreen_code, sizeof(splitscreen_code)); 00801 00802 setup_sprites(); 00803 00804 00805 memset(&sounds, 0, sizeof(sounds)); 00806 level = 0; 00807 score = 0; 00808 lives = 3; 00809 unsigned int r = 0; 00810 start_level(); 00811 00812 while (lives) { 00813 int i;//, j; 00814 00815 runobjects(r); 00816 00817 for (i = 0; i < 128; i++) 00818 objects[i].collide = 0xff; 00819 00820 GD.waitvblank(); 00821 // swap frames 00822 GD.wr(SPR_PAGE, (r & 1)); 00823 int scrollx = objects[0].x >> 4; 00824 int scrolly = objects[0].y >> 4; 00825 GD.wr16(COMM+6, scrollx & 0x1ff); 00826 GD.wr16(COMM+8, scrolly & 0x1ff); 00827 map_refresh(scrolly >> 6); 00828 update_score(); 00829 GD.wr16(COMM+12, r); // horizontal scroll the bottom banner 00830 00831 GD.waitvblank(); 00832 00833 GD.__start(COLLISION); 00834 for (i = 0; i < 256; i++) { 00835 byte c = spimain.write(0); // c is the colliding sprite number 00836 if (c != 0xff) { 00837 objects[spr2obj[i]].collide = spr2obj[c]; 00838 } 00839 } 00840 GD.__end(); 00841 00842 if (sounds.boing) { 00843 byte x; 00844 if ((16 - (sounds.boing - 1) * 2) <0) { 00845 x = 0; 00846 } else { 00847 x = 16 - (sounds.boing - 1) * 2; 00848 } 00849 byte v = x; //max(0, 16 - (sounds.boing - 1) * 2); 00850 GD.voice(0, 0, 4 * 4000 - 700 * sounds.boing, v/2, v/2); 00851 GD.voice(1, 1, 1000 - 100 * sounds.boing, v, v); 00852 SOUNDCYCLE(sounds.boing); 00853 } 00854 if (sounds.boom) { 00855 byte x; 00856 if ((96 - (sounds.boom - 1) * 6) <0) { 00857 x = 0; 00858 } else { 00859 x = 96 - (sounds.boom - 1) * 6; 00860 } 00861 byte v = x;//max(0, 96 - (sounds.boom - 1) * 6); 00862 GD.voice(2, 0, 220, v, v); 00863 GD.voice(3, 1, 220/8, v/2, v/2); 00864 SOUNDCYCLE(sounds.boom); 00865 } 00866 if (sounds.pop) { 00867 byte x; 00868 if ((32 - (sounds.pop - 1) * 3) <0) { 00869 x = 0; 00870 } else { 00871 x = 32 - (sounds.pop - 1) * 3; 00872 } 00873 byte v = x;//max(0, 32 - (sounds.pop - 1) * 3); 00874 GD.voice(4, 0, 440, v, v); 00875 GD.voice(5, 1, 440/8, v/2, v/2); 00876 SOUNDCYCLE(sounds.pop); 00877 } 00878 GD.voice(6, 1, 40, sounds.thrust ? 10 : 0, sounds.thrust ? 10 : 0); 00879 00880 static byte tune; 00881 if (sounds.bass) { 00882 byte v = sounds.bass < 9 ? 63 : 0; 00883 int f0 = tune ? 130: 163 ; 00884 byte partials[] = { 71, 32, 14, 75, 20, 40 }; 00885 byte i; 00886 for (i = 0; i < 6; i++) { 00887 byte a = (v * partials[i]) >> 8; 00888 GD.voice(7 + i, 0, f0 * (i + 1), a, a); 00889 } 00890 SOUNDCYCLE(sounds.bass); 00891 } 00892 static byte rhythm; 00893 byte x; 00894 if ((24 - level) <10) { 00895 x = 10; 00896 } else { 00897 x = 24 - level; 00898 } 00899 if (++rhythm >= x) { 00900 sounds.bass = 1; 00901 rhythm = 0; 00902 tune = !tune; 00903 } 00904 00905 byte nenemies = 64; 00906 byte pe = enemies; 00907 while (pe) { 00908 pe = objects[pe].state; 00909 nenemies--; 00910 } 00911 if (nenemies == 0) { 00912 level++; 00913 start_level(); 00914 } 00915 00916 r++; 00917 } 00918 } 00919 }
Generated on Thu Jul 14 2022 17:33:36 by 1.7.2