#include #include #include #define TFT_CS D0 #define TFT_RST D2 #define TFT_DC D1 Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); #define pin_up A5 #define pin_down A3 uint8_t y = 128; /* object types */ struct _st_ot_struct { uint8_t missle_mask; uint8_t hit_mask; uint8_t points; uint8_t draw_fn; uint8_t move_fn; uint8_t destroy_fn; uint8_t is_hit_fn; uint8_t fire_fn; }; typedef struct _st_ot_struct st_ot; struct _st_obj_struct { uint8_t ot; int8_t tmp; int16_t x, y; int8_t x0, y0, x1, y1; }; typedef struct _st_obj_struct st_obj; #define ST_FP 4 #define ST_DRAW_NONE 0 #define ST_DRAW_BBOX 1 #define ST_DRAW_TRASH1 2 #define ST_DRAW_PLAYER1 3 #define ST_DRAW_TRASH2 4 #define ST_DRAW_PLAYER2 5 #define ST_DRAW_PLAYER3 6 #define ST_DRAW_GADGET 7 #define ST_DRAW_BACKSLASH 8 #define ST_DRAW_SLASH 9 #define ST_DRAW_BIG_TRASH 10 #define ST_MOVE_NONE 0 #define ST_MOVE_X_SLOW 1 #define ST_MOVE_PX_NORMAL 2 #define ST_MOVE_PX_FAST 3 #define ST_MOVE_PLAYER 4 #define ST_MOVE_PY 5 #define ST_MOVE_NY 6 #define ST_MOVE_IMPLODE 7 #define ST_MOVE_X_FAST 8 #define ST_MOVE_WALL 9 #define ST_MOVE_NXPY 10 #define ST_MOVE_NXNY 11 #define ST_IS_HIT_NONE 0 #define ST_IS_HIT_BBOX 1 #define ST_IS_HIT_WALL 2 #define ST_DESTROY_NONE 0 #define ST_DESTROY_DISAPPEAR 1 #define ST_DESTROY_TO_DUST 2 #define ST_DESTROY_GADGET 3 #define ST_DESTROY_PLAYER 4 #define ST_DESTROY_PLAYER_GADGETS 5 #define ST_DESTROY_BIG_TRASH 6 #define ST_FIRE_NONE 0 #define ST_FIRE_PLAYER1 1 #define ST_FIRE_PLAYER2 2 #define ST_FIRE_PLAYER3 3 #define ST_OT_WALL_SOLID 1 #define ST_OT_BIG_TRASH 2 #define ST_OT_MISSLE 3 #define ST_OT_TRASH1 4 #define ST_OT_PLAYER 5 #define ST_OT_DUST_PY 6 #define ST_OT_DUST_NY 7 #define ST_OT_TRASH_IMPLODE 8 #define ST_OT_TRASH2 9 #define ST_OT_PLAYER2 10 #define ST_OT_PLAYER3 11 #define ST_OT_GADGET 12 #define ST_OT_GADGET_IMPLODE 13 #define ST_OT_DUST_NXPY 14 #define ST_OT_DUST_NXNY 15 st_obj st_objects[60]; uint8_t st_player_pos; #define ST_POINTS_PER_LEVEL 25 uint16_t st_player_points; uint16_t st_player_points_delayed; uint16_t st_highscore = 0; #define ST_STATE_PREPARE 0 #define ST_STATE_IPREPARE 1 #define ST_STATE_GAME 2 #define ST_STATE_END 3 #define ST_STATE_IEND 4 uint8_t st_state = ST_STATE_PREPARE; uint8_t st_difficulty = 1; #define ST_DIFF_VIS_LEN 30 #define ST_DIFF_FP 5 uint16_t st_to_diff_cnt = 0; const st_ot st_object_types[] PROGMEM = { { 0, 0, 0, ST_DRAW_NONE, ST_MOVE_NONE, ST_DESTROY_DISAPPEAR, ST_IS_HIT_NONE, ST_FIRE_NONE }, { 2, 1, 30, ST_DRAW_BBOX, ST_MOVE_WALL, ST_DESTROY_DISAPPEAR, ST_IS_HIT_WALL, ST_FIRE_NONE }, { 2, 1, 0, ST_DRAW_BIG_TRASH, ST_MOVE_X_SLOW, ST_DESTROY_BIG_TRASH, ST_IS_HIT_BBOX, ST_FIRE_NONE }, { 1, 0, 0, ST_DRAW_BBOX, ST_MOVE_PX_FAST, ST_DESTROY_DISAPPEAR, ST_IS_HIT_NONE, ST_FIRE_NONE }, { 2, 1, 0, ST_DRAW_TRASH1, ST_MOVE_X_SLOW, ST_DESTROY_TO_DUST, ST_IS_HIT_BBOX, ST_FIRE_NONE }, { 0, 2, 0, ST_DRAW_PLAYER1, ST_MOVE_PLAYER, ST_DESTROY_PLAYER, ST_IS_HIT_BBOX, ST_FIRE_PLAYER1 }, { 0, 0, 0, ST_DRAW_BBOX, ST_MOVE_PY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, { 0, 0, 0, ST_DRAW_BBOX, ST_MOVE_NY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, { 0, 0, 5, ST_DRAW_TRASH1, ST_MOVE_IMPLODE, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, { 2, 1, 0, ST_DRAW_TRASH2, ST_MOVE_X_SLOW, ST_DESTROY_TO_DUST, ST_IS_HIT_BBOX, ST_FIRE_NONE }, { 0, 2, 0, ST_DRAW_PLAYER2, ST_MOVE_PLAYER, ST_DESTROY_PLAYER_GADGETS, ST_IS_HIT_BBOX, ST_FIRE_PLAYER2 }, { 0, 2, 0, ST_DRAW_PLAYER3, ST_MOVE_PLAYER, ST_DESTROY_PLAYER_GADGETS, ST_IS_HIT_BBOX, ST_FIRE_PLAYER3 }, { 0, 1, 0, ST_DRAW_GADGET, ST_MOVE_X_FAST, ST_DESTROY_GADGET, ST_IS_HIT_BBOX, ST_FIRE_NONE }, { 0, 0, 20, ST_DRAW_GADGET, ST_MOVE_IMPLODE, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, { 0, 0, 0, ST_DRAW_BACKSLASH, ST_MOVE_NXPY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, { 0, 0, 0, ST_DRAW_SLASH, ST_MOVE_NXNY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE }, }; const uint8_t st_bitmap_player1[] PROGMEM = { 0x060, 0x0f8, 0x07e, 0x0f8, 0x060 }; const uint8_t st_bitmap_player2[] PROGMEM = { 0x060, 0x078, 0x060, 0x0e0, 0x0f8, 0x07e, 0x0f8, 0x060 }; const uint8_t st_bitmap_player3[] PROGMEM = { 0x060, 0x078, 0x060, 0x0e0, 0x0f8, 0x07e, 0x0f8, 0x0e0, 0x060, 0x078, 0x060 }; const uint8_t st_bitmap_trash_5x5_1[] PROGMEM = { 0x070, 0x0f0, 0x0f8, 0x078, 0x030, }; const uint8_t st_bitmap_trash_5x5_2[] PROGMEM = { 0x030, 0x0f8, 0x0f8, 0x0f0, 0x070, }; const uint8_t st_bitmap_trash_7x7[] PROGMEM = { 0x038, 0x07c, 0x0fc, 0x0fe, 0x0fe, 0x07e, 0x078, }; const uint8_t st_bitmap_gadget[] PROGMEM = { 0x070, 0x0d8, 0x088, 0x0d8, 0x070, }; char st_itoa_buf[12]; char *st_itoa(unsigned long v) { volatile unsigned char i = 11; st_itoa_buf[11] = '\0'; while( i > 0) { i--; st_itoa_buf[i] = (v % 10)+'0'; v /= 10; if ( v == 0 ) break; } return st_itoa_buf+i; } uint8_t st_rnd(void) { return rand(); } static st_obj *st_GetObj(uint8_t objnr) { return st_objects+objnr; } uint8_t st_GetMissleMask(uint8_t objnr) { st_obj *o = st_GetObj(objnr); return pgm_read_byte(&(st_object_types[o->ot].missle_mask)); } uint8_t st_GetHitMask(uint8_t objnr) { st_obj *o = st_GetObj(objnr); return pgm_read_byte(&(st_object_types[o->ot].hit_mask)); } int8_t st_FindObj(uint8_t ot) { int8_t i; for( i = 0; i < 60; i++ ) { if ( st_objects[i].ot == ot ) return i; } return -1; } void st_ClrObjs(void) { int8_t i; for( i = 0; i < 60; i++ ) st_objects[i].ot = 0; } int8_t st_NewObj(void) { int8_t i; for( i = 0; i < 60; i++ ) { if ( st_objects[i].ot == 0 ) return i; } return -1; } uint8_t st_CntObj(uint8_t ot) { uint8_t i; uint8_t cnt = 0; for( i = 0; i < 60; i++ ) { if ( st_objects[i].ot == ot ) cnt++; } return cnt; } uint8_t st_px_x, st_px_y; uint8_t st_CalcXY(st_obj *o) { st_px_y = o->y>>ST_FP; st_px_x = o->x>>ST_FP; return st_px_x; } void st_SetXY(st_obj *o, uint8_t x, uint8_t y) { o->x = ((int16_t)x) << ST_FP; o->y = ((int16_t)y) << ST_FP; } int16_t st_bbox_x0, st_bbox_y0, st_bbox_x1, st_bbox_y1; void st_CalcBBOX(uint8_t objnr) { st_obj *o = st_GetObj(objnr); st_bbox_x0 = (uint16_t)(o->x>>ST_FP); st_bbox_x1 = st_bbox_x0; st_bbox_x0 += o->x0; st_bbox_x1 += o->x1; st_bbox_y0 = (uint16_t)(o->y>>ST_FP); st_bbox_y1 = st_bbox_y0; st_bbox_y0 += o->y0; st_bbox_y1 += o->y1; } uint8_t st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1; uint8_t st_ClipBBOX(void) { if ( st_bbox_x0 >= 240 ) return 0; if ( st_bbox_x0 >= 0 ) st_cbbox_x0 = (uint16_t)st_bbox_x0; else st_cbbox_x0 = 0; if ( st_bbox_x1 < 0 ) return 0; if ( st_bbox_x1 < 240 ) st_cbbox_x1 = (uint16_t)st_bbox_x1; else st_cbbox_x1 = 240-1; if ( st_bbox_y0 >= 320 ) return 0; if ( st_bbox_y0 >= 0 ) st_cbbox_y0 = (uint16_t)st_bbox_y0; else st_cbbox_y0 = 0; if ( st_bbox_y1 < 0 ) return 0; if ( st_bbox_y1 < 320 ) st_cbbox_y1 = (uint16_t)st_bbox_y1; else st_cbbox_y1 = 320-1; return 1; } uint8_t st_IsOut(uint8_t objnr) { st_CalcBBOX(objnr); if ( st_bbox_x0 >= 240 ) return 1; if ( st_bbox_x1 < 0 ) return 1; if ( st_bbox_y0 >= 320 ) return 1; if ( st_bbox_y1 < 0 ) return 1; return 0; } void st_Disappear(uint8_t objnr) { st_obj *o = st_GetObj(objnr); st_player_points += pgm_read_byte(&(st_object_types[o->ot].points)); o->ot = 0; } void st_Move(uint8_t objnr) { st_obj *o = st_GetObj(objnr); switch(pgm_read_byte(&(st_object_types[o->ot].move_fn))) { case ST_MOVE_NONE: break; case ST_MOVE_X_SLOW: o->x -= (1<x -= st_difficulty; o->y += (int16_t)o->tmp; if ( o->y >= ((320-1) << ST_FP) || o->y <= 0 ) o->tmp = - o->tmp; break; case ST_MOVE_X_FAST: o->x -= (1<y += (int16_t)o->tmp; if ( o->y >= ((320-1) << ST_FP) || o->y <= 0 ) o->tmp = - o->tmp; break; case ST_MOVE_PX_NORMAL: o->x += (1<x += (1<y = st_player_pos<y += 3*ST_FP; break; case ST_MOVE_NY: o->y -= 3*ST_FP; break; case ST_MOVE_NXPY: o->y += 3*ST_FP; o->x -= 3*ST_FP; break; case ST_MOVE_NXNY: o->y -= 3*ST_FP; o->x -= 3*ST_FP; break; case ST_MOVE_IMPLODE: o->tmp++; if ( (o->tmp & 0x03) == 0 ) { if ( o->x0 != o->x1 ) o->x0++; else st_Disappear(objnr); } break; case ST_MOVE_WALL: o->x -= 1; o->x -= (st_difficulty>>1); break; } } void st_DrawBBOX(uint8_t objnr) { st_CalcBBOX(objnr); if ( st_ClipBBOX() == 0 ) return; tft.drawRect(st_cbbox_x0, st_cbbox_y0, st_cbbox_x1-st_cbbox_x0+1, st_cbbox_y1-st_cbbox_y0+1, ILI9341_WHITE); } void st_DrawBitmap(uint8_t objnr, const uint8_t * bm, uint8_t w, uint8_t h) { st_CalcBBOX(objnr); tft.drawBitmap(st_bbox_x0, st_bbox_y1, bm, w, h, ILI9341_WHITE); } void st_DrawObj(uint8_t objnr) { st_obj *o = st_GetObj(objnr); switch(pgm_read_byte(&(st_object_types[o->ot].draw_fn))) { case ST_DRAW_NONE: break; case ST_DRAW_BBOX: st_DrawBBOX(objnr); break; case ST_DRAW_TRASH1: st_DrawBitmap(objnr, st_bitmap_trash_5x5_1,o->x1-o->x0+1, 5); break; case ST_DRAW_TRASH2: st_DrawBitmap(objnr, st_bitmap_trash_5x5_2,o->x1-o->x0+1, 5); break; case ST_DRAW_BIG_TRASH: st_DrawBitmap(objnr, st_bitmap_trash_7x7,o->x1-o->x0+1, 7); break; case ST_DRAW_PLAYER1: st_DrawBitmap(objnr, st_bitmap_player1,7,5); break; case ST_DRAW_PLAYER2: st_DrawBitmap(objnr, st_bitmap_player2,7,8); break; case ST_DRAW_PLAYER3: st_DrawBitmap(objnr, st_bitmap_player3,7,11); break; case ST_DRAW_GADGET: st_DrawBitmap(objnr, st_bitmap_gadget,5,5); break; case ST_DRAW_BACKSLASH: { uint8_t x; uint8_t y; x = st_CalcXY(o); y = st_px_y; tft.drawPixel(x, y, ILI9341_WHITE); x++; y--; tft.drawPixel(x, y, ILI9341_WHITE); x++; y--; tft.drawPixel(x, y, ILI9341_WHITE); } break; case ST_DRAW_SLASH: { uint8_t x; uint8_t y; x = st_CalcXY(o); y = st_px_y; tft.drawPixel(x, y, ILI9341_WHITE); x++; y++; tft.drawPixel(x, y, ILI9341_WHITE); x++; y++; tft.drawPixel(x, y, ILI9341_WHITE); } break; } } uint8_t st_IsHitBBOX(uint8_t objnr, uint8_t x, uint8_t y) { st_CalcBBOX(objnr); if ( st_ClipBBOX() == 0 ) return 0; if ( x < st_cbbox_x0 ) return 0; if ( x > st_cbbox_x1 ) return 0; if ( y < st_cbbox_y0 ) return 0; if ( y > st_cbbox_y1 ) return 0; return 1; } void st_Destroy(uint8_t objnr) { int8_t nr; st_obj *o = st_GetObj(objnr); switch(pgm_read_byte(&(st_object_types[o->ot].destroy_fn))) { case ST_DESTROY_NONE: break; case ST_DESTROY_DISAPPEAR: st_Disappear(objnr); break; case ST_DESTROY_GADGET: nr = st_FindObj(ST_OT_PLAYER2); if ( nr >= 0 ) st_SetupPlayer(nr, ST_OT_PLAYER3); else { nr = st_FindObj(ST_OT_PLAYER); if ( nr >= 0 ) st_SetupPlayer(nr, ST_OT_PLAYER2); } st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY); st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY); o->ot = ST_OT_GADGET_IMPLODE; o->tmp = 0; break; case ST_DESTROY_TO_DUST: st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY); st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY); o->ot = ST_OT_TRASH_IMPLODE; o->tmp = 0; break; case ST_DESTROY_BIG_TRASH: st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY); st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY); st_InitTrash((o->x>>ST_FP)-1, (o->y>>ST_FP)+3, 2+(st_rnd()&3)); st_InitTrash((o->x>>ST_FP)-2, (o->y>>ST_FP)-3, -2-(st_rnd()&3)); st_Disappear(objnr); break; case ST_DESTROY_PLAYER: st_Disappear(objnr); st_state = ST_STATE_END; o->tmp = 0; break; case ST_DESTROY_PLAYER_GADGETS: st_SetupPlayer(objnr, ST_OT_PLAYER); break; } } uint8_t st_IsHit(uint8_t objnr, uint8_t x, uint8_t y, uint8_t missle_mask) { uint8_t hit_mask = st_GetHitMask(objnr); st_obj *o; if ( (hit_mask & missle_mask) == 0 ) return 0; o = st_GetObj(objnr); switch(pgm_read_byte(&(st_object_types[o->ot].is_hit_fn))) { case ST_IS_HIT_NONE: break; case ST_IS_HIT_BBOX: if ( st_IsHitBBOX(objnr, x, y) != 0 ) { st_Destroy(objnr); return 1; } break; case ST_IS_HIT_WALL: if ( st_IsHitBBOX(objnr, x, y) != 0 ) { o->x0++; if ( o->x0 < o->x1 ) { st_NewTrashDust(x, y, ST_OT_DUST_NXPY); st_NewTrashDust(x, y, ST_OT_DUST_NXNY); } else { st_Destroy(objnr); st_NewTrashDust(x, y, ST_OT_DUST_NXPY); st_NewTrashDust(x, y, ST_OT_DUST_NXNY); st_NewTrashDust(x, y, ST_OT_DUST_NY); st_NewTrashDust(x, y, ST_OT_DUST_PY); } return 1; } break; } return 0; } uint8_t st_fire_player = 0; uint8_t st_fire_period = 51; uint8_t st_manual_fire_delay = 20; uint8_t st_is_fire_last_value = 0; void st_FireStep(uint8_t is_auto_fire, uint8_t is_fire) { if ( is_auto_fire != 0 ) { st_fire_player++; if ( st_fire_player >= st_fire_period ) st_fire_player = 0; } else { if ( st_fire_player < st_manual_fire_delay ) { st_fire_player++; } else { if ( st_is_fire_last_value == 0 ) if ( is_fire != 0 ) st_fire_player = 0; } st_is_fire_last_value = is_fire; } } void st_Fire(uint8_t objnr) { st_obj *o = st_GetObj(objnr); uint8_t x; uint8_t y; switch(pgm_read_byte(&(st_object_types[o->ot].fire_fn))) { case ST_FIRE_NONE: break; case ST_FIRE_PLAYER1: if ( st_fire_player == 0 ) { x = st_CalcXY(o); y = st_px_y; st_NewPlayerMissle(x , y ); } break; case ST_FIRE_PLAYER2: if ( st_fire_player == 0 ) { x = st_CalcXY(o); y = st_px_y; st_NewPlayerMissle(x , y ); st_NewPlayerMissle(x , y+4 ); } break; case ST_FIRE_PLAYER3: if ( st_fire_player == 0 ) { x = st_CalcXY(o); y = st_px_y; st_NewPlayerMissle(x , y ); st_NewPlayerMissle(x , y+4 ); st_NewPlayerMissle(x , y-4 ); } break; } } void st_NewGadget(uint8_t x, uint8_t y) { st_obj *o; int8_t objnr = st_NewObj(); if ( objnr < 0 ) return; o = st_GetObj(objnr); st_SetXY(o, x, y); o->ot = ST_OT_GADGET; o->tmp = 8; o->x0 = -3; o->x1 = 1; o->y0 = -2; o->y1 = 2; } void st_InitTrash(uint8_t x, uint8_t y, int8_t dir) { st_obj *o; int8_t objnr = st_NewObj(); if ( objnr < 0 ) return; o = st_GetObj(objnr); if ( (st_rnd() & 1) == 0 ) o->ot = ST_OT_TRASH1; else o->ot = ST_OT_TRASH2; if ( dir == 0 ) { o->tmp = 0; if ( st_rnd() & 1 ) { if ( st_rnd() & 1 ) o->tmp++; else o->tmp--; } } else { o->tmp = dir; } st_SetXY(o, x, y); o->x0 = -3; o->x1 = 1; o->y0 = -2; o->y1 = 2; if ( st_difficulty >= 5 ) { if ( (st_rnd() & 3) == 0 ) { o->ot = ST_OT_BIG_TRASH; o->y0--; o->y1++; o->x0--; o->x1++; } } } void st_NewTrashDust(uint8_t x, uint8_t y, int ot) { st_obj *o; int8_t objnr = st_NewObj(); if ( objnr < 0 ) return; o = st_GetObj(objnr); o->ot = ot; st_SetXY(o, x, y); o->x0 = 0; o->x1 = 0; o->y0 = -2; o->y1 = 2; } void st_NewTrashDustAreaArgs(int16_t x, int16_t y, int ot) { st_NewTrashDust(x>>ST_FP, y>>ST_FP, ot); } void st_NewWall(void) { st_obj *o; int8_t objnr = st_NewObj(); int8_t h; if ( objnr < 0 ) return; o = st_GetObj(objnr); o->ot = ST_OT_WALL_SOLID; h = st_rnd(); h &= 63; h = (int8_t)(((int16_t)h*(int16_t)(320/4))>>6); h += 320/6; o->x0 = 0; o->x1 = 5; o->x = (240-1)<y = (320-1)<y0 = -h; o->y1 = 0; } else { o->y = (0)<y0 = 0; o->y1 = h; } } void st_NewPlayerMissle(uint8_t x, uint8_t y) { st_obj *o; int8_t objnr = st_NewObj(); if ( objnr < 0 ) return; o = st_GetObj(objnr); o->ot = ST_OT_MISSLE; st_SetXY(o, x, y); o->x0 = -4; o->x1 = 1; o->y0 = 0; o->y1 = 0; } void st_SetupPlayer(uint8_t objnr, uint8_t ot) { st_obj *o = st_GetObj(objnr); switch(ot) { case ST_OT_PLAYER: o->ot = ot; o->y0 = -2; o->y1 = 2; break; case ST_OT_PLAYER2: o->ot = ot; o->y0 = -2; o->y1 = 5; break; case ST_OT_PLAYER3: o->ot = ot; o->y0 = -5; o->y1 = 5; break; } } void st_NewPlayer(void) { st_obj *o; int8_t objnr = st_NewObj(); if ( objnr < 0 ) return; o = st_GetObj(objnr); o->x = 6<y = (320/2)<x0 = -6; o->x1 = 0; st_SetupPlayer(objnr, ST_OT_PLAYER); } void st_InitDeltaWall(void) { uint8_t i; uint8_t cnt = 0; uint8_t max_x = 0; uint8_t max_l; uint8_t min_dist_for_new = 40; uint8_t my_difficulty = st_difficulty; if ( st_difficulty >= 2 ) { max_l = 240; max_l -= min_dist_for_new; if ( my_difficulty > 30 ) my_difficulty = 30; min_dist_for_new -= my_difficulty; for( i = 0; i < 60; i++ ) { if ( st_objects[i].ot == ST_OT_WALL_SOLID ) { cnt++; if ( max_x < (st_objects[i].x>>ST_FP) ) max_x = (st_objects[i].x>>ST_FP); } } if ( max_x < max_l ) { st_NewWall(); } } } void st_InitDeltaTrash(void) { uint8_t i; uint8_t cnt = 0; uint8_t max_x = 0; uint8_t max_l; uint8_t upper_trash_limit = 60-7; uint8_t min_dist_for_new = 20; uint8_t my_difficulty = st_difficulty; if ( my_difficulty > 14 ) my_difficulty = 14; min_dist_for_new -= my_difficulty; for( i = 0; i < 60; i++ ) { if ( st_objects[i].ot == ST_OT_TRASH1 || st_objects[i].ot == ST_OT_TRASH2 || st_objects[i].ot == ST_OT_GADGET || st_objects[i].ot == ST_OT_BIG_TRASH ) { cnt++; if ( max_x < (st_objects[i].x>>ST_FP) ) max_x = (st_objects[i].x>>ST_FP); } } max_l = 240; max_l -= min_dist_for_new; if ( cnt < upper_trash_limit ) if ( max_x < max_l ) { if ( (st_difficulty >= 3) && ((st_rnd() & 7) == 0) ) st_NewGadget(240-1, rand() & (320-1)); else st_InitTrash(240-1, rand() & (320-1),0 ); } } void st_InitDelta(void) { st_InitDeltaTrash(); st_InitDeltaWall(); } void st_DrawInGame(uint8_t fps) { uint8_t i; for( i = 0; i < 60; i++ ) st_DrawObj(i); tft.fillRect(0, 0, 240, 8, ILI9341_BLACK); tft.drawFastHLine(0, 8, 240, ILI9341_WHITE); tft.setCursor(0, 0); tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1); tft.print(st_itoa(st_difficulty)); tft.drawFastHLine(10, 10, (st_to_diff_cnt>>ST_DIFF_FP)+1, ILI9341_WHITE); tft.drawFastVLine(10, 7, 3, ILI9341_WHITE); tft.drawFastVLine(10+ST_DIFF_VIS_LEN, 7, 3, ILI9341_WHITE); tft.setCursor(180, 0); tft.print(st_itoa(st_player_points_delayed)); if ( fps > 0 ) { tft.setCursor(90, 0); tft.print("FPS:"); tft.print(st_itoa(fps)); } } void st_Draw(uint8_t fps) { switch(st_state) { case ST_STATE_PREPARE: case ST_STATE_IPREPARE: tft.setCursor(31, 160); tft.setTextColor(ILI9341_RED); tft.setTextSize(2); tft.print("GAMESHINE"); tft.setTextColor(ILI9341_WHITE); tft.setTextSize(2); tft.setCursor(18, 145); tft.print("SPACE TRASH!!!"); tft.drawFastHLine(240-st_to_diff_cnt-10, 160, 11, ILI9341_WHITE); break; case ST_STATE_GAME: st_DrawInGame(fps); break; case ST_STATE_END: case ST_STATE_IEND: tft.setCursor(0, 160); tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1); tft.print("Game Over"); tft.setCursor(50, 160); tft.print(st_itoa(st_player_points)); tft.setCursor(75, 160); tft.print(st_itoa(st_highscore)); tft.drawFastHLine(st_to_diff_cnt, 160, 11, ILI9341_WHITE); break; } } void st_SetupInGame(void) { st_player_points = 0; st_player_points_delayed = 0; st_difficulty = 1; st_to_diff_cnt = 0; st_ClrObjs(); st_NewPlayer(); } void st_Setup(void) { tft.begin(); tft.setRotation(1); tft.fillScreen(ILI9341_BLACK); } void st_StepInGame(uint8_t player_pos, uint8_t is_auto_fire, uint8_t is_fire) { uint8_t i, j; uint8_t missle_mask; if ( player_pos < 64 ) st_player_pos = 0; else if ( player_pos >= 192 ) st_player_pos = 320-2-1; else st_player_pos = ((uint16_t)((player_pos-64)) * (uint16_t)(320-2))/128; st_player_pos+=1; for( i = 0; i < 60; i++ ) st_Move(i); for( i = 0; i < 60; i++ ) if ( st_objects[i].ot != 0 ) if ( st_IsOut(i) != 0 ) st_Disappear(i); for( i = 0; i < 60; i++ ) { missle_mask = st_GetMissleMask(i); if ( missle_mask != 0 ) if ( st_CalcXY(st_objects+i) != 0 ) for( j = 0; j < 60; j++ ) if ( i != j ) if ( st_IsHit(j, st_px_x, st_px_y, missle_mask) != 0 ) { st_Destroy(i); } } st_FireStep(is_auto_fire, is_fire); for( i = 0; i < 60; i++ ) st_Fire(i); st_InitDelta(); st_to_diff_cnt++; if ( st_to_diff_cnt == (ST_DIFF_VIS_LEN< textSizeMax) increasing = false; } else { textSize -= textSizeStep; if (textSize < textSizeMin) increasing = true; } const char *title = "GAMESHINE"; const char *subtitle = "A Fab Academy Project"; // Center text calculations int16_t x1, y1; uint16_t w, h; // Calculate center for title tft.setTextSize(textSize); tft.getTextBounds(title, 0, 0, &x1, &y1, &w, &h); int16_t x = (310 - w) / 2 + 10; int16_t y = (320 - h) / 2 - 60 ; tft.setCursor(x, y); tft.setTextColor(ILI9341_RED); tft.println(title); // Calculate center for subtitle tft.setTextSize(2); tft.getTextBounds(subtitle, 0, 0, &x1, &y1, &w, &h); x = (310 - w) / 2 + 10; y = (320 - h) / 2 - 35; tft.setCursor(x, y); tft.setTextColor(ILI9341_WHITE); tft.println(subtitle); } void menu() { tft.fillScreen(ILI9341_BLACK); // Draw hexagons for (int i = 0; i < 50; i++) { int x = rand() % 240; int y = rand() % 320; int size = rand() % 20 + 10; uint16_t color = rand() % 65536; drawHexagon(x, y, size, color); } // Animate the "GAMESHINE" logo static uint8_t colorIndex = 0; uint16_t colors[] = { ILI9341_RED, ILI9341_GREEN, ILI9341_BLUE, ILI9341_YELLOW, ILI9341_CYAN }; tft.setCursor(30, 50); tft.setTextColor(colors[colorIndex]); tft.setTextSize(3); tft.println("GAMESHINE"); tft.setCursor(50, 150); tft.setTextColor(ILI9341_GREEN); tft.setTextSize(2); tft.println("1. Space Trash"); tft.setCursor(50, 200); tft.setTextColor(ILI9341_BLUE); tft.println("2. GalaFab"); // Update color index colorIndex = (colorIndex + 1) % 5; } void setup() { tft.begin(); tft.setRotation(1); tft.fillScreen(ILI9341_BLACK); } unsigned long startTime; bool splashScreenDone = false; uint8_t gameSelection = 0; void loop() { if (!splashScreenDone) { unsigned long currentTime = millis(); if (currentTime - startTime > 15000) { // Show splash screen for 15 seconds splashScreenDone = true; } else { splashScreen(); } } else { static unsigned long lastUpdate = 0; if (millis() - lastUpdate > 500) { // Update every 500 milliseconds menu(); lastUpdate = millis(); } if (gameSelection == 0) { if (digitalRead(pin_up)) { gameSelection = 1; delay(200); } else if (digitalRead(pin_down)) { gameSelection = 2; delay(200); } } if (gameSelection == 1) { st_Setup(); for (;;) { static uint8_t direction = 0; // 0 for down, 1 for up st_Step(y, 1, 1); // Automatic fire enabled if (direction == 0) { y++; if (y >= 255) { direction = 1; } } else { y--; if (y <= 1) { direction = 0; } } tft.fillScreen(ILI9341_BLACK); st_Draw(0); } } else if (gameSelection == 2) { // To be implemented... } } }