"Fly 'n' Shoot" game model from Chapters 1 & 9 of PSiCC2
NOTE: Requries QP6.
Tunnel Active Object
uint32_t rnd;
rnd = (BSP_random() & 0xFFU);
/* reduce the top wall thickness 18.75% of the time */
if ((rnd < 48U) && (me->wall_thickness_top > 0U)) {
--me->wall_thickness_top;
}
/* reduce the bottom wall thickness 18.75% of the time */
if ((rnd > 208U) && (me->wall_thickness_bottom > 0U)) {
--me->wall_thickness_bottom;
}
rnd = (BSP_random() & 0xFFU);
/* grow the bottom wall thickness 19.14% of the time */
if ((rnd < 49U)
&& ((GAME_TUNNEL_HEIGHT
- me->wall_thickness_top
- me->wall_thickness_bottom) > me->wall_gap))
{
++me->wall_thickness_bottom;
}
/* grow the top wall thickness 19.14% of the time */
if ((rnd > 207U)
&& ((GAME_TUNNEL_HEIGHT
- me->wall_thickness_top
- me->wall_thickness_bottom) > me->wall_gap))
{
++me->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(me->wall_thickness_top, me->wall_thickness_bottom);
uint32_t rnd = (BSP_random() & 0xFFU);
if (me->last_mine_x > 0U) {
--me->last_mine_x; /* shift the last Mine 1 position to the left */
}
/* last mine far enough? */
if ((me->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(me->mines); ++n) { /*look for disabled mines */
if (me->mines[n] == (QMsm *)0) {
break;
}
}
if (n < Q_DIM(me->mines)) { /* a disabled Mine found? */
ObjectPosEvt ope; /* event to dispatch to the Mine */
rnd = (BSP_random() & 0xFFFFU);
if ((rnd & 1U) == 0U) { /* choose the type of the mine */
me->mines[n] = me->mine1_pool[n];
}
else {
me->mines[n] = me->mine2_pool[n];
}
/* new Mine is planted by the end of the tunnel */
me->last_mine_x = GAME_TUNNEL_WIDTH - 8U;
/* choose a random y-position for the Mine in the Tunnel */
rnd %= (GAME_TUNNEL_HEIGHT
- me->wall_thickness_top
- me->wall_thickness_bottom - 4U);
me->last_mine_y = (uint8_t)(me->wall_thickness_top + 2U + rnd);
ope.super.sig = MINE_PLANT_SIG;
ope.x = me->last_mine_x;
ope.y = me->last_mine_y;
QHSM_DISPATCH(me->mines[n], (QEvt *)&ope); /* direct dispatch */
}
}
uint8_t n;
for (n = 0U; n < GAME_MINES_MAX; ++n) {
if (me->mines[n] != (QMsm *)0) { /* is the mine used? */
QHSM_DISPATCH(me->mines[n], e);
}
}
uint8_t n;
for (n = 0U; n < GAME_MINES_MAX; ++n) {
QHSM_INIT(me->mine1_pool[n], (QEvt *)0);/*initial tran. for Mine1 */
QHSM_INIT(me->mine2_pool[n], (QEvt *)0);/*initial tran. for Mine2 */
}
BSP_randomSeed(1234); /* seed the pseudo-random generator */
QActive_subscribe(&me->super, TIME_TICK_SIG);
QActive_subscribe(&me->super, PLAYER_TRIGGER_SIG);
QActive_subscribe(&me->super, PLAYER_QUIT_SIG);
/* object dictionaries... */
QS_OBJ_DICTIONARY(&l_tunnel.blinkTimeEvt);
QS_OBJ_DICTIONARY(&l_tunnel.screenTimeEvt);
/* local signals... */
QS_SIG_DICTIONARY(BLINK_TIMEOUT_SIG, me);
QS_SIG_DICTIONARY(SCREEN_TIMEOUT_SIG, me);
QS_SIG_DICTIONARY(SHIP_IMG_SIG, me);
QS_SIG_DICTIONARY(MISSILE_IMG_SIG, me);
QS_SIG_DICTIONARY(MINE_IMG_SIG, me);
QS_SIG_DICTIONARY(MINE_DISABLED_SIG, me);
QS_SIG_DICTIONARY(EXPLOSION_SIG, me);
QS_SIG_DICTIONARY(SCORE_SIG, me);
(void)e; /* unused parameter */
Q_ASSERT((Q_EVT_CAST(MineEvt)->id < GAME_MINES_MAX)
&& (me->mines[Q_EVT_CAST(MineEvt)->id] != (QMsm *)0));
me->mines[Q_EVT_CAST(MineEvt)->id] = (QMsm *)0;
QTimeEvt_armX(&me->blinkTimeEvt, BSP_TICKS_PER_SEC/2U,
BSP_TICKS_PER_SEC/2U);
QTimeEvt_armX(&me->screenTimeEvt, BSP_TICKS_PER_SEC*5U, 0U);
me->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();
QTimeEvt_disarm(&me->blinkTimeEvt);
QTimeEvt_disarm(&me->screenTimeEvt);
me->blink_ctr ^= 1U; /* toggle the blink counter */
me->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->last_mine_x = 0U; /* last mine at right edge of the tunnel */
me->last_mine_y = 0U;
/* set the tunnel properties... */
me->wall_thickness_top = 0U;
me->wall_thickness_bottom = 0U;
me->wall_gap = GAME_WALLS_GAP_Y;
/* clear the tunnel walls */
BSP_clearWalls();
QTimeEvt_armX(&me->blinkTimeEvt, BSP_TICKS_PER_SEC/2U,
BSP_TICKS_PER_SEC/2U); /* every 1/2 sec */
QTimeEvt_armX(&me->screenTimeEvt, BSP_TICKS_PER_SEC*20U, 0U);
me->blink_ctr = 0U; /* init the blink counter */
QTimeEvt_disarm(&me->blinkTimeEvt);
QTimeEvt_disarm(&me->screenTimeEvt);
me->blink_ctr ^= 1U; /* toggle the blink cunter */
Tunnel_advance(me);
if (me->blink_ctr != 0U) {
/* add the text bitmap into the frame buffer */
BSP_paintString((GAME_TUNNEL_WIDTH - 10U*6U)/2U,
(GAME_TUNNEL_HEIGHT - 4U)/2U,
"Press BTN0");
}
BSP_updateScreen();
static QEvt const takeoff = { TAKE_OFF_SIG, 0U, 0U };
me->wall_gap = GAME_WALLS_GAP_Y;
QACTIVE_POST(AO_Ship, &takeoff, me); /* post the TAKEOFF sig */
QEvt recycle;
recycle.sig = MINE_RECYCLE_SIG;
Tunnel_dispatchToAllMines(me, &recycle); /* recycle all Mines */
/* render this frame on the display */
BSP_updateScreen();
Tunnel_advance(me);
Tunnel_plantMine(me);
Tunnel_dispatchToAllMines(me, 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 QEvt const hit = { HIT_WALL_SIG, 0U, 0U };
QACTIVE_POST(AO_Ship, &hit, me);
}
BSP_paintBitmap(x, y, bmp);
Tunnel_dispatchToAllMines(me, 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 QEvt const hit = { HIT_WALL_SIG, 0U, 0U };
QACTIVE_POST(AO_Missile, &hit, me);
}
BSP_paintBitmap(x, y, bmp);
Tunnel_dispatchToAllMines(me, 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->wall_gap = (uint8_t)(GAME_WALLS_GAP_Y
- Q_EVT_CAST(ScoreEvt)->score/100U);
if (me->wall_gap < GAME_WALLS_MIN_GAP_Y) {
me->wall_gap = GAME_WALLS_MIN_GAP_Y;
}
BSP_clearWalls();
BSP_updateScore(Q_EVT_CAST(ScoreEvt)->score);
BSP_updateScreen();
QTimeEvt_armX(&me->blinkTimeEvt, BSP_TICKS_PER_SEC/2U,
BSP_TICKS_PER_SEC/2U); /* every 1/2 sec */
QTimeEvt_armX(&me->screenTimeEvt, BSP_TICKS_PER_SEC*5U, 0U);
me->blink_ctr = 0U;
BSP_paintString((GAME_TUNNEL_WIDTH - 6U * 9U) / 2U,
(GAME_TUNNEL_HEIGHT / 2U) - 4U,
"Game Over");
BSP_updateScreen();
QTimeEvt_disarm(&me->blinkTimeEvt);
QTimeEvt_disarm(&me->screenTimeEvt);
BSP_updateScore(0); /* update the score on the display */
me->blink_ctr ^= 1U; /* toggle the blink counter */
BSP_paintString((GAME_TUNNEL_WIDTH - 6U*9U) / 2U,
(GAME_TUNNEL_HEIGHT / 2U) - 4U,
((me->blink_ctr == 0U)
? "Game Over"
: " "));
BSP_updateScreen();
BSP_displayOff(); /* power down the display */
QTimeEvt_armX(&me->screenTimeEvt, BSP_TICKS_PER_SEC*3U, 0U);
QTimeEvt_disarm(&me->screenTimeEvt);
BSP_displayOn(); /* power up the display */
uint32_t rnd = BSP_random();
/* clear the screen frame buffer */
BSP_clearFB();
BSP_paintString((uint8_t)(rnd % (GAME_TUNNEL_WIDTH - 10U*6U)),
(uint8_t) (rnd % (GAME_TUNNEL_HEIGHT - 8U)),
"Press BTN0");
BSP_updateScreen();
QTimeEvt_armX(&me->screenTimeEvt, BSP_TICKS_PER_SEC/2U, 0U);
QTimeEvt_disarm(&me->screenTimeEvt);
BSP_clearFB();
BSP_updateScreen();
/* clear the screen */
BSP_clearFB();
BSP_updateScreen();
QF_stop(); /* stop QF and cleanup */
Ship Active Object
vertical position of the ship in the 8s2 fixed-point notation.
(void)e; /* avoid the compiler warning 'usused parameter' */
QActive_subscribe(&me->super, TIME_TICK_SIG);
QActive_subscribe(&me->super, PLAYER_TRIGGER_SIG);
/* local signals... */
//QS_SIG_DICTIONARY(PLAYER_SHIP_MOVE_SIG, me);
QS_SIG_DICTIONARY(TAKE_OFF_SIG, me);
QS_SIG_DICTIONARY(HIT_WALL_SIG, me);
QS_SIG_DICTIONARY(HIT_MINE_SIG, me);
QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, me);
ScoreEvt *sev;
me->score = 0U; /* reset the score */
sev = Q_NEW(ScoreEvt, SCORE_SIG);
sev->score = me->score;
QACTIVE_POST(AO_Tunnel, (QEvt *)sev, me);
/* lauch the ship from the initial position */
me->x = GAME_SHIP_X;
me->y = (GAME_SHIP_Y << 2);
ObjectImageEvt *oie;
if (BSP_isThrottle()) {
if (me->y > 0) {
me->y -= 1U;
}
}
else {
if (me->y < (GAME_TUNNEL_HEIGHT << 2)) {
me->y += 1U;
}
}
/* tell the Tunnel to draw the Ship and test for hits */
oie = Q_NEW(ObjectImageEvt, SHIP_IMG_SIG);
oie->x = me->x;
oie->y = (uint8_t)(me->y >> 2);
oie->bmp = SHIP_BMP;
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);
++me->score; /* increment the score for surviving another tick */
if ((me->score % 10U) == 0U) { /* is the score "round"? */
ScoreEvt *sev = Q_NEW(ScoreEvt, SCORE_SIG);
sev->score = me->score;
QACTIVE_POST(AO_Tunnel, (QEvt *)sev, me);
}
ObjectPosEvt *ope = Q_NEW(ObjectPosEvt, MISSILE_FIRE_SIG);
ope->x = me->x;
ope->y = (me->y >> 2) + SHIP_HEIGHT - 1U;
QACTIVE_POST(AO_Missile, (QEvt *)ope, me);
me->score += Q_EVT_CAST(ScoreEvt)->score;
/* the score will be sent to the Tunnel by the next TIME_TICK */
me->exp_ctr = 0U;
me->exp_ctr < 15U
ObjectImageEvt *oie;
++me->exp_ctr;
/* tell the Tunnel to draw the current stage of Explosion */
oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG);
oie->bmp = EXPLOSION0_BMP + (me->exp_ctr >> 2);
oie->x = me->x; /* x of explosion */
oie->y = (int8_t)((int)(me->y >> 2) - 4U + SHIP_HEIGHT);
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);
ScoreEvt *gameOver = Q_NEW(ScoreEvt, GAME_OVER_SIG);
gameOver->score = me->score;
QACTIVE_POST(AO_Tunnel, (QEvt *)gameOver, me);
Missile Active Object
(void)e;
QActive_subscribe(&me->super, TIME_TICK_SIG);
/* local signals */
QS_SIG_DICTIONARY(MISSILE_FIRE_SIG, me);
QS_SIG_DICTIONARY(HIT_WALL_SIG, me);
QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, me);
me->x = Q_EVT_CAST(ObjectPosEvt)->x;
me->y = Q_EVT_CAST(ObjectPosEvt)->y;
me->x + GAME_MISSILE_SPEED_X < GAME_TUNNEL_WIDTH
ObjectImageEvt *oie;
me->x += GAME_MISSILE_SPEED_X;
/*tell the Tunnel to draw the Missile and test for wall hits*/
oie = Q_NEW(ObjectImageEvt, MISSILE_IMG_SIG);
oie->x = me->x;
oie->y = me->y;
oie->bmp = MISSILE_BMP;
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);
QACTIVE_POST(AO_Ship, e, me);
me->exp_ctr = 0U;
(me->x >= GAME_SPEED_X) && (me->exp_ctr < 15U)
ObjectImageEvt *oie;
++me->exp_ctr; /* advance the explosion counter */
me->x -= GAME_SPEED_X; /* move the explosion by one step */
/* tell the Tunnel to render the current stage of Explosion */
oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG);
oie->x = me->x + 3U; /* x-pos of explosion */
oie->y = (int8_t)((int)me->y - 4U); /* y-pos */
oie->bmp = EXPLOSION0_BMP + (me->exp_ctr >> 2);
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);
The Mine1 orthogonal component
static uint8_t dict_sent;
if (!dict_sent) {
QS_OBJ_DICTIONARY(&l_mine1[0]); /* obj. dictionaries for Mine1 pool */
QS_OBJ_DICTIONARY(&l_mine1[1]);
QS_OBJ_DICTIONARY(&l_mine1[2]);
QS_OBJ_DICTIONARY(&l_mine1[3]);
QS_OBJ_DICTIONARY(&l_mine1[4]);
QS_FUN_DICTIONARY(&Mine1_initial);/*fun. dictionaries for Mine1 HSM */
QS_FUN_DICTIONARY(&Mine1_unused);
QS_FUN_DICTIONARY(&Mine1_used);
QS_FUN_DICTIONARY(&Mine1_planted);
QS_FUN_DICTIONARY(&Mine1_exploding);
dict_sent = 1U;
}
/* 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; /* avoid the "unreferenced parameter" warning */
me->x = Q_EVT_CAST(ObjectPosEvt)->x;
me->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);
QACTIVE_POST(AO_Tunnel, (QEvt *)mev, me);
me->x >= GAME_SPEED_X
ObjectImageEvt *oie;
me->x -= GAME_SPEED_X; /* move the mine 1 step */
/* tell the Tunnel to draw the Mine */
oie = Q_NEW(ObjectImageEvt, MINE_IMG_SIG);
oie->x = me->x;
oie->y = me->y;
oie->bmp = MINE1_BMP;
QACTIVE_POST(AO_Tunnel, (QEvt *)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->x, me->y, bmp, x, y)
static MineEvt const mine1_hit = {
{ HIT_MINE_SIG, 0U, 0U }, /* the QEvt base instance */
1U /* type of the mine (1 for Mine type-1) */
};
QACTIVE_POST(AO_Ship, (QEvt *)&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->x, me->y, bmp, x, y)
static ScoreEvt const mine1_destroyed = {
{ DESTROYED_MINE_SIG, 0U, 0U }, /* the QEvt base instance */
25U /* score for destroying Mine type-1 */
};
QACTIVE_POST(AO_Missile, (QEvt *)&mine1_destroyed, me);
me->exp_ctr = 0U;
(me->x >= GAME_SPEED_X) && (me->exp_ctr < 15)
ObjectImageEvt *oie;
++me->exp_ctr; /* advance the explosion counter */
me->x -= GAME_SPEED_X; /* move explosion by 1 step */
/* tell the Game to render the current stage of Explosion */
oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG);
oie->x = me->x + 1U; /* x of explosion */
oie->y = (int8_t)((int)me->y - 4 + 2); /* y of explosion */
oie->bmp = EXPLOSION0_BMP + (me->exp_ctr >> 2);
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);
The Mine2 orthogonal component
static uint8_t dict_sent;
if (!dict_sent) {
/* 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 HSM... */
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);
dict_sent = 1U;
}
/* 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; /* avoid the "unreferenced parameter" warning */
me->x = Q_EVT_CAST(ObjectPosEvt)->x;
me->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);
QACTIVE_POST(AO_Tunnel, (QEvt *)mev, me);
me->x >= GAME_SPEED_X
ObjectImageEvt *oie;
me->x -= GAME_SPEED_X; /* move the mine 1 step */
/* tell the Tunnel to draw the Mine */
oie = Q_NEW(ObjectImageEvt, MINE_IMG_SIG);
oie->x = me->x;
oie->y = me->y;
oie->bmp = MINE2_BMP;
QACTIVE_POST(AO_Tunnel, (QEvt *)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->x, me->y, bmp, x, y)
static MineEvt const mine1_hit = {
{ HIT_MINE_SIG, 0U, 0U }, /* the QEvt base instance */
2U /* type of the mine (2 for Mine type-2) */
};
QACTIVE_POST(AO_Ship, (QEvt *)&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(MINE2_MISSILE_BMP, me->x, me->y, bmp, x, y)
/* NOTE: Mine type-2 is nastier than Mine type-1.
* The type-2 mine can hit the Ship with any of its
* "tentacles". However, it can be destroyed by the
* Missile only by hitting its center, defined as
* a smaller bitmap MINE2_MISSILE_BMP.
*/
static ScoreEvt const mine2_destroyed = {
{ DESTROYED_MINE_SIG, 0U, 0U }, /* the QEvt base instance */
45U /* score for destroying Mine type-2 */
};
QACTIVE_POST(AO_Missile, (QEvt *)&mine2_destroyed, me);
me->exp_ctr = 0U;
(me->x >= GAME_SPEED_X) && (me->exp_ctr < 15U)
ObjectImageEvt *oie;
++me->exp_ctr; /* advance the explosion counter */
me->x -= GAME_SPEED_X; /* move explosion by 1 step */
/* tell the Game to render the current stage of Explosion */
oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG);
oie->x = me->x + 1U; /* x of explosion */
oie->y = (int8_t)((int)me->y - 4 + 2); /* y of explosion */
oie->bmp = EXPLOSION0_BMP + (me->exp_ctr >> 2);
QACTIVE_POST(AO_Tunnel, (QEvt *)oie, me);
/* opaque AO pointer */
= &l_tunnel.super;
/* opaque AO pointer */
= &l_ship.super;
/* opaque AO pointer */
= &l_missile.super;
uint8_t n;
Tunnel *me = &l_tunnel;
QActive_ctor(&me->super, Q_STATE_CAST(&Tunnel_initial));
QTimeEvt_ctorX(&me->blinkTimeEvt, &me->super, BLINK_TIMEOUT_SIG, 0U);
QTimeEvt_ctorX(&me->screenTimeEvt, &me->super, SCREEN_TIMEOUT_SIG, 0U);
for (n = 0; n < GAME_MINES_MAX; ++n) {
me->mine1_pool[n] = Mine1_ctor(n); /* instantiate Mine1 in the pool */
me->mine2_pool[n] = Mine2_ctor(n); /* instantiate Mine2 in the pool */
me->mines[n] = (QMsm *)0; /* mine 'n' is unused */
}
me->last_mine_x = 0; /* the last mine at the right edge of the tunnel */
me->last_mine_y = 0;
Ship *me = &l_ship;
QActive_ctor(&me->super, Q_STATE_CAST(&Ship_initial));
me->x = GAME_SHIP_X;
me->y = (GAME_SHIP_Y << 2);
Missile *me = &l_missile;
QActive_ctor(&me->super, Q_STATE_CAST(&Missile_initial));
Mine1 *me;
Q_REQUIRE(id < GAME_MINES_MAX);
me = &l_mine1[id];
/* superclass' ctor */
QHsm_ctor(&me->super, Q_STATE_CAST(&Mine1_initial));
return (QHsm *)me;
Mine2 *me;
Q_REQUIRE(id < GAME_MINES_MAX);
me = &l_mine2[id];
/* superclass' ctor */
QHsm_ctor(&me->super, Q_STATE_CAST(&Mine2_initial));
return (QHsm *)me;
#ifndef GAME_H
#define GAME_H
enum GameSignals { /* signals used in the game */
TIME_TICK_SIG = 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_UP_SIG, /* posted by Player (ISR) to Ship to move it up */
PLAYER_SHIP_DOWN_SIG, /* posted by Player (ISR) to Ship to let if fall */
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 adjust game level based on score */
MAX_SIG /* the last signal (keep always last) */
};
$declare${Events::ObjectPosEvt}
$declare${Events::ObjectImageEvt}
$declare${Events::MineEvt}
$declare${Events::ScoreEvt}
#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
};
/* active objects' "constructors" */
$declare${AOs::Tunnel_ctor}
$declare${AOs::Ship_ctor}
$declare${AOs::Missile_ctor}
/* instantiation of the Mines orthogonal components */
$declare${AOs::Mine1_ctor}
$declare${AOs::Mine2_ctor}
/* opaque pointers to active objects in the application */
$declare${AOs::AO_Tunnel}
$declare${AOs::AO_Ship}
$declare${AOs::AO_Missile}
#endif /* GAME_H */
#include "qpc.h"
#include "bsp.h"
#include "game.h"
/* Q_DEFINE_THIS_FILE */
/* local objects -----------------------------------------------------------*/
$declare${AOs::Missile}
static Missile l_missile; /* the sole instance of the Missile active object */
/* Public-scope objects ----------------------------------------------------*/
$define${AOs::AO_Missile}
/* Active object definition ------------------------------------------------*/
$define${AOs::Missile_ctor}
$define${AOs::Missile}
#include "qpc.h"
#include "bsp.h"
#include "game.h"
/* Q_DEFINE_THIS_FILE */
#define SHIP_WIDTH 5
#define SHIP_HEIGHT 3
/* encapsulated delcaration of the Ship active object ----------------------*/
$declare${AOs::Ship}
/* local objects -----------------------------------------------------------*/
static Ship l_ship; /* the sole instance of the Ship active object */
/* Public-scope objects ----------------------------------------------------*/
$define${AOs::AO_Ship}
/* Active object definition ------------------------------------------------*/
$define${AOs::Ship_ctor}
$define${AOs::Ship}
#include "qpc.h"
#include "bsp.h"
#include "game.h"
Q_DEFINE_THIS_FILE
/* local objects -----------------------------------------------------------*/
$declare${AOs::Tunnel}
static Tunnel l_tunnel; /* the sole instance of the Tunnel active object */
/* Public-scope objects ----------------------------------------------------*/
$define${AOs::AO_Tunnel}
/* Active object definition ================================================*/
$define${AOs::Tunnel_ctor}
$define${AOs::Tunnel}
#include "qpc.h"
#include "bsp.h"
#include "game.h"
Q_DEFINE_THIS_FILE
/* encapsulated delcaration of the Mine1 HSM -------------------------------*/
$declare(AOs::Mine1)
/* local objects -----------------------------------------------------------*/
static Mine1 l_mine1[GAME_MINES_MAX]; /* a pool of type-1 mines */
/* helper macro to provide the ID of this mine */
#define MINE_ID(me_) ((uint8_t)((me_) - l_mine1))
/* Mine1 class definition --------------------------------------------------*/
$define(AOs::Mine1_ctor)
$define(AOs::Mine1)
#include "qpc.h"
#include "bsp.h"
#include "game.h"
Q_DEFINE_THIS_FILE
/* encapsulated delcaration of the Mine2 HSM -------------------------------*/
$declare(AOs::Mine2)
/* local objects -----------------------------------------------------------*/
static Mine2 l_mine2[GAME_MINES_MAX]; /* a pool of type-2 mines */
/* helper macro to provide the ID of this mine */
#define MINE_ID(me_) ((uint8_t)((me_) - l_mine2))
/* Mine2 class definition --------------------------------------------------*/
$define(AOs::Mine2_ctor)
$define(AOs::Mine2)