"Fly 'n' Shoot" game model from Chapters 1 & 9 of PSiCC2
NOTE: Requries QP6.
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.m_blinkTimeEvt);
QS_OBJ_DICTIONARY(&l_tunnel.m_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->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);
// 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);
(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);
// local signals...
QS_SIG_DICTIONARY(MISSILE_FIRE_SIG, me);
QS_SIG_DICTIONARY(HIT_WALL_SIG, me);
QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, me);
(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);
// opaque pointer
= &l_tunnel;
// opaque pointer
= &l_ship;
// opaque pointer
= &l_missile;
#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
} // namespace GAME
// Public-scope objects ------------------------------------------------------
$define${AOs::AO_Missile}
// 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
} // namespace GAME
// Public-scope objects ------------------------------------------------------
$define${AOs::AO_Ship}
// 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
} // namespace GAME
// Public-scope objects ------------------------------------------------------
$define${AOs::AO_Tunnel}
// 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)