Quantum Leaps 9d72aa81de 5.2.0
2013-12-30 17:41:15 -05:00

1638 lines
59 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<model version="3.0.0">
<documentation>&quot;Fly 'n' Shoot&quot; game model from Chapters 1 &amp; 9 of PSiCC2</documentation>
<framework name="qpcpp"/>
<package name="Events" stereotype="0x01" namespace="GAME::">
<class name="ObjectPosEvt" superclass="qpcpp::QEvt">
<attribute name="x" type="uint8_t" visibility="0x00" properties="0x00"/>
<attribute name="y" type="uint8_t" visibility="0x00" properties="0x00"/>
</class>
<class name="ObjectImageEvt" superclass="qpcpp::QEvt">
<attribute name="x" type="uint8_t" visibility="0x00" properties="0x00"/>
<attribute name="y" type="int8_t" visibility="0x00" properties="0x00"/>
<attribute name="bmp" type="uint8_t" visibility="0x00" properties="0x00"/>
</class>
<class name="MineEvt" superclass="qpcpp::QEvt">
<attribute name="id" type="uint8_t" visibility="0x00" properties="0x00"/>
<operation name="MineEvt" type="" visibility="0x00" properties="0x02">
<documentation>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</documentation>
<parameter name="sig_p" type="QP::QSignal"/>
<parameter name="id_p" type="uint8_t"/>
<code>sig = sig_p;
poolId_ = 0U;
id = id_p;</code>
</operation>
</class>
<class name="ScoreEvt" superclass="qpcpp::QEvt">
<attribute name="score" type="uint16_t" visibility="0x00" properties="0x00"/>
<operation name="ScoreEvt" type="" visibility="0x00" properties="0x02">
<documentation>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</documentation>
<parameter name="sig_p" type="QP::QSignal"/>
<parameter name="score_p" type="uint16_t"/>
<code>sig = sig_p;
poolId_ = 0U;
score = score_p;</code>
</operation>
</class>
</package>
<package name="AOs" stereotype="0x02" namespace="GAME::">
<class name="Tunnel" superclass="qpcpp::QMActive">
<documentation>Tunnel Active Object</documentation>
<attribute name="m_blinkTimeEvt" type="QP::QTimeEvt" visibility="0x02" properties="0x00"/>
<attribute name="m_screenTimeEvt" type="QP::QTimeEvt" visibility="0x02" properties="0x00"/>
<attribute name="m_mines[GAME_MINES_MAX]" type="QP::QMsm *" visibility="0x02" properties="0x00"/>
<attribute name="m_mine1_pool[GAME_MINES_MAX]" type="QP::QMsm *" visibility="0x02" properties="0x00"/>
<attribute name="m_mine2_pool[GAME_MINES_MAX]" type="QP::QMsm *" visibility="0x02" properties="0x00"/>
<attribute name="m_blink_ctr" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_last_mine_x" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_last_mine_y" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_wall_thickness_top" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_wall_thickness_bottom" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_minimal_gap" type="uint8_t" visibility="0x02" properties="0x00"/>
<operation name="Tunnel" type="" visibility="0x00" properties="0x00">
<code> : QMActive(Q_STATE_CAST(&amp;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 &lt; 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&lt;QMsm *&gt;(0); // mine 'n' is unused
}</code>
</operation>
<operation name="advance" type="void" visibility="0x02" properties="0x00">
<code>uint32_t bmp1; // bimap representing 1 column of the image
uint32_t rnd = (random() &amp; 0xFFU);
// reduce the top wall thickness 18.75% of the time
if ((rnd &lt; 48U) &amp;&amp; (m_wall_thickness_top &gt; 0U)) {
--m_wall_thickness_top;
}
// reduce the bottom wall thickness 18.75% of the time
if ((rnd &gt; 208U) &amp;&amp; (m_wall_thickness_bottom &gt; 0U)) {
--m_wall_thickness_bottom;
}
rnd = (random() &amp; 0xFFU);
// grow the top wall thickness 18.75% of the time
if ((rnd &lt; 48U)
&amp;&amp; ((GAME_SCREEN_HEIGHT
- m_wall_thickness_top
- m_wall_thickness_bottom) &gt; m_minimal_gap)
&amp;&amp; ((m_last_mine_x &lt; (GAME_SCREEN_WIDTH - 5U))
|| (m_last_mine_y &gt; (m_wall_thickness_top + 1U))))
{
++m_wall_thickness_top;
}
// grow the bottom wall thickness 18.75% of the time
if ((rnd &gt; 208U)
&amp;&amp; ((GAME_SCREEN_HEIGHT
- m_wall_thickness_top
- m_wall_thickness_bottom) &gt; m_minimal_gap)
&amp;&amp; ((m_last_mine_x &lt; (GAME_SCREEN_WIDTH - 5U))
|| (m_last_mine_y + 1U
&lt; (GAME_SCREEN_HEIGHT - m_wall_thickness_bottom))))
{
++m_wall_thickness_bottom;
}
// advance the Tunnel by 1 game step to the left
memmove(l_walls, l_walls + GAME_SPEED_X,
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U) - GAME_SPEED_X);
bmp1 = (~(~0U &lt;&lt; m_wall_thickness_top))
| (~0U &lt;&lt; (GAME_SCREEN_HEIGHT
- m_wall_thickness_bottom));
l_walls[GAME_SCREEN_WIDTH - 1] = (uint8_t)bmp1;
l_walls[GAME_SCREEN_WIDTH + GAME_SCREEN_WIDTH - 1] = (uint8_t)(bmp1 &gt;&gt; 8);
// copy the Tunnel layer to the main frame buffer
memcpy(l_frame, l_walls, (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));</code>
</operation>
<operation name="plantMine" type="void" visibility="0x02" properties="0x00">
<code>uint32_t rnd = (random() &amp; 0xFFU);
if (m_last_mine_x &gt; 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 &lt; GAME_SCREEN_WIDTH)
&amp;&amp; (rnd &lt; 8U)) // place the mines only 5% of the time
{
uint8_t n;
for (n = 0U; n &lt; Q_DIM(m_mines); ++n) { // look for disabled mines
if (m_mines[n] == (QMsm *)0) {
break;
}
}
if (n &lt; Q_DIM(m_mines)) { // a disabled Mine found?
rnd = (random() &amp; 0xFFFFU);
if ((rnd &amp; 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 in the last column of the tunnel
m_last_mine_x = GAME_SCREEN_WIDTH;
// choose a random y-position for the Mine in the Tunnel
rnd %= (GAME_SCREEN_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]-&gt;dispatch(&amp;ope); // direct dispatch
}
}</code>
</operation>
<operation name="addImageAt" type="void" visibility="0x02" properties="0x00">
<parameter name="bmp" type="uint8_t"/>
<parameter name="x_pos" type="uint8_t"/>
<parameter name="y_pos" type="int8_t"/>
<code>Q_REQUIRE(bmp &lt; Q_DIM(l_bitmap));
uint8_t w = l_bitmap[bmp].width;
if (w &gt; GAME_SCREEN_WIDTH - x_pos) {
w = GAME_SCREEN_WIDTH - x_pos;
}
for (uint8_t x = 0U; x &lt; w; ++x) {
uint32_t bmp1;
if (y_pos &gt;= 0) {
bmp1 = (l_bitmap[bmp].bits[x] &lt;&lt; (uint8_t)y_pos);
}
else {
bmp1 = (l_bitmap[bmp].bits[x] &gt;&gt; (uint8_t)(-y_pos));
}
l_frame[x_pos + x] |= (uint8_t)bmp1;
l_frame[x_pos + x + GAME_SCREEN_WIDTH] |= (uint8_t)(bmp1 &gt;&gt; 8);
}</code>
</operation>
<operation name="dispatchToAllMines" type="void" visibility="0x02" properties="0x00">
<parameter name="e" type="QP::QEvt const *"/>
<code>for (uint8_t n = 0U; n &lt; GAME_MINES_MAX; ++n) {
if (m_mines[n] != static_cast&lt;QMsm *&gt;(0)) { // is the mine used?
m_mines[n]-&gt;dispatch(e);
}
}</code>
</operation>
<operation name="isWallHit" type="bool" visibility="0x02" properties="0x00">
<parameter name="bmp" type="uint8_t"/>
<parameter name="x_pos" type="uint8_t"/>
<parameter name="y_pos" type="uint8_t"/>
<code>Q_REQUIRE(bmp &lt; Q_DIM(l_bitmap));
uint8_t w = l_bitmap[bmp].width;
if (w &gt; GAME_SCREEN_WIDTH - x_pos) {
w = GAME_SCREEN_WIDTH - x_pos;
}
for (uint8_t x = 0U; x &lt; w; ++x) {
uint32_t bmp1 = ((uint32_t)l_bitmap[bmp].bits[x] &lt;&lt; y_pos);
if (((l_walls[x_pos + x] &amp; (uint8_t)bmp1) != 0U)
|| ((l_walls[x_pos + x + GAME_SCREEN_WIDTH]
&amp; (uint8_t)(bmp1 &gt;&gt; 8)) != 0))
{
return true;
}
}
return false;</code>
</operation>
<statechart>
<initial target="../1/2">
<action>for (uint8_t n = 0; n &lt; GAME_MINES_MAX; ++n) {
me-&gt;m_mine1_pool[n]-&gt;init(); // take the initial tran. for Mine1
me-&gt;m_mine2_pool[n]-&gt;init(); // take the initial tran. for Mine2
}
randomSeed(1234); // seed the pseudo-random generator
me-&gt;subscribe(TIME_TICK_SIG);
me-&gt;subscribe(PLAYER_TRIGGER_SIG);
me-&gt;subscribe(PLAYER_QUIT_SIG);
QS_OBJ_DICTIONARY(&amp;l_tunnel); // object dictionary for Tunnel object
QS_OBJ_DICTIONARY(&amp;l_tunnel.m_blinkTimeEvt);
QS_OBJ_DICTIONARY(&amp;l_tunnel.m_screenTimeEvt);
QS_FUN_DICTIONARY(&amp;Tunnel::initial); // fun. dictionaries for Tunnel HSM
QS_FUN_DICTIONARY(&amp;Tunnel::final);
QS_FUN_DICTIONARY(&amp;Tunnel::active);
QS_FUN_DICTIONARY(&amp;Tunnel::playing);
QS_FUN_DICTIONARY(&amp;Tunnel::demo);
QS_FUN_DICTIONARY(&amp;Tunnel::game_over);
QS_FUN_DICTIONARY(&amp;Tunnel::screen_saver);
QS_FUN_DICTIONARY(&amp;Tunnel::screen_saver_hide);
QS_FUN_DICTIONARY(&amp;Tunnel::screen_saver_show);
QS_SIG_DICTIONARY(BLINK_TIMEOUT_SIG, &amp;l_tunnel); // local signals
QS_SIG_DICTIONARY(SCREEN_TIMEOUT_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(SHIP_IMG_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(MISSILE_IMG_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(MINE_IMG_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(MINE_DISABLED_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(EXPLOSION_SIG, &amp;l_tunnel);
QS_SIG_DICTIONARY(SCORE_SIG, &amp;l_tunnel);</action>
<initial_glyph conn="3,2,5,1,26,15,-3">
<action box="1,-2,11,2"/>
</initial_glyph>
</initial>
<state name="active">
<tran trig="MINE_DISABLED">
<action>Q_ASSERT((Q_EVT_CAST(MineEvt)-&gt;id &lt; GAME_MINES_MAX)
&amp;&amp; (me-&gt;m_mines[Q_EVT_CAST(MineEvt)-&gt;id] != static_cast&lt;QMsm *&gt;(0)));
me-&gt;m_mines[Q_EVT_CAST(MineEvt)-&gt;id] = static_cast&lt;QMsm *&gt;(0);</action>
<tran_glyph conn="2,9,3,-1,14">
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<tran trig="PLAYER_QUIT" target="../../2">
<tran_glyph conn="2,12,3,1,62,76,-38">
<action box="0,-2,11,2"/>
</tran_glyph>
</tran>
<state name="show_logo">
<entry>me-&gt;m_blinkTimeEvt.armX(BSP_TICKS_PER_SEC/2U,
BSP_TICKS_PER_SEC/2U); // every 1/2 sec
me-&gt;m_screenTimeEvt.armX(BSP_TICKS_PER_SEC*5U, 0U); // in 5 sec
me-&gt;m_blink_ctr = 0U;
BSP_drawNString(0U, 0U, &quot; Quantum LeAps &quot;);
BSP_drawNString(0U, 1U, &quot;state-machine.co&quot;);</entry>
<exit>me-&gt;m_blinkTimeEvt.disarm();
me-&gt;m_screenTimeEvt.disarm();</exit>
<tran trig="SCREEN_TIMEOUT" target="../../3">
<tran_glyph conn="4,26,3,1,24,7,-2">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<tran trig="BLINK_TIMEOUT">
<action>me-&gt;m_blink_ctr ^= 1U; // toggle the blink couner</action>
<choice>
<guard>me-&gt;m_blink_ctr == 0U</guard>
<action>BSP_drawNString(6U*9U, 0U, &quot; LeAps&quot;);
BSP_drawNString(0U, 1U, &quot;state-machine.co&quot;);</action>
<choice_glyph conn="18,23,4,-1,-3,7">
<action box="1,-3,15,2"/>
</choice_glyph>
</choice>
<choice>
<guard>else</guard>
<action>BSP_drawNString(6U*9U, 0U, &quot;LeaPs &quot;);
BSP_drawNString(0U, 1U, &quot;tate-machine.com&quot;);</action>
<choice_glyph conn="18,23,5,-1,7">
<action box="1,0,6,2"/>
</choice_glyph>
</choice>
<tran_glyph conn="4,23,3,-1,14">
<action box="0,-2,12,2"/>
</tran_glyph>
</tran>
<state_glyph node="4,15,22,14">
<entry box="1,2,5,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
<state name="demo">
<entry>me-&gt;m_last_mine_x = 0U; // last mine at right edge of the tunnel
me-&gt;m_last_mine_y = 0U;
// set the tunnel properties...
me-&gt;m_wall_thickness_top = 0U;
me-&gt;m_wall_thickness_bottom = 0U;
me-&gt;m_minimal_gap = GAME_SCREEN_HEIGHT - 3U;
// erase the tunnel walls
memset(l_walls, (uint8_t)0,
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
me-&gt;m_blinkTimeEvt.armX(BSP_TICKS_PER_SEC/2U,
BSP_TICKS_PER_SEC/2U); // every 1/2 sec
me-&gt;m_screenTimeEvt.armX(BSP_TICKS_PER_SEC*20U, 0U); // in 20 sec
me-&gt;m_blink_ctr = 0U; // init the blink counter</entry>
<exit>me-&gt;m_blinkTimeEvt.disarm();
me-&gt;m_screenTimeEvt.disarm();</exit>
<tran trig="BLINK_TIMEOUT">
<action>me-&gt;m_blink_ctr ^= 1U; /* toggle the blink cunter */</action>
<tran_glyph conn="4,43,3,-1,14">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<tran trig="SCREEN_TIMEOUT" target="../../6">
<tran_glyph conn="4,46,3,3,28">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<tran trig="TIME_TICK">
<action>me-&gt;advance();
if (me-&gt;m_blink_ctr != 0U) {
// add the text bitmap into the frame buffer
me-&gt;addImageAt(PRESS_BUTTON_BMP,
(GAME_SCREEN_WIDTH - 55U)/2U,
(GAME_SCREEN_HEIGHT - 8U)/2U);
}
BSP_drawBitmap(l_frame);</action>
<tran_glyph conn="4,40,3,-1,14">
<action box="0,-2,12,2"/>
</tran_glyph>
</tran>
<tran trig="PLAYER_TRIGGER" target="../../4">
<tran_glyph conn="4,49,3,1,24,6,-2">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<state_glyph node="4,31,22,20">
<entry box="1,2,6,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
<state name="playing">
<entry>static QP::QEvt const takeoff = QEVT_INITIALIZER(TAKE_OFF_SIG);
me-&gt;m_minimal_gap = GAME_SCREEN_HEIGHT - 3U;
// erase the walls
memset(l_walls, (uint8_t)0,
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
AO_Ship-&gt;POST(&amp;takeoff, me); // post the TAKEOFF sig</entry>
<exit>QP::QEvt recycle;
recycle.sig = MINE_RECYCLE_SIG;
me-&gt;dispatchToAllMines(&amp;recycle); // recycle all Mines</exit>
<tran trig="TIME_TICK">
<action>// render this frame on the display
BSP_drawBitmap(l_frame);
me-&gt;advance();
me-&gt;plantMine();
me-&gt;dispatchToAllMines(e);</action>
<tran_glyph conn="4,62,3,-1,14">
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<tran trig="SHIP_IMG">
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)-&gt;x;
int8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;
// did the Ship/Missile hit the tunnel wall?
if (me-&gt;isWallHit(bmp, x, y)) {
static QP::QEvt const hit = QEVT_INITIALIZER(HIT_WALL_SIG);
AO_Ship-&gt;POST(&amp;hit, me);
}
me-&gt;addImageAt(bmp, x, y);
me-&gt;dispatchToAllMines(e); // let Mines check for hits</action>
<tran_glyph conn="4,65,3,-1,14">
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<tran trig="MISSILE_IMG">
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)-&gt;x;
int8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;
// did the Ship/Missile hit the tunnel wall?
if (me-&gt;isWallHit(bmp, x, y)) {
static QP::QEvt const hit = QEVT_INITIALIZER(HIT_WALL_SIG);
AO_Missile-&gt;POST(&amp;hit, me);
}
me-&gt;addImageAt(bmp, x, y);
me-&gt;dispatchToAllMines(e); // let Mines check for hits</action>
<tran_glyph conn="4,68,3,-1,14">
<action box="0,-2,12,2"/>
</tran_glyph>
</tran>
<tran trig="MINE_IMG">
<action>me-&gt;addImageAt(Q_EVT_CAST(ObjectImageEvt)-&gt;bmp,
Q_EVT_CAST(ObjectImageEvt)-&gt;x,
Q_EVT_CAST(ObjectImageEvt)-&gt;y);</action>
<tran_glyph conn="4,71,3,-1,14">
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<tran trig="EXPLOSION">
<action>me-&gt;addImageAt(Q_EVT_CAST(ObjectImageEvt)-&gt;bmp,
Q_EVT_CAST(ObjectImageEvt)-&gt;x,
Q_EVT_CAST(ObjectImageEvt)-&gt;y);</action>
<tran_glyph conn="4,74,3,-1,14">
<action box="0,-2,11,2"/>
</tran_glyph>
</tran>
<tran trig="SCORE">
<action>BSP_updateScore(Q_EVT_CAST(ScoreEvt)-&gt;score);
// increase difficulty of the game:
// the tunnel gets narrower as the score goes up
//
me-&gt;m_minimal_gap = (uint8_t)(GAME_SCREEN_HEIGHT - 3U
- Q_EVT_CAST(ScoreEvt)-&gt;score/2000U);</action>
<tran_glyph conn="4,77,3,-1,14">
<action box="0,-2,6,2"/>
</tran_glyph>
</tran>
<tran trig="GAME_OVER" target="../../5">
<action>uint16_t score = Q_EVT_CAST(ScoreEvt)-&gt;score;
BSP_updateScore(score);
// clear the screen
memset(l_frame, (uint8_t)0,
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
BSP_drawBitmap(l_frame);
// Output the final score to the screen
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*10U)/2U, 1U, &quot;Score:&quot;);
char str[5];
str[4] = '\0'; // zero-terminate the string
str[3] = '0' + (score % 10U); score /= 10U;
str[2] = '0' + (score % 10U); score /= 10U;
str[1] = '0' + (score % 10U); score /= 10U;
str[0] = '0' + (score % 10U);
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*10U)/2U + 6U*6U, 1U, str);</action>
<tran_glyph conn="4,80,3,3,26,-10,2">
<action box="0,-2,10,2"/>
</tran_glyph>
</tran>
<state_glyph node="4,53,22,29">
<entry box="1,2,6,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
<state name="game_over">
<entry>me-&gt;m_blinkTimeEvt.armX(BSP_TICKS_PER_SEC/2U,
BSP_TICKS_PER_SEC/2U); // every 1/2 sec
me-&gt;m_screenTimeEvt.armX(BSP_TICKS_PER_SEC*5U, 0U); // in 5 se
me-&gt;m_blink_ctr = 0U;
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*9U)/2U, 0U, &quot;Game Over&quot;);</entry>
<exit>me-&gt;m_blinkTimeEvt.disarm();
me-&gt;m_screenTimeEvt.disarm();
BSP_updateScore(0U); // update the score on the display</exit>
<tran trig="BLINK_TIMEOUT">
<action>me-&gt;m_blink_ctr ^= 1U; // toggle the blink couner
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*9U)/2U, 0U,
((me-&gt;m_blink_ctr == 0U)
? &quot;Game Over&quot;
: &quot; &quot;));</action>
<tran_glyph conn="32,80,3,-1,15">
<action box="0,-2,12,2"/>
</tran_glyph>
</tran>
<tran trig="SCREEN_TIMEOUT" target="../../3">
<tran_glyph conn="32,77,3,1,28,-11,-30,-18,-4">
<action box="0,-2,14,2"/>
</tran_glyph>
</tran>
<state_glyph node="32,68,26,14">
<entry box="1,2,6,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
<state name="screen_saver">
<initial target="../2">
<initial_glyph conn="34,35,5,1,20,7,-2">
<action box="1,-2,6,2"/>
</initial_glyph>
</initial>
<tran trig="PLAYER_TRIGGER" target="../../3">
<tran_glyph conn="32,38,3,1,28,-8,-30,5,-4">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<state name="screen_saver_hide">
<entry>BSP_displayOff(); // power down the display
me-&gt;m_screenTimeEvt.armX(BSP_TICKS_PER_SEC*3U, 0U); // in 3 sec</entry>
<exit>me-&gt;m_screenTimeEvt.disarm();
BSP_displayOn(); // power up the display</exit>
<tran trig="SCREEN_TIMEOUT" target="../../3">
<tran_glyph conn="34,48,3,1,20,6,-2">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<state_glyph node="34,40,18,10">
<entry box="1,2,5,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
<state name="screen_saver_show">
<entry>uint32_t rnd = random();
// clear the screen frame buffer
memset(l_frame, (uint8_t)0,
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
me-&gt;addImageAt(PRESS_BUTTON_BMP,
(uint8_t)(rnd % (GAME_SCREEN_WIDTH - 55U)),
(int8_t) (rnd % (GAME_SCREEN_HEIGHT - 8U)));
BSP_drawBitmap(l_frame);
me-&gt;m_screenTimeEvt.armX(BSP_TICKS_PER_SEC/3U, 0U); // in 1/3 sec</entry>
<exit>me-&gt;m_screenTimeEvt.disarm();
// clear the screen frame buffer
memset(l_frame, (uint8_t)0,
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
BSP_drawBitmap(l_frame);</exit>
<tran trig="SCREEN_TIMEOUT" target="../../2">
<tran_glyph conn="34,60,3,1,22,-15,-4">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<state_glyph node="34,52,18,10">
<entry box="1,2,6,2"/>
<exit box="1,4,5,2"/>
</state_glyph>
</state>
<state_glyph node="32,31,26,33"/>
</state>
<state_glyph node="2,4,60,80"/>
</state>
<state name="final">
<entry>// clear the screen
memset(l_frame, (uint8_t)0,
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
BSP_drawBitmap(l_frame);
QP::QF::stop(); /* stop QF and cleanup */</entry>
<state_glyph node="2,86,24,6">
<entry box="1,2,6,2"/>
</state_glyph>
</state>
<state_diagram size="68,94"/>
</statechart>
</class>
<class name="Ship" superclass="qpcpp::QMActive">
<documentation>Ship Active Object</documentation>
<attribute name="m_x" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_y" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_exp_ctr" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_score" type="uint16_t" visibility="0x02" properties="0x00"/>
<operation name="Ship" type="" visibility="0x00" properties="0x00">
<code> : QMActive(Q_STATE_CAST(&amp;Ship::initial)),
m_x(GAME_SHIP_X),
m_y(GAME_SHIP_Y)</code>
</operation>
<statechart>
<initial target="../1">
<action>me-&gt;subscribe(TIME_TICK_SIG);
me-&gt;subscribe(PLAYER_TRIGGER_SIG);
// object dictionaries...
QS_OBJ_DICTIONARY(&amp;l_ship);
// function dictionaries for Ship HSM...
QS_FUN_DICTIONARY(&amp;Ship::initial);
QS_FUN_DICTIONARY(&amp;Ship::active);
QS_FUN_DICTIONARY(&amp;Ship::parked);
QS_FUN_DICTIONARY(&amp;Ship::flying);
QS_FUN_DICTIONARY(&amp;Ship::exploding);
// local signals...
QS_SIG_DICTIONARY(PLAYER_SHIP_MOVE_SIG, &amp;l_ship);
QS_SIG_DICTIONARY(TAKE_OFF_SIG, &amp;l_ship);
QS_SIG_DICTIONARY(HIT_WALL_SIG, &amp;l_ship);
QS_SIG_DICTIONARY(HIT_MINE_SIG, &amp;l_ship);
QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, &amp;l_ship);</action>
<initial_glyph conn="3,2,5,1,36,4,-2">
<action box="1,-2,6,2"/>
</initial_glyph>
</initial>
<state name="active">
<initial target="../2">
<initial_glyph conn="4,8,5,1,29,10,-2">
<action box="1,-2,6,2"/>
</initial_glyph>
</initial>
<tran trig="PLAYER_SHIP_MOVE">
<action brief="m_x = e-&gt;x;\m_y = e-&gt;y">me-&gt;m_x = Q_EVT_CAST(ObjectPosEvt)-&gt;x;
me-&gt;m_y = Q_EVT_CAST(ObjectPosEvt)-&gt;y;</action>
<tran_glyph conn="3,11,3,-1,21">
<action box="1,-2,15,6"/>
</tran_glyph>
</tran>
<state name="parked">
<tran trig="TAKE_OFF" target="../../3">
<tran_glyph conn="5,22,3,1,28,6,-2">
<action box="0,-2,8,2"/>
</tran_glyph>
</tran>
<state_glyph node="5,16,26,8"/>
</state>
<state name="flying">
<entry>me-&gt;m_score = 0U; /* reset the score */
ScoreEvt *sev = Q_NEW(ScoreEvt, SCORE_SIG);
sev-&gt;score = me-&gt;m_score;
AO_Tunnel-&gt;POST(sev, me);</entry>
<tran trig="TIME_TICK">
<action>// tell the Tunnel to draw the Ship and test for hits
ObjectImageEvt *oie = Q_NEW(ObjectImageEvt, SHIP_IMG_SIG);
oie-&gt;x = me-&gt;m_x;
oie-&gt;y = me-&gt;m_y;
oie-&gt;bmp = SHIP_BMP;
AO_Tunnel-&gt;POST(oie, me);
++me-&gt;m_score; // increment the score for surviving another tick
if ((me-&gt;m_score % 10U) == 0U) { // is the score &quot;round&quot;?
ScoreEvt *sev = Q_NEW(ScoreEvt, SCORE_SIG);
sev-&gt;score = me-&gt;m_score;
AO_Tunnel-&gt;POST(sev, me);
}</action>
<tran_glyph conn="5,33,3,-1,16">
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<tran trig="PLAYER_TRIGGER">
<action>ObjectPosEvt *ope = Q_NEW(ObjectPosEvt, MISSILE_FIRE_SIG);
ope-&gt;x = me-&gt;m_x;
ope-&gt;y = me-&gt;m_y + SHIP_HEIGHT - 1U;
AO_Missile-&gt;POST(ope, me);</action>
<tran_glyph conn="5,36,3,-1,16">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<tran trig="DESTROYED_MINE">
<action>me-&gt;m_score += Q_EVT_CAST(ScoreEvt)-&gt;score;
// the score will be sent to the Tunnel by the next TIME_TICK</action>
<tran_glyph conn="5,39,3,-1,16">
<action box="0,-2,13,2"/>
</tran_glyph>
</tran>
<tran trig="HIT_WALL" target="../../4">
<tran_glyph conn="5,42,3,1,28,9,-2">
<action box="0,-2,8,2"/>
</tran_glyph>
</tran>
<tran trig="HIT_MINE" target="../../4">
<tran_glyph conn="5,45,3,1,28,6,-2">
<action box="0,-2,10,2"/>
</tran_glyph>
</tran>
<state_glyph node="5,26,26,21">
<entry box="1,2,5,2"/>
</state_glyph>
</state>
<state name="exploding">
<entry>me-&gt;m_exp_ctr = 0U;</entry>
<tran trig="TIME_TICK">
<choice>
<guard>me-&gt;m_exp_ctr &lt; 15U</guard>
<action>++me-&gt;m_exp_ctr;
// tell the Tunnel to draw the current stage of Explosion
ObjectImageEvt *oie = Q_NEW(ObjectImageEvt, EXPLOSION_SIG);
oie-&gt;bmp = EXPLOSION0_BMP + (me-&gt;m_exp_ctr &gt;&gt; 2);
oie-&gt;x = me-&gt;m_x; // x of explosion
oie-&gt;y = (int8_t)((int)me-&gt;m_y - 4U + SHIP_HEIGHT);
AO_Tunnel-&gt;POST(oie, me);</action>
<choice_glyph conn="14,57,5,-1,15">
<action box="1,0,15,2"/>
</choice_glyph>
</choice>
<choice target="../../../2">
<guard brief="else"/>
<action>ScoreEvt *gameOver = Q_NEW(ScoreEvt, GAME_OVER_SIG);
gameOver-&gt;score = me-&gt;m_score;
AO_Tunnel-&gt;POST(gameOver, me);</action>
<choice_glyph conn="14,57,4,1,4,21,-41,-4">
<action box="1,4,6,2"/>
</choice_glyph>
</choice>
<tran_glyph conn="5,57,3,-1,9">
<action box="0,-2,10,2"/>
</tran_glyph>
</tran>
<state_glyph node="5,49,26,14">
<entry box="1,2,13,4"/>
</state_glyph>
</state>
<state_glyph node="3,4,34,61"/>
</state>
<state_diagram size="41,67"/>
</statechart>
</class>
<class name="Missile" superclass="qpcpp::QMActive">
<documentation>Missile Active Object</documentation>
<attribute name="m_x" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_y" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_exp_ctr" type="uint8_t" visibility="0x02" properties="0x00"/>
<operation name="Missile" type="" visibility="0x00" properties="0x00">
<code> : QMActive(Q_STATE_CAST(&amp;Missile::initial))</code>
</operation>
<statechart>
<initial target="../1">
<action>me-&gt;subscribe( TIME_TICK_SIG);
QS_OBJ_DICTIONARY(&amp;l_missile); // object dictionary for Missile object
QS_FUN_DICTIONARY(&amp;Missile::initial); // dictionaries for Missile HSM
QS_FUN_DICTIONARY(&amp;Missile::armed);
QS_FUN_DICTIONARY(&amp;Missile::flying);
QS_FUN_DICTIONARY(&amp;Missile::exploding);
QS_SIG_DICTIONARY(MISSILE_FIRE_SIG, &amp;l_missile); // local signals
QS_SIG_DICTIONARY(HIT_WALL_SIG, &amp;l_missile);
QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, &amp;l_missile);</action>
<initial_glyph conn="3,3,5,1,35,4,-2">
<action box="1,-2,6,2"/>
</initial_glyph>
</initial>
<state name="armed">
<tran trig="MISSILE_FIRE" target="../../2">
<action>me-&gt;m_x = Q_EVT_CAST(ObjectPosEvt)-&gt;x;
me-&gt;m_y = Q_EVT_CAST(ObjectPosEvt)-&gt;y;</action>
<tran_glyph conn="3,11,3,1,35,6,-2">
<action box="0,-2,11,2"/>
</tran_glyph>
</tran>
<state_glyph node="3,5,33,8"/>
</state>
<state name="flying">
<tran trig="TIME_TICK">
<choice>
<guard>me-&gt;m_x + GAME_MISSILE_SPEED_X &lt; GAME_SCREEN_WIDTH</guard>
<action brief="...">me-&gt;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-&gt;x = me-&gt;m_x;
oie-&gt;y = me-&gt;m_y;
oie-&gt;bmp = MISSILE_BMP;
AO_Tunnel-&gt;POST(oie, me);</action>
<choice_glyph conn="12,21,5,-1,20">
<action box="1,0,22,4"/>
</choice_glyph>
</choice>
<choice target="../../../1">
<guard brief="else"/>
<choice_glyph conn="12,21,4,1,5,28,-17,-4">
<action box="1,5,6,2"/>
</choice_glyph>
</choice>
<tran_glyph conn="3,21,3,-1,9">
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<tran trig="HIT_WALL" target="../../3">
<tran_glyph conn="3,33,3,1,35,6,-2">
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<tran trig="DESTROYED_MINE" target="../../1">
<action>AO_Ship-&gt;POST(e, me);</action>
<tran_glyph conn="3,30,3,1,39,-21,-6">
<action box="0,-2,15,2"/>
</tran_glyph>
</tran>
<state_glyph node="3,15,33,20"/>
</state>
<state name="exploding">
<entry>me-&gt;m_exp_ctr = 0U;</entry>
<tran trig="TIME_TICK">
<choice>
<guard>(me-&gt;m_x &gt;= GAME_SPEED_X) &amp;&amp; (me-&gt;m_exp_ctr &lt; 15U)</guard>
<action brief="...">++me-&gt;m_exp_ctr; // advance the explosion counter
me-&gt;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-&gt;x = me-&gt;m_x + 3U; // x-pos of explosion
oie-&gt;y = (int8_t)((int)me-&gt;m_y - 4U); // y-pos
oie-&gt;bmp = EXPLOSION0_BMP + (me-&gt;m_exp_ctr &gt;&gt; 2);
AO_Tunnel-&gt;POST(oie, me);</action>
<choice_glyph conn="12,46,5,-1,20">
<action box="1,0,19,4"/>
</choice_glyph>
</choice>
<choice target="../../../1">
<guard brief="else"/>
<choice_glyph conn="12,46,4,1,5,32,-42,-8">
<action box="1,5,7,2"/>
</choice_glyph>
</choice>
<tran_glyph conn="3,46,3,-1,9">
<action box="0,-2,8,2"/>
</tran_glyph>
</tran>
<state_glyph node="3,37,33,16">
<entry box="1,2,14,4"/>
</state_glyph>
</state>
<state_diagram size="46,55"/>
</statechart>
</class>
<class name="Mine1" superclass="qpcpp::QMsm">
<documentation>The Mine1 orthogonal component</documentation>
<attribute name="m_x" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_y" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_exp_ctr" type="uint8_t" visibility="0x02" properties="0x00"/>
<operation name="Mine1" type="" visibility="0x00" properties="0x02">
<code> : QMsm(Q_STATE_CAST(&amp;Mine1::initial))</code>
</operation>
<statechart>
<initial target="../1">
<action>static bool dict_sent = false;
if (!dict_sent) {
dict_sent = true;
QS_OBJ_DICTIONARY(&amp;l_mine1[0]); // obj. dictionaries for Mine1 pool
QS_OBJ_DICTIONARY(&amp;l_mine1[1]);
QS_OBJ_DICTIONARY(&amp;l_mine1[2]);
QS_OBJ_DICTIONARY(&amp;l_mine1[3]);
QS_OBJ_DICTIONARY(&amp;l_mine1[4]);
QS_FUN_DICTIONARY(&amp;Mine1::initial);// fun. dictionaries for Mine1 HSM
QS_FUN_DICTIONARY(&amp;Mine1::unused);
QS_FUN_DICTIONARY(&amp;Mine1::used);
QS_FUN_DICTIONARY(&amp;Mine1::planted);
QS_FUN_DICTIONARY(&amp;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);</action>
<initial_glyph conn="2,2,5,1,31,4,-2">
<action box="0,-2,11,2"/>
</initial_glyph>
</initial>
<state name="unused">
<tran trig="MINE_PLANT" target="../../2/2">
<action>me-&gt;m_x = Q_EVT_CAST(ObjectPosEvt)-&gt;x;
me-&gt;m_y = Q_EVT_CAST(ObjectPosEvt)-&gt;y;</action>
<tran_glyph conn="2,10,3,1,43,16,-8">
<action box="0,-2,10,2"/>
</tran_glyph>
</tran>
<state_glyph node="2,4,29,8"/>
</state>
<state name="used">
<exit brief="...">// tell the Tunnel that this mine is becoming disabled
MineEvt *mev = Q_NEW(MineEvt, MINE_DISABLED_SIG);
mev-&gt;id = MINE_ID(me);
AO_Tunnel-&gt;POST(mev, me);</exit>
<tran trig="MINE_RECYCLE" target="../../1">
<tran_glyph conn="2,21,3,1,41,-13,-12">
<action box="0,-2,11,2"/>
</tran_glyph>
</tran>
<state name="exploding">
<entry>me-&gt;m_exp_ctr = 0U;</entry>
<tran trig="TIME_TICK">
<choice>
<guard brief="still on screen?">(me-&gt;m_x &gt;= GAME_SPEED_X) &amp;&amp; (me-&gt;m_exp_ctr &lt; 15)</guard>
<action>++me-&gt;m_exp_ctr; // advance the explosion counter
me-&gt;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-&gt;x = me-&gt;m_x + 1U; // x of explosion
oie-&gt;y = (int8_t)((int)me-&gt;m_y - 4 + 2); // y of explosion
oie-&gt;bmp = EXPLOSION0_BMP + (me-&gt;m_exp_ctr &gt;&gt; 2);
AO_Tunnel-&gt;POST(oie, me);</action>
<choice_glyph conn="14,57,5,-1,21">
<action box="1,0,20,2"/>
</choice_glyph>
</choice>
<choice target="../../../../1">
<guard brief="else"/>
<choice_glyph conn="14,57,4,1,5,37,-54,-20">
<action box="1,5,6,2"/>
</choice_glyph>
</choice>
<tran_glyph conn="4,57,3,-1,10">
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<state_glyph node="4,50,33,14">
<entry box="1,2,5,2"/>
</state_glyph>
</state>
<state name="planted">
<tran trig="TIME_TICK">
<choice>
<guard>me-&gt;m_x &gt;= GAME_SPEED_X</guard>
<action>me-&gt;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-&gt;x = me-&gt;m_x;
oie-&gt;y = me-&gt;m_y;
oie-&gt;bmp = MINE1_BMP;
AO_Tunnel-&gt;POST(oie, me);</action>
<choice_glyph conn="15,30,5,-1,20">
<action box="1,0,20,2"/>
</choice_glyph>
</choice>
<choice target="../../../../1">
<guard brief="else"/>
<choice_glyph conn="15,30,4,1,4,32,-26,-16">
<action box="1,4,6,2"/>
</choice_glyph>
</choice>
<tran_glyph conn="4,30,3,-1,11">
<action box="0,-2,10,2"/>
</tran_glyph>
</tran>
<tran trig="SHIP_IMG">
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)-&gt;x;
uint8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;</action>
<choice target="../../../../1">
<guard brief="collision with MINE1_BMP?">do_bitmaps_overlap(MINE1_BMP, me-&gt;m_x, me-&gt;m_y, bmp, x, y)</guard>
<action brief="...">static MineEvt const mine1_hit(HIT_MINE_SIG, 1U);
AO_Ship-&gt;POST(&amp;mine1_hit, me);
// go straight to 'disabled' and let the Ship do
// the exploding</action>
<choice_glyph conn="15,37,5,1,34,-29,-18">
<action box="1,0,22,4"/>
</choice_glyph>
</choice>
<tran_glyph conn="4,37,3,-1,11">
<action box="0,-2,8,2"/>
</tran_glyph>
</tran>
<tran trig="MISSILE_IMG">
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)-&gt;x;
uint8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;</action>
<choice target="../../../1">
<guard brief="collision with MINE1_BMP?">do_bitmaps_overlap(MINE1_BMP, me-&gt;m_x, me-&gt;m_y, bmp, x, y)</guard>
<action brief="...">static ScoreEvt const mine1_destroyed(DESTROYED_MINE_SIG, 25U);
AO_Missile-&gt;POST(&amp;mine1_destroyed, me);</action>
<choice_glyph conn="15,43,5,1,24,9,-2">
<action box="1,0,22,4"/>
</choice_glyph>
</choice>
<tran_glyph conn="4,43,3,-1,11">
<action box="0,-2,11,2"/>
</tran_glyph>
</tran>
<state_glyph node="4,24,33,24"/>
</state>
<state_glyph node="2,14,39,52">
<exit box="1,2,5,2"/>
</state_glyph>
</state>
<state_diagram size="53,68"/>
</statechart>
</class>
<class name="Mine2" superclass="qpcpp::QMsm">
<documentation>The Mine2 orthogonal component</documentation>
<attribute name="m_x" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_y" type="uint8_t" visibility="0x02" properties="0x00"/>
<attribute name="m_exp_ctr" type="uint8_t" visibility="0x02" properties="0x00"/>
<operation name="Mine2" type="" visibility="0x00" properties="0x02">
<code> : QMsm(Q_STATE_CAST(&amp;Mine2::initial))</code>
</operation>
<statechart>
<initial target="../1">
<action>static bool dict_sent = false;
if (!dict_sent) {
dict_sent = true;
QS_OBJ_DICTIONARY(&amp;l_mine2[0]); // obj. dictionaries for Mine2 pool
QS_OBJ_DICTIONARY(&amp;l_mine2[1]);
QS_OBJ_DICTIONARY(&amp;l_mine2[2]);
QS_OBJ_DICTIONARY(&amp;l_mine2[3]);
QS_OBJ_DICTIONARY(&amp;l_mine2[4]);
QS_FUN_DICTIONARY(&amp;Mine2::initial);// fun. dictionaries for Mine2 HSM
QS_FUN_DICTIONARY(&amp;Mine2::unused);
QS_FUN_DICTIONARY(&amp;Mine2::used);
QS_FUN_DICTIONARY(&amp;Mine2::planted);
QS_FUN_DICTIONARY(&amp;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);</action>
<initial_glyph conn="2,2,5,1,31,4,-2">
<action box="0,-2,11,2"/>
</initial_glyph>
</initial>
<state name="unused">
<tran trig="MINE_PLANT" target="../../2/2">
<action>me-&gt;m_x = Q_EVT_CAST(ObjectPosEvt)-&gt;x;
me-&gt;m_y = Q_EVT_CAST(ObjectPosEvt)-&gt;y;</action>
<tran_glyph conn="2,10,3,1,43,16,-8">
<action box="0,-2,10,2"/>
</tran_glyph>
</tran>
<state_glyph node="2,4,29,8"/>
</state>
<state name="used">
<exit brief="...">// tell the Tunnel that this mine is becoming disabled
MineEvt *mev = Q_NEW(MineEvt, MINE_DISABLED_SIG);
mev-&gt;id = MINE_ID(me);
AO_Tunnel-&gt;POST(mev, me);</exit>
<tran trig="MINE_RECYCLE" target="../../1">
<tran_glyph conn="2,21,3,1,41,-13,-12">
<action box="0,-2,11,2"/>
</tran_glyph>
</tran>
<state name="exploding">
<entry>me-&gt;m_exp_ctr = 0U;</entry>
<tran trig="TIME_TICK">
<choice>
<guard brief="still on screen?">(me-&gt;m_x &gt;= GAME_SPEED_X) &amp;&amp; (me-&gt;m_exp_ctr &lt; 15)</guard>
<action>++me-&gt;m_exp_ctr; // advance the explosion counter
me-&gt;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-&gt;x = me-&gt;m_x + 1U; // x of explosion
oie-&gt;y = (int8_t)((int)me-&gt;m_y - 4 + 2); // y of explosion
oie-&gt;bmp = EXPLOSION0_BMP + (me-&gt;m_exp_ctr &gt;&gt; 2);
AO_Tunnel-&gt;POST(oie, me);</action>
<choice_glyph conn="14,57,5,-1,21">
<action box="1,0,20,2"/>
</choice_glyph>
</choice>
<choice target="../../../../1">
<guard brief="else"/>
<choice_glyph conn="14,57,4,1,5,37,-54,-20">
<action box="1,5,6,2"/>
</choice_glyph>
</choice>
<tran_glyph conn="4,57,3,-1,10">
<action box="0,-2,9,2"/>
</tran_glyph>
</tran>
<state_glyph node="4,50,33,14">
<entry box="1,2,5,2"/>
</state_glyph>
</state>
<state name="planted">
<tran trig="TIME_TICK">
<choice>
<guard>me-&gt;m_x &gt;= GAME_SPEED_X</guard>
<action>me-&gt;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-&gt;x = me-&gt;m_x;
oie-&gt;y = me-&gt;m_y;
oie-&gt;bmp = MINE2_BMP;
AO_Tunnel-&gt;POST(oie, me);</action>
<choice_glyph conn="15,30,5,-1,20">
<action box="1,0,20,2"/>
</choice_glyph>
</choice>
<choice target="../../../../1">
<guard brief="else"/>
<choice_glyph conn="15,30,4,1,4,32,-26,-16">
<action box="1,4,6,2"/>
</choice_glyph>
</choice>
<tran_glyph conn="4,30,3,-1,11">
<action box="0,-2,10,2"/>
</tran_glyph>
</tran>
<tran trig="SHIP_IMG">
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)-&gt;x;
uint8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;</action>
<choice target="../../../../1">
<guard brief="collision with MINE2_BMP?">do_bitmaps_overlap(MINE2_BMP, me-&gt;m_x, me-&gt;m_y, bmp, x, y)</guard>
<action brief="...">static MineEvt const mine2_hit(HIT_MINE_SIG, 2U);
AO_Ship-&gt;POST(&amp;mine2_hit, me);
// go straight to 'disabled' and let the Ship do
// the exploding</action>
<choice_glyph conn="15,37,5,1,34,-29,-18">
<action box="1,0,22,4"/>
</choice_glyph>
</choice>
<tran_glyph conn="4,37,3,-1,11">
<action box="0,-2,8,2"/>
</tran_glyph>
</tran>
<tran trig="MISSILE_IMG">
<action>uint8_t x = Q_EVT_CAST(ObjectImageEvt)-&gt;x;
uint8_t y = Q_EVT_CAST(ObjectImageEvt)-&gt;y;
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)-&gt;bmp;</action>
<choice target="../../../1">
<guard brief="collision with MINE2_MISSILE_BMP?">do_bitmaps_overlap(MINE2_MISSILE_BMP, me-&gt;m_x, me-&gt;m_y, bmp, x, y)</guard>
<action brief="...">static ScoreEvt const mine2_destroyed(DESTROYED_MINE_SIG, 45U);
AO_Missile-&gt;POST(&amp;mine2_destroyed, me);</action>
<choice_glyph conn="15,43,5,1,24,9,-2">
<action box="1,0,22,4"/>
</choice_glyph>
</choice>
<tran_glyph conn="4,43,3,-1,11">
<action box="0,-2,11,2"/>
</tran_glyph>
</tran>
<state_glyph node="4,24,33,24"/>
</state>
<state_glyph node="2,14,39,52">
<exit box="1,2,5,2"/>
</state_glyph>
</state>
<state_diagram size="53,68"/>
</statechart>
</class>
<attribute name="AO_Tunnel" type="QP::QActive * const" visibility="0x00" properties="0x00"/>
<attribute name="AO_Ship" type="QP::QActive * const" visibility="0x00" properties="0x00"/>
<attribute name="AO_Missile" type="QP::QActive * const" visibility="0x00" properties="0x00"/>
<operation name="do_bitmaps_overlap" type="bool" visibility="0x00" properties="0x00">
<parameter name="bmp_id1" type="uint8_t"/>
<parameter name="x1" type="uint8_t"/>
<parameter name="y1" type="uint8_t"/>
<parameter name="bmp_id2" type="uint8_t"/>
<parameter name="x2" type="uint8_t"/>
<parameter name="y2" type="uint8_t"/>
</operation>
</package>
<directory name=".">
<file name="game.h">
<text>#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 adjust game level based on score
MAX_SIG // the last signal (keep always last)
};
#define GAME_SCREEN_WIDTH BSP_SCREEN_WIDTH
#define GAME_SCREEN_HEIGHT BSP_SCREEN_HEIGHT
#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_SCREEN_HEIGHT / 2U)
enum GameBitmapIds {
PRESS_BUTTON_BMP,
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::QMsm *Mine1_getInst(uint8_t id);
QP::QMsm *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)
// helper function for all AOs
$declare(AOs::do_bitmaps_overlap)
#endif // game_h</text>
</file>
<file name="main.cpp">
<text>#include &quot;qp_port.h&quot;
#include &quot;bsp.h&quot;
#include &quot;game.h&quot;
//............................................................................
int main() {
static QP::QEvt const * missileQueueSto[2];
static QP::QEvt const * shipQueueSto[3];
static QP::QEvt const * tunnelQueueSto[GAME_MINES_MAX + 5];
static QF_MPOOL_EL(QP::QEvt) smlPoolSto[10];
static QF_MPOOL_EL(GAME::ObjectImageEvt) medPoolSto[2*GAME_MINES_MAX + 10];
static QP::QSubscrList subscrSto[GAME::MAX_PUB_SIG];
QP::QF::init(); // initialize the framework and the underlying RT kernel
GAME::BSP_init(); // initialize the Board Support Package
// initialize the event pools...
QP::QF::poolInit(smlPoolSto, sizeof(smlPoolSto), sizeof(smlPoolSto[0]));
QP::QF::poolInit(medPoolSto, sizeof(medPoolSto), sizeof(medPoolSto[0]));
QP::QF::psInit(subscrSto, Q_DIM(subscrSto)); // init publish-subscribe
// send object dictionaries for event queues...
QS_OBJ_DICTIONARY(missileQueueSto);
QS_OBJ_DICTIONARY(shipQueueSto);
QS_OBJ_DICTIONARY(tunnelQueueSto);
// send object dictionaries for event pools...
QS_OBJ_DICTIONARY(smlPoolSto);
QS_OBJ_DICTIONARY(medPoolSto);
// send signal dictionaries for globally published events...
QS_SIG_DICTIONARY(GAME::TIME_TICK_SIG, static_cast&lt;void *&gt;(0));
QS_SIG_DICTIONARY(GAME::PLAYER_TRIGGER_SIG, static_cast&lt;void *&gt;(0));
QS_SIG_DICTIONARY(GAME::PLAYER_QUIT_SIG, static_cast&lt;void *&gt;(0));
QS_SIG_DICTIONARY(GAME::GAME_OVER_SIG, static_cast&lt;void *&gt;(0));
// start the active objects...
GAME::AO_Tunnel -&gt;start(1U, // priority
tunnelQueueSto, Q_DIM(tunnelQueueSto), // evt queue
static_cast&lt;void *&gt;(0), 0U); // no per-thread stack
GAME::AO_Missile-&gt;start(2U, // priority
missileQueueSto, Q_DIM(missileQueueSto), // evt queue
static_cast&lt;void *&gt;(0), 0U); // no per-thread stack
GAME::AO_Ship -&gt;start(3U, // priority
shipQueueSto, Q_DIM(shipQueueSto), // evt queue
static_cast&lt;void *&gt;(0), 0U); // no per-thread stack
return QP::QF::run(); // run the QF application
}
</text>
</file>
<file name="missile.cpp">
<text>#include &quot;qp_port.h&quot;
#include &quot;bsp.h&quot;
#include &quot;game.h&quot;
//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 = &amp;l_missile; // opaque pointer
} // namespace GAME
// Active object definition --------------------------------------------------
$define(AOs::Missile)</text>
</file>
<file name="ship.cpp">
<text>#include &quot;qp_port.h&quot;
#include &quot;bsp.h&quot;
#include &quot;game.h&quot;
//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 = &amp;l_ship; // opaque pointer
} // namespace GAME
// Active object definition --------------------------------------------------
$define(AOs::Ship)</text>
</file>
<file name="tunnel.cpp">
<text>#include &quot;qp_port.h&quot;
#include &quot;bsp.h&quot;
#include &quot;game.h&quot;
#include &lt;string.h&gt; // 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
static uint32_t l_rnd; // random seed
static uint8_t l_walls[GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U];
static uint8_t l_frame[GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U];
// local helper functions ----------------------------------------------------
static void randomSeed(uint32_t seed);
static uint32_t random(void);
// Public-scope objects ------------------------------------------------------
QP::QActive * const AO_Tunnel = &amp;l_tunnel; // opaque pointer
// helper functions ----------------------------------------------------------
//
// The bitmap for the &quot;Press Button&quot; text:
//
// xxx.........................xxx........x...x...........
// x..x........................x..x.......x...x...........
// x..x.x.xx..xx...xxx..xxx....x..x.x..x.xxx.xxx..xx..xxx.
// xxx..xx...x..x.x....x.......xxx..x..x..x...x..x..x.x..x
// x....x....xxxx..xx...xx.....x..x.x..x..x...x..x..x.x..x
// x....x....x.......x....x....x..x.x..x..x...x..x..x.x..x
// x....x.....xxx.xxx..xxx.....xxx...xxx...x...x..xx..x..x
// .......................................................
///
static uint8_t const press_button_bits[] = {
0x7F, 0x09, 0x09, 0x06, 0x00, 0x7C, 0x08, 0x04, 0x04, 0x00,
0x38, 0x54, 0x54, 0x58, 0x00, 0x48, 0x54, 0x54, 0x24, 0x00,
0x48, 0x54, 0x54, 0x24, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x49,
0x49, 0x36, 0x00, 0x3C, 0x40, 0x40, 0x7C, 0x00, 0x04, 0x3F,
0x44, 0x00, 0x04, 0x3F, 0x44, 0x00, 0x38, 0x44, 0x44, 0x38,
0x00, 0x7C, 0x04, 0x04, 0x78
};
// bitmap of the Ship:
//
// x....
// xxx..
// xxxxx
///
static uint8_t const ship_bits[] = {
0x07, 0x06, 0x06, 0x04, 0x04
};
// bitmap of the Missile:
//
// xxx
///
static uint8_t const missile_bits[] = {
0x01, 0x01, 0x01
};
// bitmap of the Mine type-1:
//
// .x.
// xxx
// .x.
///
static uint8_t const mine1_bits[] = {
0x02, 0x07, 0x02
};
// bitmap of the Mine type-2:
//
// x..x
// .xx.
// .xx.
// x..x
///
static uint8_t const mine2_bits[] = {
0x09, 0x06, 0x06, 0x09
};
// Mine type-2 is nastier than Mine type-1. The type-2 mine can
// hit the Ship with any of its &quot;tentacles&quot;. However, it can be
// destroyed by the Missile only by hitting its center, defined as
// the following bitmap:
//
// ....
// .xx.
// .xx.
// ....
///
static uint8_t const mine2_missile_bits[] = {
0x00, 0x06, 0x06, 0x00
};
// The bitmap of the explosion stage 0:
//
// .......
// .......
// ...x...
// ..x.x..
// ...x...
// .......
// .......
///
static uint8_t const explosion0_bits[] = {
0x00, 0x00, 0x08, 0x14, 0x08, 0x00, 0x00
};
// The bitmap of the explosion stage 1:
//
// .......
// .......
// ..x.x..
// ...x...
// ..x.x..
// .......
// .......
///
static uint8_t const explosion1_bits[] = {
0x00, 0x00, 0x14, 0x08, 0x14, 0x00, 0x00
};
// The bitmap of the explosion stage 2:
//
// .......
// .x...x.
// ..x.x..
// ...x...
// ..x.x..
// .x...x.
// .......
///
static uint8_t const explosion2_bits[] = {
0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00
};
// The bitmap of the explosion stage 3:
//
// x..x..x
// .x.x.x.
// ..x.x..
// xx.x.xx
// ..x.x..
// .x.x.x.
// x..x..x
///
static uint8_t const explosion3_bits[] = {
0x49, 0x2A, 0x14, 0x6B, 0x14, 0x2A, 0x49
};
struct Bitmap { // the auxiliary structure to hold const bitmaps
uint8_t const *bits; // the bits in the bitmap
uint8_t width; // the width of the bitmap
};
static Bitmap const l_bitmap[MAX_BMP] = {
{ press_button_bits, Q_DIM(press_button_bits) },
{ ship_bits, Q_DIM(ship_bits) },
{ missile_bits, Q_DIM(missile_bits) },
{ mine1_bits, Q_DIM(mine1_bits) },
{ mine2_bits, Q_DIM(mine2_bits) },
{ mine2_missile_bits, Q_DIM(mine2_missile_bits) },
{ explosion0_bits, Q_DIM(explosion0_bits) },
{ explosion1_bits, Q_DIM(explosion1_bits) },
{ explosion2_bits, Q_DIM(explosion2_bits) },
{ explosion3_bits, Q_DIM(explosion3_bits) }
};
//............................................................................
uint32_t random(void) { // a very cheap pseudo-random-number generator
// &quot;Super-Duper&quot; Linear Congruential Generator (LCG)
// LCG(2^32, 3*7*11*13*23, 0, seed)
//
l_rnd = l_rnd * (3*7*11*13*23);
return l_rnd &gt;&gt; 8;
}
//............................................................................
void randomSeed(uint32_t seed) {
l_rnd = seed;
}
//............................................................................
bool do_bitmaps_overlap(uint8_t bmp_id1, uint8_t x1, uint8_t y1,
uint8_t bmp_id2, uint8_t x2, uint8_t y2)
{
uint8_t x;
uint8_t x0;
uint8_t w;
uint32_t bits1;
uint32_t bits2;
Bitmap const *bmp1;
Bitmap const *bmp2;
Q_REQUIRE((bmp_id1 &lt; Q_DIM(l_bitmap)) &amp;&amp; (bmp_id2 &lt; Q_DIM(l_bitmap)));
bmp1 = &amp;l_bitmap[bmp_id1];
bmp2 = &amp;l_bitmap[bmp_id2];
// is the incoming object starting to overlap the Mine bitmap?
if ((x1 &lt;= x2) &amp;&amp; (x1 + bmp2-&gt;width &gt; x2)) {
x0 = x2 - x1;
w = x1 + bmp2-&gt;width - x2;
if (w &gt; bmp1-&gt;width) {
w = bmp1-&gt;width;
}
for (x = 0; x &lt; w; ++x) { // scan over the overlapping columns
bits1 = ((uint32_t)bmp2-&gt;bits[x + x0] &lt;&lt; y2);
bits2 = ((uint32_t)bmp1-&gt;bits[x] &lt;&lt; y1);
if ((bits1 &amp; bits2) != 0) { // do the bits overlap?
return true; // yes!
}
}
}
else {
if ((x1 &gt; x2) &amp;&amp; (x2 + bmp1-&gt;width &gt; x1)) {
x0 = x1 - x2;
w = x2 + bmp1-&gt;width - x1;
if (w &gt; bmp2-&gt;width) {
w = bmp2-&gt;width;
}
for (x = 0; x &lt; w; ++x) { // scan over the overlapping columns
bits1 = ((uint32_t)bmp1-&gt;bits[x + x0] &lt;&lt; y1);
bits2 = ((uint32_t)bmp2-&gt;bits[x] &lt;&lt; y2);
if ((bits1 &amp; bits2) != 0U) { // do the bits overlap?
return true; // yes!
}
}
}
}
return false; // the bitmaps do not overlap
}
} // namespace GAME
// Active object definition ==================================================
$define(AOs::Tunnel)
</text>
</file>
<file name="mine1.cpp">
<text>#include &quot;qp_port.h&quot;
#include &quot;bsp.h&quot;
#include &quot;game.h&quot;
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::QMsm *Mine1_getInst(uint8_t id) {
Q_REQUIRE(id &lt; GAME_MINES_MAX);
return &amp;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&lt;uint8_t&gt;(me - l_mine1);
}
} // namespace GAME
// Mine1 class definition ----------------------------------------------------
$define(AOs::Mine1)</text>
</file>
<file name="mine2.cpp">
<text>#include &quot;qp_port.h&quot;
#include &quot;bsp.h&quot;
#include &quot;game.h&quot;
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::QMsm *Mine2_getInst(uint8_t id) {
Q_REQUIRE(id &lt; GAME_MINES_MAX);
return &amp;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&lt;uint8_t&gt;(me - l_mine2);
}
} // namespace GAME
// Mine1 class definition ----------------------------------------------------
$define(AOs::Mine2)</text>
</file>
</directory>
</model>