"Fly 'n' Shoot" game model from Chapters 1 & 9 of PSiCC2 NOTE: Requries QP5. This constructor is called only for statically allocated MineEvt NOTE: QP can call event constructors in Q_NEW, when the port is configured with the Q_EVT_CTOR macro sig = sig_p; poolId_ = 0U; id = id_p; This constructor is called only for statically allocated MineEvt NOTE: QP can call event constructors in Q_NEW, when the port is configured with the Q_EVT_CTOR macro sig = sig_p; poolId_ = 0U; score = score_p; Tunnel Active Object : QActive(Q_STATE_CAST(&Tunnel::initial)), m_blinkTimeEvt(this, BLINK_TIMEOUT_SIG, 0U), m_screenTimeEvt(this, SCREEN_TIMEOUT_SIG, 0U), m_last_mine_x(0U), m_last_mine_y(0U) for (uint8_t n = 0U; n < GAME_MINES_MAX; ++n) { m_mine1_pool[n] = Mine1_getInst(n); // initialize mine1-type pool m_mine2_pool[n] = Mine2_getInst(n); // initialize mine2-type pool m_mines[n] = static_cast<QHsm *>(0); // mine 'n' is unused } uint32_t rnd = (BSP_random() & 0xFFU); // reduce the top wall thickness 18.75% of the time if ((rnd < 48U) && (m_wall_thickness_top > 0U)) { --m_wall_thickness_top; } // reduce the bottom wall thickness 18.75% of the time if ((rnd > 208U) && (m_wall_thickness_bottom > 0U)) { --m_wall_thickness_bottom; } rnd = (BSP_random() & 0xFFU); // grow the bottom wall thickness 19.14% of the time if ((rnd < 49U) && ((GAME_TUNNEL_HEIGHT - m_wall_thickness_top - m_wall_thickness_bottom) > m_wall_gap)) { ++m_wall_thickness_bottom; } // grow the top wall thickness 19.14% of the time if ((rnd > 207U) && ((GAME_TUNNEL_HEIGHT - m_wall_thickness_top - m_wall_thickness_bottom) > m_wall_gap)) { ++m_wall_thickness_top; } // advance the Tunnel by 1 game step to the left // and copy the Tunnel layer to the main frame buffer // BSP_advanceWalls(m_wall_thickness_top, m_wall_thickness_bottom); uint32_t rnd = (BSP_random() & 0xFFU); if (m_last_mine_x > 0U) { --m_last_mine_x; // shift the last Mine 1 position to the left } // last mine far enough? if ((m_last_mine_x + GAME_MINES_DIST_MIN < GAME_TUNNEL_WIDTH) && (rnd < 8U)) // place the mines only 5% of the time { uint8_t n; for (n = 0U; n < Q_DIM(m_mines); ++n) { // look for disabled mines if (m_mines[n] == (QHsm *)0) { break; } } if (n < Q_DIM(m_mines)) { // a disabled Mine found? rnd = (BSP_random() & 0xFFFFU); if ((rnd & 1U) == 0U) { // choose the type of the mine m_mines[n] = m_mine1_pool[n]; } else { m_mines[n] = m_mine2_pool[n]; } // new Mine is planted by the end of the tunnel m_last_mine_x = GAME_TUNNEL_WIDTH - 8U; // choose a random y-position for the Mine in the Tunnel rnd %= (GAME_TUNNEL_HEIGHT - m_wall_thickness_top - m_wall_thickness_bottom - 4U); m_last_mine_y = (uint8_t)(m_wall_thickness_top + 2U + rnd); ObjectPosEvt ope; // event to dispatch to the Mine ope.sig = MINE_PLANT_SIG; ope.x = m_last_mine_x; ope.y = m_last_mine_y; m_mines[n]->dispatch(&ope); // direct dispatch } } for (uint8_t n = 0U; n < GAME_MINES_MAX; ++n) { if (m_mines[n] != static_cast<QHsm *>(0)) { // is the mine used? m_mines[n]->dispatch(e); } } for (uint8_t n = 0; n < GAME_MINES_MAX; ++n) { me->m_mine1_pool[n]->init(); // take the initial tran. for Mine1 me->m_mine2_pool[n]->init(); // take the initial tran. for Mine2 } BSP_randomSeed(1234U); // seed the pseudo-random generator me->subscribe(TIME_TICK_SIG); me->subscribe(PLAYER_TRIGGER_SIG); me->subscribe(PLAYER_QUIT_SIG); // object dictionary for Tunnel object... QS_OBJ_DICTIONARY(&l_tunnel); QS_OBJ_DICTIONARY(&l_tunnel.m_blinkTimeEvt); QS_OBJ_DICTIONARY(&l_tunnel.m_screenTimeEvt); // function dictionaries for Tunnel SM... QS_FUN_DICTIONARY(&Tunnel::initial); QS_FUN_DICTIONARY(&Tunnel::final); QS_FUN_DICTIONARY(&Tunnel::active); QS_FUN_DICTIONARY(&Tunnel::playing); QS_FUN_DICTIONARY(&Tunnel::demo); QS_FUN_DICTIONARY(&Tunnel::game_over); QS_FUN_DICTIONARY(&Tunnel::screen_saver); QS_FUN_DICTIONARY(&Tunnel::screen_saver_hide); QS_FUN_DICTIONARY(&Tunnel::screen_saver_show); // local signals... QS_SIG_DICTIONARY(BLINK_TIMEOUT_SIG, &l_tunnel); QS_SIG_DICTIONARY(SCREEN_TIMEOUT_SIG, &l_tunnel); QS_SIG_DICTIONARY(SHIP_IMG_SIG, &l_tunnel); QS_SIG_DICTIONARY(MISSILE_IMG_SIG, &l_tunnel); QS_SIG_DICTIONARY(MINE_IMG_SIG, &l_tunnel); QS_SIG_DICTIONARY(MINE_DISABLED_SIG, &l_tunnel); QS_SIG_DICTIONARY(EXPLOSION_SIG, &l_tunnel); QS_SIG_DICTIONARY(SCORE_SIG, &l_tunnel); (void)e; // unused parameter Q_ASSERT((Q_EVT_CAST(MineEvt)->id < GAME_MINES_MAX) && (me->m_mines[Q_EVT_CAST(MineEvt)->id] != static_cast<QHsm *>(0))); me->m_mines[Q_EVT_CAST(MineEvt)->id] = static_cast<QHsm *>(0); me->m_blinkTimeEvt.armX(BSP_TICKS_PER_SEC/2U, BSP_TICKS_PER_SEC/2U); // every 1/2 sec me->m_screenTimeEvt.armX(BSP_TICKS_PER_SEC*5U, 0U); // in 5 sec me->m_blink_ctr = 0U; BSP_paintString(24U, (GAME_TUNNEL_HEIGHT / 2U) - 8U, "Quantum LeAps"); BSP_paintString(16U, (GAME_TUNNEL_HEIGHT / 2U) + 0U, "state-machine.com"); BSP_paintString(1U, GAME_TUNNEL_HEIGHT - 18U, "Fire missile: BTN0"); BSP_paintString(1U, GAME_TUNNEL_HEIGHT - 10U, "Fly ship up: BTN1"); BSP_updateScreen(); me->m_blinkTimeEvt.disarm(); me->m_screenTimeEvt.disarm(); me->m_blink_ctr ^= 1U; // toggle the blink counter me->m_blink_ctr == 0U BSP_paintString(24U + 8U*6U, (GAME_TUNNEL_HEIGHT / 2U) - 8U, "LeAps"); BSP_updateScreen(); else BSP_paintString(24U + 8U*6U, (GAME_TUNNEL_HEIGHT / 2U) - 8U, "LeaPs"); BSP_updateScreen(); me->m_last_mine_x = 0U; // last mine at right edge of the tunnel me->m_last_mine_y = 0U; // set the tunnel properties... me->m_wall_thickness_top = 0U; me->m_wall_thickness_bottom = 0U; me->m_wall_gap = GAME_WALLS_GAP_Y; BSP_clearWalls(); // erase the tunnel walls me->m_blinkTimeEvt.armX(BSP_TICKS_PER_SEC/2U, BSP_TICKS_PER_SEC/2U); // every 1/2 sec me->m_screenTimeEvt.armX(BSP_TICKS_PER_SEC*20U, 0U); // in 20 sec me->m_blink_ctr = 0U; // init the blink counter me->m_blinkTimeEvt.disarm(); me->m_screenTimeEvt.disarm(); me->m_blink_ctr ^= 1U; /* toggle the blink cunter */ me->advance(); if (me->m_blink_ctr != 0U) { // add the text into the frame buffer BSP_paintString((GAME_TUNNEL_WIDTH - 10U*6U)/2U, (GAME_TUNNEL_HEIGHT - 4U)/2U, "Press BTN0"); } BSP_updateScreen(); static QP::QEvt const takeoff = QEVT_INITIALIZER(TAKE_OFF_SIG); me->m_wall_gap = GAME_WALLS_GAP_Y; AO_Ship->POST(&takeoff, me); // post the TAKEOFF sig QP::QEvt recycle; recycle.sig = MINE_RECYCLE_SIG; me->dispatchToAllMines(&recycle); // recycle all Mines // render this frame on the display BSP_updateScreen(); me->advance(); me->plantMine(); me->dispatchToAllMines(e); uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x; int8_t y = Q_EVT_CAST(ObjectImageEvt)->y; uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp; // did the Ship/Missile hit the tunnel wall? if (BSP_isWallHit(bmp, x, y)) { static QP::QEvt const hit = QEVT_INITIALIZER(HIT_WALL_SIG); AO_Ship->POST(&hit, me); } BSP_paintBitmap(x, y, bmp); me->dispatchToAllMines(e); // let Mines check for hits uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x; int8_t y = Q_EVT_CAST(ObjectImageEvt)->y; uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp; // did the Ship/Missile hit the tunnel wall? if (BSP_isWallHit(bmp, x, y)) { static QP::QEvt const hit = QEVT_INITIALIZER(HIT_WALL_SIG); AO_Missile->POST(&hit, me); } BSP_paintBitmap(x, y, bmp); me->dispatchToAllMines(e); // let Mines check for hits BSP_paintBitmap(Q_EVT_CAST(ObjectImageEvt)->x, Q_EVT_CAST(ObjectImageEvt)->y, Q_EVT_CAST(ObjectImageEvt)->bmp); BSP_paintBitmap(Q_EVT_CAST(ObjectImageEvt)->x, Q_EVT_CAST(ObjectImageEvt)->y, Q_EVT_CAST(ObjectImageEvt)->bmp); BSP_updateScore(Q_EVT_CAST(ScoreEvt)->score); // increase difficulty of the game: // the tunnel gets narrower as the score goes up // me->m_wall_gap = (uint8_t)(GAME_WALLS_GAP_Y - Q_EVT_CAST(ScoreEvt)->score/100U); if (me->m_wall_gap < GAME_WALLS_MIN_GAP_Y) { me->m_wall_gap = GAME_WALLS_MIN_GAP_Y; } BSP_clearWalls(); BSP_updateScore(Q_EVT_CAST(ScoreEvt)->score); BSP_updateScreen(); me->m_blinkTimeEvt.armX(BSP_TICKS_PER_SEC/2U, BSP_TICKS_PER_SEC/2U); // every 1/2 sec me->m_screenTimeEvt.armX(BSP_TICKS_PER_SEC*5U, 0U); // in 5 se me->m_blink_ctr = 0U; BSP_paintString((GAME_TUNNEL_WIDTH - 6U * 9U) / 2U, (GAME_TUNNEL_HEIGHT / 2U) - 4U, "Game Over"); BSP_updateScreen(); me->m_blinkTimeEvt.disarm(); me->m_screenTimeEvt.disarm(); BSP_updateScore(0U); // update the score on the display me->m_blink_ctr ^= 1U; // toggle the blink counter BSP_paintString((GAME_TUNNEL_WIDTH - 6U*9U) / 2U, (GAME_TUNNEL_HEIGHT / 2U) - 4U, ((me->m_blink_ctr == 0U) ? "Game Over" : " ")); BSP_updateScreen(); BSP_displayOff(); // power down the display me->m_screenTimeEvt.armX(BSP_TICKS_PER_SEC*3U, 0U); // in 3 sec me->m_screenTimeEvt.disarm(); BSP_displayOn(); // power up the display BSP_clearFB(); // clear the screen frame buffer uint32_t rnd = BSP_random(); BSP_paintString((uint8_t)(rnd % (GAME_TUNNEL_WIDTH - 10U*6U)), (uint8_t) (rnd % (GAME_TUNNEL_HEIGHT - 8U)), "Press BTN0"); BSP_updateScreen(); me->m_screenTimeEvt.armX(BSP_TICKS_PER_SEC/3U, 0U); // in 1/3 sec me->m_screenTimeEvt.disarm(); BSP_clearFB(); BSP_updateScreen(); BSP_clearFB(); BSP_updateScreen(); QP::QF::stop(); // stop QF and cleanup Ship Active Object vertical position of the ship in the 8s2 fixed-point notation. : QActive(Q_STATE_CAST(&Ship::initial)), m_x(GAME_SHIP_X), m_y(GAME_SHIP_Y << 2) me->subscribe(TIME_TICK_SIG); me->subscribe(PLAYER_TRIGGER_SIG); // object dictionaries... QS_OBJ_DICTIONARY(&l_ship); // function dictionaries for Ship HSM... QS_FUN_DICTIONARY(&Ship::initial); QS_FUN_DICTIONARY(&Ship::active); QS_FUN_DICTIONARY(&Ship::parked); QS_FUN_DICTIONARY(&Ship::flying); QS_FUN_DICTIONARY(&Ship::exploding); // local signals... QS_SIG_DICTIONARY(PLAYER_SHIP_MOVE_SIG, &l_ship); QS_SIG_DICTIONARY(TAKE_OFF_SIG, &l_ship); QS_SIG_DICTIONARY(HIT_WALL_SIG, &l_ship); QS_SIG_DICTIONARY(HIT_MINE_SIG, &l_ship); QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, &l_ship); (void)e; // unused parameter me->m_score = 0U; /* reset the score */ ScoreEvt *sev = Q_NEW(ScoreEvt, SCORE_SIG); sev->score = me->m_score; AO_Tunnel->POST(sev, me); if (BSP_isThrottle()) { if (me->m_y > 0U) { me->m_y -= 1U; } } else { if (me->m_y < (GAME_TUNNEL_HEIGHT << 2)) { me->m_y += 1U; } } // tell the Tunnel to draw the Ship and test for hits ObjectImageEvt *oie = Q_NEW(ObjectImageEvt, SHIP_IMG_SIG); oie->x = me->m_x; oie->y = me->m_y >> 2; oie->bmp = SHIP_BMP; AO_Tunnel->POST(oie, me); ++me->m_score; // increment the score for surviving another tick if ((me->m_score % 10U) == 0U) { // is the score "round"? ScoreEvt *sev = Q_NEW(ScoreEvt, SCORE_SIG); sev->score = me->m_score; AO_Tunnel->POST(sev, me); } ObjectPosEvt *ope = Q_NEW(ObjectPosEvt, MISSILE_FIRE_SIG); ope->x = me->m_x; ope->y = (me->m_y >> 2) + SHIP_HEIGHT - 1U; AO_Missile->POST(ope, me); me->m_score += Q_EVT_CAST(ScoreEvt)->score; // the score will be sent to the Tunnel by the next TIME_TICK me->m_exp_ctr = 0U; me->m_exp_ctr < 15U ++me->m_exp_ctr; // tell the Tunnel to draw the current stage of Explosion ObjectImageEvt *oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG); oie->bmp = EXPLOSION0_BMP + (me->m_exp_ctr >> 2); oie->x = me->m_x; // x of explosion oie->y = (int8_t)((int)(me->m_y >> 2) - 4U + SHIP_HEIGHT); AO_Tunnel->POST(oie, me); ScoreEvt *gameOver = Q_NEW(ScoreEvt, GAME_OVER_SIG); gameOver->score = me->m_score; AO_Tunnel->POST(gameOver, me); Missile Active Object : QActive(Q_STATE_CAST(&Missile::initial)) me->subscribe( TIME_TICK_SIG); // object dictionary for Missile object QS_OBJ_DICTIONARY(&l_missile); // dictionaries for Missile SM... QS_FUN_DICTIONARY(&Missile::initial); QS_FUN_DICTIONARY(&Missile::armed); QS_FUN_DICTIONARY(&Missile::flying); QS_FUN_DICTIONARY(&Missile::exploding); // local signals... QS_SIG_DICTIONARY(MISSILE_FIRE_SIG, &l_missile); QS_SIG_DICTIONARY(HIT_WALL_SIG, &l_missile); QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, &l_missile); (void)e; // unused parameter me->m_x = Q_EVT_CAST(ObjectPosEvt)->x; me->m_y = Q_EVT_CAST(ObjectPosEvt)->y; me->m_x + GAME_MISSILE_SPEED_X < GAME_TUNNEL_WIDTH me->m_x += GAME_MISSILE_SPEED_X; // tell the Tunnel to draw the Missile and test for wall hits ObjectImageEvt *oie = Q_NEW(ObjectImageEvt, MISSILE_IMG_SIG); oie->x = me->m_x; oie->y = me->m_y; oie->bmp = MISSILE_BMP; AO_Tunnel->POST(oie, me); AO_Ship->POST(e, me); me->m_exp_ctr = 0U; (me->m_x >= GAME_SPEED_X) && (me->m_exp_ctr < 15U) ++me->m_exp_ctr; // advance the explosion counter me->m_x -= GAME_SPEED_X; // move the explosion by one step // tell the Tunnel to render the current stage of Explosion ObjectImageEvt *oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG); oie->x = me->m_x + 3U; // x-pos of explosion oie->y = (int8_t)((int)me->m_y - 4U); // y-pos oie->bmp = EXPLOSION0_BMP + (me->m_exp_ctr >> 2); AO_Tunnel->POST(oie, me); The Mine1 orthogonal component : QHsm(Q_STATE_CAST(&Mine1::initial)) static bool dict_sent = false; if (!dict_sent) { dict_sent = true; // object dictionaries for Mine1 pool... QS_OBJ_DICTIONARY(&l_mine1[0]); QS_OBJ_DICTIONARY(&l_mine1[1]); QS_OBJ_DICTIONARY(&l_mine1[2]); QS_OBJ_DICTIONARY(&l_mine1[3]); QS_OBJ_DICTIONARY(&l_mine1[4]); // function dictionaries for Mine1 SM QS_FUN_DICTIONARY(&Mine1::initial); QS_FUN_DICTIONARY(&Mine1::unused); QS_FUN_DICTIONARY(&Mine1::used); QS_FUN_DICTIONARY(&Mine1::planted); QS_FUN_DICTIONARY(&Mine1::exploding); } // local signals QS_SIG_DICTIONARY(MINE_PLANT_SIG, me); QS_SIG_DICTIONARY(MINE_DISABLED_SIG, me); QS_SIG_DICTIONARY(MINE_RECYCLE_SIG, me); QS_SIG_DICTIONARY(SHIP_IMG_SIG, me); QS_SIG_DICTIONARY(MISSILE_IMG_SIG, me); (void)e; // unused parameter me->m_x = Q_EVT_CAST(ObjectPosEvt)->x; me->m_y = Q_EVT_CAST(ObjectPosEvt)->y; // tell the Tunnel that this mine is becoming disabled MineEvt *mev = Q_NEW(MineEvt, MINE_DISABLED_SIG); mev->id = MINE_ID(me); AO_Tunnel->POST(mev, me); me->m_exp_ctr = 0U; (me->m_x >= GAME_SPEED_X) && (me->m_exp_ctr < 15) ++me->m_exp_ctr; // advance the explosion counter me->m_x -= GAME_SPEED_X; // move explosion by 1 step // tell the Game to render the current stage of Explosion ObjectImageEvt *oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG); oie->x = me->m_x + 1U; // x of explosion oie->y = (int8_t)((int)me->m_y - 4 + 2); // y of explosion oie->bmp = EXPLOSION0_BMP + (me->m_exp_ctr >> 2); AO_Tunnel->POST(oie, me); me->m_x >= GAME_SPEED_X me->m_x -= GAME_SPEED_X; // move the mine 1 step // tell the Tunnel to draw the Mine ObjectImageEvt *oie = Q_NEW(ObjectImageEvt, MINE_IMG_SIG); oie->x = me->m_x; oie->y = me->m_y; oie->bmp = MINE1_BMP; AO_Tunnel->POST(oie, me); uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x; uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y; uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp; BSP_doBitmapsOverlap(MINE1_BMP, me->m_x, me->m_y, bmp, x, y) static MineEvt const mine1_hit(HIT_MINE_SIG, 1U); AO_Ship->POST(&mine1_hit, me); // go straight to 'disabled' and let the Ship do // the exploding uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x; uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y; uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp; BSP_doBitmapsOverlap(MINE1_BMP, me->m_x, me->m_y, bmp, x, y) static ScoreEvt const mine1_destroyed(DESTROYED_MINE_SIG, 25U); AO_Missile->POST(&mine1_destroyed, me); The Mine2 orthogonal component : QHsm(Q_STATE_CAST(&Mine2::initial)) static bool dict_sent = false; if (!dict_sent) { dict_sent = true; // object dictionaries for Mine2 pool... QS_OBJ_DICTIONARY(&l_mine2[0]); QS_OBJ_DICTIONARY(&l_mine2[1]); QS_OBJ_DICTIONARY(&l_mine2[2]); QS_OBJ_DICTIONARY(&l_mine2[3]); QS_OBJ_DICTIONARY(&l_mine2[4]); // function dictionaries for Mine2 SM... QS_FUN_DICTIONARY(&Mine2::initial); QS_FUN_DICTIONARY(&Mine2::unused); QS_FUN_DICTIONARY(&Mine2::used); QS_FUN_DICTIONARY(&Mine2::planted); QS_FUN_DICTIONARY(&Mine2::exploding); } // local signals... QS_SIG_DICTIONARY(MINE_PLANT_SIG, me); QS_SIG_DICTIONARY(MINE_DISABLED_SIG, me); QS_SIG_DICTIONARY(MINE_RECYCLE_SIG, me); QS_SIG_DICTIONARY(SHIP_IMG_SIG, me); QS_SIG_DICTIONARY(MISSILE_IMG_SIG, me); (void)e; // unused parameter me->m_x = Q_EVT_CAST(ObjectPosEvt)->x; me->m_y = Q_EVT_CAST(ObjectPosEvt)->y; // tell the Tunnel that this mine is becoming disabled MineEvt *mev = Q_NEW(MineEvt, MINE_DISABLED_SIG); mev->id = MINE_ID(me); AO_Tunnel->POST(mev, me); me->m_exp_ctr = 0U; (me->m_x >= GAME_SPEED_X) && (me->m_exp_ctr < 15) ++me->m_exp_ctr; // advance the explosion counter me->m_x -= GAME_SPEED_X; // move explosion by 1 step // tell the Game to render the current stage of Explosion ObjectImageEvt *oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG); oie->x = me->m_x + 1U; // x of explosion oie->y = (int8_t)((int)me->m_y - 4 + 2); // y of explosion oie->bmp = EXPLOSION0_BMP + (me->m_exp_ctr >> 2); AO_Tunnel->POST(oie, me); me->m_x >= GAME_SPEED_X me->m_x -= GAME_SPEED_X; // move the mine 1 step // tell the Tunnel to draw the Mine ObjectImageEvt *oie = Q_NEW(ObjectImageEvt, MINE_IMG_SIG); oie->x = me->m_x; oie->y = me->m_y; oie->bmp = MINE2_BMP; AO_Tunnel->POST(oie, me); uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x; uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y; uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp; BSP_doBitmapsOverlap(MINE2_BMP, me->m_x, me->m_y, bmp, x, y) static MineEvt const mine2_hit(HIT_MINE_SIG, 2U); AO_Ship->POST(&mine2_hit, me); // go straight to 'disabled' and let the Ship do // the exploding uint8_t x = Q_EVT_CAST(ObjectImageEvt)->x; uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y; uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp; BSP_doBitmapsOverlap(MINE2_MISSILE_BMP, me->m_x, me->m_y, bmp, x, y) static ScoreEvt const mine2_destroyed(DESTROYED_MINE_SIG, 45U); AO_Missile->POST(&mine2_destroyed, me); #ifndef game_h #define game_h namespace GAME { enum GameSignals { // signals used in the game TIME_TICK_SIG = QP::Q_USER_SIG, // published from tick ISR PLAYER_TRIGGER_SIG, // published by Player (ISR) to trigger the Missile PLAYER_QUIT_SIG, // published by Player (ISR) to quit the game GAME_OVER_SIG, // published by Ship when it finishes exploding // insert other published signals here ... MAX_PUB_SIG, // the last published signal PLAYER_SHIP_MOVE_SIG, // posted by Player (ISR) to the Ship to move it BLINK_TIMEOUT_SIG, // signal for Tunnel's blink timeout event SCREEN_TIMEOUT_SIG, // signal for Tunnel's screen timeout event TAKE_OFF_SIG, // from Tunnel to Ship to grant permission to take off HIT_WALL_SIG, // from Tunnel to Ship when Ship hits the wall HIT_MINE_SIG, // from Mine to Ship or Missile when it hits the mine SHIP_IMG_SIG, // from Ship to the Tunnel to draw and check for hits MISSILE_IMG_SIG, // from Missile the Tunnel to draw and check for hits MINE_IMG_SIG, // sent by Mine to the Tunnel to draw the mine MISSILE_FIRE_SIG, // sent by Ship to the Missile to fire DESTROYED_MINE_SIG, // from Missile to Ship when Missile destroyed Mine EXPLOSION_SIG, // from any exploding object to render the explosion MINE_PLANT_SIG, // from Tunnel to the Mine to plant it MINE_DISABLED_SIG, // from Mine to Tunnel when it becomes disabled MINE_RECYCLE_SIG, // sent by Tunnel to Mine to recycle the mine SCORE_SIG, // from Ship to Tunnel to display the score MAX_SIG // the last signal (keep always last) }; #define GAME_TUNNEL_WIDTH BSP_SCREEN_WIDTH #define GAME_TUNNEL_HEIGHT (BSP_SCREEN_HEIGHT - 10U) #define GAME_MINES_MAX 5U #define GAME_MINES_DIST_MIN 10U #define GAME_SPEED_X 1U #define GAME_MISSILE_SPEED_X 2U #define GAME_SHIP_X 10U #define GAME_SHIP_Y (GAME_TUNNEL_HEIGHT / 2U) #define GAME_WALLS_GAP_Y 50U #define GAME_WALLS_MIN_GAP_Y 20U enum GameBitmapIds { SHIP_BMP, MISSILE_BMP, MINE1_BMP, MINE2_BMP, MINE2_MISSILE_BMP, EXPLOSION0_BMP, EXPLOSION1_BMP, EXPLOSION2_BMP, EXPLOSION3_BMP, MAX_BMP }; // obtain instances of the Mines orthogonal components QP::QHsm *Mine1_getInst(uint8_t id); QP::QHsm *Mine2_getInst(uint8_t id); } // namespace GAME $declare(Events::ObjectPosEvt) $declare(Events::ObjectImageEvt) $declare(Events::MineEvt) $declare(Events::ScoreEvt) // opaque pointers to active objects in the application $declare(AOs::AO_Tunnel) $declare(AOs::AO_Ship) $declare(AOs::AO_Missile) #endif // game_h #include "qpcpp.h" #include "bsp.h" #include "game.h" //Q_DEFINE_THIS_FILE $declare(AOs::Missile) namespace GAME { // local objects ------------------------------------------------------------- static Missile l_missile; // the sole instance of the Missile active object // Public-scope objects ------------------------------------------------------ QP::QActive * const AO_Missile = &l_missile; // opaque pointer } // namespace GAME // Active object definition -------------------------------------------------- $define(AOs::Missile) #include "qpcpp.h" #include "bsp.h" #include "game.h" //Q_DEFINE_THIS_FILE #define SHIP_WIDTH 5U #define SHIP_HEIGHT 3U // encapsulated delcaration of the Ship active object ------------------------ $declare(AOs::Ship) namespace GAME { // local objects ------------------------------------------------------------- static Ship l_ship; // the sole instance of the Ship active object // Public-scope objects ------------------------------------------------------ QP::QActive * const AO_Ship = &l_ship; // opaque pointer } // namespace GAME // Active object definition -------------------------------------------------- $define(AOs::Ship) #include "qpcpp.h" #include "bsp.h" #include "game.h" #include <string.h> // for memmove() and memcpy() Q_DEFINE_THIS_FILE // declaration of the Tunnel AO ---------------------------------------------- $declare(AOs::Tunnel) namespace GAME { // local objects ------------------------------------------------------------- static Tunnel l_tunnel; // the sole instance of the Tunnel active object // Public-scope objects ------------------------------------------------------ QP::QActive * const AO_Tunnel = &l_tunnel; // opaque pointer } // namespace GAME // Active object definition ================================================== $define(AOs::Tunnel) #include "qpcpp.h" #include "bsp.h" #include "game.h" Q_DEFINE_THIS_FILE // encapsulated delcaration of the Mine1 HSM --------------------------------- $declare(AOs::Mine1) namespace GAME { // local objects ------------------------------------------------------------- static Mine1 l_mine1[GAME_MINES_MAX]; // a pool of type-1 mines //............................................................................ QP::QHsm *Mine1_getInst(uint8_t id) { Q_REQUIRE(id < GAME_MINES_MAX); return &l_mine1[id]; } // helper function to provide the ID of this mine ............................ static inline uint8_t MINE_ID(Mine1 const * const me) { return static_cast<uint8_t>(me - l_mine1); } } // namespace GAME // Mine1 class definition ---------------------------------------------------- $define(AOs::Mine1) #include "qpcpp.h" #include "bsp.h" #include "game.h" Q_DEFINE_THIS_FILE // encapsulated delcaration of the Mine1 HSM --------------------------------- $declare(AOs::Mine2) namespace GAME { // local objects ------------------------------------------------------------- static Mine2 l_mine2[GAME_MINES_MAX]; // a pool of type-2 mines //............................................................................ QP::QHsm *Mine2_getInst(uint8_t id) { Q_REQUIRE(id < GAME_MINES_MAX); return &l_mine2[id]; } // helper function to provide the ID of this mine ............................ static inline uint8_t MINE_ID(Mine2 const * const me) { return static_cast<uint8_t>(me - l_mine2); } } // namespace GAME // Mine1 class definition ---------------------------------------------------- $define(AOs::Mine2)