mirror of
https://github.com/QuantumLeaps/qpcpp.git
synced 2025-01-28 06:02:56 +08:00
1698 lines
64 KiB
XML
1698 lines
64 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<model version="2.3.2">
|
|
<documentation>"Fly 'n' Shoot" game model from Chapters 1 & 9 of PSiCC2</documentation>
|
|
<framework name="qpcpp"/>
|
|
<package name="Qt-port" stereotype="0x00" namespace="QP::">
|
|
<class name="GuiQActive" superclass="qpcpp::QActive">
|
|
<operation name="GuiQActive" type="QActive(initial)" visibility="0x00" properties="0x00">
|
|
<parameter name="initial" type="QStateHandler"/>
|
|
</operation>
|
|
<operation name="start" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>Starts execution of an active object and registers the object with the framework. This function is strongly OS-dependent and must be defined in the QP port to a particular platform.
|
|
|
|
The function takes six arguments:
|
|
|
|
'prio' is the priority of the active object. QP allows you to start up to 63 active objects, each one having a *unique* priority number between 1 and 63 inclusive, where higher numerical values correspond to higher priority (urgency) of the active object relative to the others.
|
|
|
|
'qSto[]' and 'qLen' arguments are the storage and size of the event queue used by this active object.
|
|
|
|
'stkSto' and 'stkSize' are the stack storage and size in bytes. Please note that a per-active object stack is used only when the underlying OS requies it. If the stack is not required, or the underlying OS allocates the stack internally, the stkSto should be NULL and/or stkSize should be 0.
|
|
|
|
'ie' is an optional initialization event that can be used to pass additional startup data to the active object. (Pass NULL if your active object does not expect the initialization event).</documentation>
|
|
<parameter name="prio" type="uint8_t"/>
|
|
<parameter name="qSto[]" type="QEvt const *"/>
|
|
<parameter name="qLen" type="uint32_t"/>
|
|
<parameter name="stkSto" type="void *"/>
|
|
<parameter name="stkSize" type="uint32_t"/>
|
|
<parameter name="ie" type="QEvt const *"/>
|
|
<code>// Example:
|
|
|
|
static Table l_table; // Table active object instance
|
|
static QEvt const *l_tableQueueSto[N]; // storage for Table queue
|
|
static int l_tableStk[256]; // storage for the stack for Table AO
|
|
. . .
|
|
int main() {
|
|
TableEvt ie; // initialization event for the Table AO
|
|
. . .
|
|
ie.philNum = n; // build the initialization event
|
|
. . .
|
|
l_table.start(
|
|
6, // unique priority (1..QF_MAX_ACTIVE)
|
|
l_tableQueueSto, // event queue of the active object
|
|
Q_DIM(l_tableQueueSto),// the depth of the event queue
|
|
l_tableStk, // the stack of the acitve object (optional)
|
|
sizeof(l_tableStk), // the size of the stack in bytes (optional)
|
|
&ie); // initialization event (optional)
|
|
. . .
|
|
}</code>
|
|
</operation>
|
|
<operation name="postFIFO" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>Posts an event e directly to the event queue of the acitve object me using the First-In-First-Out (FIFO) policy.
|
|
|
|
Direct event posting is the simplest asynchronous communication method available in QP.
|
|
|
|
NOTE: Direct event posting should not be confused with direct event dispatching. In contrast to asynchronous event posting through event queues, direct event dispatching is synchronous. Direct event dispatching occurs when you call QHsm::dispatch() or QFsm::dispatch() function.</documentation>
|
|
<parameter name="e" type="QEvt const *"/>
|
|
<code>// Example:
|
|
|
|
extern QActive *AO_Table;
|
|
|
|
. . .
|
|
pe = Q_NEW(TableEvt, HUNGRY_SIG); // dynamically allocate event
|
|
pe->philNum = me->num;
|
|
|
|
AO_Table->postFIFO(pe); // <==</code>
|
|
</operation>
|
|
<operation name="postLIFO" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>Posts an event e directly to the event queue of the acitve object me using the Last-In-First-Out (LIFO) policy.
|
|
|
|
Direct event posting is the simplest asynchronous communication method available in QP.
|
|
|
|
NOTE: You should be very careful with the LIFO (Last In First Out) policy, because it *reverses* the order of events in the queue. Typically, the QActive_postLIFO() operation shuould be only used for self-posting of events as reminders (see the "Reminder" state pattern) for continuing a processing. The postLIFO() operation is also used in the QActive::recall() operation.
|
|
|
|
NOTE: Direct event posting should not be confused with direct event dispatching. In contrast to asynchronous event posting through event queues, direct event dispatching is synchronous. Direct event dispatching occurs when you call QHsm::dispatch() or QFsm::dispatch() function.</documentation>
|
|
<parameter name="e" type="QEvt const *"/>
|
|
<code>// Example:
|
|
. . .
|
|
pe = Q_NEW(TableEvt, HUNGRY_SIG); // dynamically allocate event
|
|
pe->philNum = me->num;
|
|
. . .
|
|
me->postLIFO(pe); // <==</code>
|
|
</operation>
|
|
</class>
|
|
<class name="GuiQMActive" superclass="qpcpp::QActive">
|
|
<operation name="GuiQMActive" type="QMActive(initial)" visibility="0x00" properties="0x00">
|
|
<parameter name="initial" type="QStateHandler"/>
|
|
</operation>
|
|
<operation name="start" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>Starts execution of an active object and registers the object with the framework. This function is strongly OS-dependent and must be defined in the QP port to a particular platform.
|
|
|
|
The function takes six arguments:
|
|
|
|
'prio' is the priority of the active object. QP allows you to start up to 63 active objects, each one having a *unique* priority number between 1 and 63 inclusive, where higher numerical values correspond to higher priority (urgency) of the active object relative to the others.
|
|
|
|
'qSto[]' and 'qLen' arguments are the storage and size of the event queue used by this active object.
|
|
|
|
'stkSto' and 'stkSize' are the stack storage and size in bytes. Please note that a per-active object stack is used only when the underlying OS requies it. If the stack is not required, or the underlying OS allocates the stack internally, the stkSto should be NULL and/or stkSize should be 0.
|
|
|
|
'ie' is an optional initialization event that can be used to pass additional startup data to the active object. (Pass NULL if your active object does not expect the initialization event).</documentation>
|
|
<parameter name="prio" type="uint8_t"/>
|
|
<parameter name="qSto[]" type="QEvt const *"/>
|
|
<parameter name="qLen" type="uint32_t"/>
|
|
<parameter name="stkSto" type="void *"/>
|
|
<parameter name="stkSize" type="uint32_t"/>
|
|
<parameter name="ie" type="QEvt const *"/>
|
|
<code>// Example:
|
|
|
|
static Table l_table; // Table active object instance
|
|
static QEvt const *l_tableQueueSto[N]; // storage for Table queue
|
|
static int l_tableStk[256]; // storage for the stack for Table AO
|
|
. . .
|
|
int main() {
|
|
TableEvt ie; // initialization event for the Table AO
|
|
. . .
|
|
ie.philNum = n; // build the initialization event
|
|
. . .
|
|
l_table.start(
|
|
6, // unique priority (1..QF_MAX_ACTIVE)
|
|
l_tableQueueSto, // event queue of the active object
|
|
Q_DIM(l_tableQueueSto),// the depth of the event queue
|
|
l_tableStk, // the stack of the acitve object (optional)
|
|
sizeof(l_tableStk), // the size of the stack in bytes (optional)
|
|
&ie); // initialization event (optional)
|
|
. . .
|
|
}</code>
|
|
</operation>
|
|
<operation name="postFIFO" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>Posts an event e directly to the event queue of the acitve object me using the First-In-First-Out (FIFO) policy.
|
|
|
|
Direct event posting is the simplest asynchronous communication method available in QP.
|
|
|
|
NOTE: Direct event posting should not be confused with direct event dispatching. In contrast to asynchronous event posting through event queues, direct event dispatching is synchronous. Direct event dispatching occurs when you call QHsm::dispatch() or QFsm::dispatch() function.</documentation>
|
|
<parameter name="e" type="QEvt const *"/>
|
|
<code>// Example:
|
|
|
|
extern QActive *AO_Table;
|
|
|
|
. . .
|
|
pe = Q_NEW(TableEvt, HUNGRY_SIG); // dynamically allocate event
|
|
pe->philNum = me->num;
|
|
|
|
AO_Table->postFIFO(pe); // <==</code>
|
|
</operation>
|
|
<operation name="postLIFO" type="void" visibility="0x00" properties="0x00">
|
|
<documentation>Posts an event e directly to the event queue of the acitve object me using the Last-In-First-Out (LIFO) policy.
|
|
|
|
Direct event posting is the simplest asynchronous communication method available in QP.
|
|
|
|
NOTE: You should be very careful with the LIFO (Last In First Out) policy, because it *reverses* the order of events in the queue. Typically, the QActive_postLIFO() operation shuould be only used for self-posting of events as reminders (see the "Reminder" state pattern) for continuing a processing. The postLIFO() operation is also used in the QActive::recall() operation.
|
|
|
|
NOTE: Direct event posting should not be confused with direct event dispatching. In contrast to asynchronous event posting through event queues, direct event dispatching is synchronous. Direct event dispatching occurs when you call QHsm::dispatch() or QFsm::dispatch() function.</documentation>
|
|
<parameter name="e" type="QEvt const *"/>
|
|
<code>// Example:
|
|
. . .
|
|
pe = Q_NEW(TableEvt, HUNGRY_SIG); // dynamically allocate event
|
|
pe->philNum = me->num;
|
|
. . .
|
|
me->postLIFO(pe); // <==</code>
|
|
</operation>
|
|
</class>
|
|
</package>
|
|
<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"/>
|
|
<operation name="ObjectPosEvt" type="QEvt(sig), x(x_p), y(y_p)" visibility="0x00" properties="0x02">
|
|
<parameter name="sig" type="QP::QSignal"/>
|
|
<parameter name="x_p" type="uint8_t"/>
|
|
<parameter name="y_p" type="uint8_t"/>
|
|
</operation>
|
|
</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"/>
|
|
<operation name="ObjectImageEvt" type="QEvt(sig), x(x_p), y(y_p), bmp(bmp_p)" visibility="0x00" properties="0x02">
|
|
<parameter name="sig" type="QP::QSignal"/>
|
|
<parameter name="x_p" type="uint8_t"/>
|
|
<parameter name="y_p" type="uint8_t"/>
|
|
<parameter name="bmp_p" type="uint8_t"/>
|
|
</operation>
|
|
</class>
|
|
<class name="MineEvt" superclass="qpcpp::QEvt">
|
|
<attribute name="id" type="uint8_t" visibility="0x00" properties="0x00"/>
|
|
<operation name="MineEvt" type="QEvt(sig), id(id_p)" visibility="0x00" properties="0x02">
|
|
<parameter name="sig" type="QP::QSignal"/>
|
|
<parameter name="id_p" type="uint8_t"/>
|
|
</operation>
|
|
</class>
|
|
<class name="ScoreEvt" superclass="qpcpp::QEvt">
|
|
<attribute name="score" type="uint16_t" visibility="0x00" properties="0x00"/>
|
|
<operation name="ScoreEvt" type="QEvt(sig), score(score_p)" visibility="0x00" properties="0x02">
|
|
<parameter name="sig" type="QP::QSignal"/>
|
|
<parameter name="score_p" type="uint16_t"/>
|
|
</operation>
|
|
</class>
|
|
</package>
|
|
<package name="AOs" stereotype="0x02" namespace="GAME::">
|
|
<class name="Tunnel" superclass="Qt-port::GuiQActive">
|
|
<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::QHsm *" visibility="0x02" properties="0x00"/>
|
|
<attribute name="m_mine1_pool[GAME_MINES_MAX]" type="QP::QHsm *" visibility="0x02" properties="0x00"/>
|
|
<attribute name="m_mine2_pool[GAME_MINES_MAX]" type="QP::QHsm *" 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="GuiQActive(Q_STATE_CAST(&Tunnel::initial)), m_blinkTimeEvt(BLINK_TIMEOUT_SIG), m_screenTimeEvt(SCREEN_TIMEOUT_SIG), m_last_mine_x(0U), m_last_mine_y(0U)" visibility="0x00" properties="0x00">
|
|
<code>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] = (QHsm *)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() & 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 = (random() & 0xFFU);
|
|
|
|
// grow the top wall thickness 18.75% of the time
|
|
if ((rnd < 48U)
|
|
&& ((GAME_SCREEN_HEIGHT
|
|
- m_wall_thickness_top
|
|
- m_wall_thickness_bottom) > m_minimal_gap)
|
|
&& ((m_last_mine_x < (GAME_SCREEN_WIDTH - 5U))
|
|
|| (m_last_mine_y > (m_wall_thickness_top + 1U))))
|
|
{
|
|
++m_wall_thickness_top;
|
|
}
|
|
|
|
// grow the bottom wall thickness 18.75% of the time
|
|
if ((rnd > 208U)
|
|
&& ((GAME_SCREEN_HEIGHT
|
|
- m_wall_thickness_top
|
|
- m_wall_thickness_bottom) > m_minimal_gap)
|
|
&& ((m_last_mine_x < (GAME_SCREEN_WIDTH - 5U))
|
|
|| (m_last_mine_y + 1U
|
|
< (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 << m_wall_thickness_top))
|
|
| (~0U << (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 >> 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() & 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_SCREEN_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 = (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 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);
|
|
|
|
// event to dispatch to the Mine
|
|
ObjectPosEvt ope(MINE_PLANT_SIG,
|
|
m_last_mine_x, m_last_mine_y);
|
|
m_mines[n]->dispatch(&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 < Q_DIM(l_bitmap));
|
|
|
|
uint8_t w = l_bitmap[bmp].width;
|
|
if (w > GAME_SCREEN_WIDTH - x_pos) {
|
|
w = GAME_SCREEN_WIDTH - x_pos;
|
|
}
|
|
for (uint8_t x = 0U; x < w; ++x) {
|
|
uint32_t bmp1;
|
|
if (y_pos >= 0) {
|
|
bmp1 = (l_bitmap[bmp].bits[x] << (uint8_t)y_pos);
|
|
}
|
|
else {
|
|
bmp1 = (l_bitmap[bmp].bits[x] >> (uint8_t)(-y_pos));
|
|
}
|
|
l_frame[x_pos + x] |= (uint8_t)bmp1;
|
|
l_frame[x_pos + x + GAME_SCREEN_WIDTH] |= (uint8_t)(bmp1 >> 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 < GAME_MINES_MAX; ++n) {
|
|
if (m_mines[n] != (QHsm *)0) { // is the mine used?
|
|
m_mines[n]->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 < Q_DIM(l_bitmap));
|
|
|
|
uint8_t w = l_bitmap[bmp].width;
|
|
if (w > GAME_SCREEN_WIDTH - x_pos) {
|
|
w = GAME_SCREEN_WIDTH - x_pos;
|
|
}
|
|
for (uint8_t x = 0U; x < w; ++x) {
|
|
uint32_t bmp1 = ((uint32_t)l_bitmap[bmp].bits[x] << y_pos);
|
|
if (((l_walls[x_pos + x] & (uint8_t)bmp1) != 0U)
|
|
|| ((l_walls[x_pos + x + GAME_SCREEN_WIDTH]
|
|
& (uint8_t)(bmp1 >> 8)) != 0))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;</code>
|
|
</operation>
|
|
<statechart>
|
|
<initial target="../1/2">
|
|
<action>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
|
|
}
|
|
|
|
randomSeed(1234); // seed the pseudo-random generator
|
|
|
|
me->subscribe(TIME_TICK_SIG);
|
|
me->subscribe(PLAYER_TRIGGER_SIG);
|
|
me->subscribe(PLAYER_QUIT_SIG);
|
|
|
|
QS_OBJ_DICTIONARY(&l_tunnel); // object dictionary for Tunnel object
|
|
QS_OBJ_DICTIONARY(&l_tunnel.m_blinkTimeEvt);
|
|
QS_OBJ_DICTIONARY(&l_tunnel.m_screenTimeEvt);
|
|
|
|
QS_FUN_DICTIONARY(&Tunnel::initial); // fun. dictionaries for Tunnel HSM
|
|
QS_FUN_DICTIONARY(&Tunnel::final);
|
|
QS_FUN_DICTIONARY(&Tunnel::active);
|
|
QS_FUN_DICTIONARY(&Tunnel::playing);
|
|
QS_FUN_DICTIONARY(&Tunnel::demo);
|
|
QS_FUN_DICTIONARY(&Tunnel::game_over);
|
|
QS_FUN_DICTIONARY(&Tunnel::screen_saver);
|
|
QS_FUN_DICTIONARY(&Tunnel::screen_saver_hide);
|
|
QS_FUN_DICTIONARY(&Tunnel::screen_saver_show);
|
|
|
|
QS_SIG_DICTIONARY(BLINK_TIMEOUT_SIG, &l_tunnel); // local signals
|
|
QS_SIG_DICTIONARY(SCREEN_TIMEOUT_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(SHIP_IMG_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(MISSILE_IMG_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(MINE_IMG_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(MINE_DISABLED_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(EXPLOSION_SIG, &l_tunnel);
|
|
QS_SIG_DICTIONARY(SCORE_SIG, &l_tunnel);</action>
|
|
<initial_glyph conn="2,2,5,1,26,14,-2">
|
|
<action box="1,-2,11,2"/>
|
|
</initial_glyph>
|
|
</initial>
|
|
<state name="active">
|
|
<tran trig="MINE_DISABLED">
|
|
<action>Q_ASSERT((Q_EVT_CAST(MineEvt)->id < GAME_MINES_MAX)
|
|
&& (me->m_mines[Q_EVT_CAST(MineEvt)->id] != (QHsm *)0));
|
|
me->m_mines[Q_EVT_CAST(MineEvt)->id] = (QHsm *)0;</action>
|
|
<tran_glyph conn="2,9,3,-1,15">
|
|
<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->m_blinkTimeEvt.postEvery(me, BSP_TICKS_PER_SEC/2U); // 1/2 sec
|
|
me->m_screenTimeEvt.postIn(me, BSP_TICKS_PER_SEC*5U); // 5 sec timeout
|
|
me->m_blink_ctr = 0U;
|
|
BSP_drawNString(0U, 0U, " Quantum LeAps ");
|
|
BSP_drawNString(0U, 1U, "state-machine.co");</entry>
|
|
<exit>me->m_blinkTimeEvt.disarm();
|
|
me->m_screenTimeEvt.disarm();</exit>
|
|
<tran trig="SCREEN_TIMEOUT" target="../../3">
|
|
<tran_glyph conn="4,26,3,1,24,6,-2">
|
|
<action box="0,-2,14,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="BLINK_TIMEOUT">
|
|
<action>me->m_blink_ctr ^= 1U; // toggle the blink couner</action>
|
|
<choice>
|
|
<guard>me->m_blink_ctr == 0U</guard>
|
|
<action>BSP_drawNString(6U*9U, 0U, " LeAps");
|
|
BSP_drawNString(0U, 1U, "state-machine.co");</action>
|
|
<choice_glyph conn="18,22,4,-1,-3,7">
|
|
<action box="1,-3,15,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<choice>
|
|
<guard>else</guard>
|
|
<action>BSP_drawNString(6U*9U, 0U, "LeaPs ");
|
|
BSP_drawNString(0U, 1U, "tate-machine.com");</action>
|
|
<choice_glyph conn="18,22,5,-1,7">
|
|
<action box="1,0,6,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="4,22,3,-1,14">
|
|
<action box="0,-2,12,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,14,22,14">
|
|
<entry box="1,2,6,2"/>
|
|
<exit box="1,4,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state name="demo">
|
|
<entry>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_minimal_gap = GAME_SCREEN_HEIGHT - 3U;
|
|
|
|
// erase the tunnel walls
|
|
memset(l_walls, (uint8_t)0,
|
|
(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8U));
|
|
|
|
me->m_blinkTimeEvt.postEvery(me, BSP_TICKS_PER_SEC/2U); // 1/2 sec
|
|
me->m_screenTimeEvt.postIn(me, BSP_TICKS_PER_SEC*20U); // 20 sec
|
|
|
|
me->m_blink_ctr = 0U; // init the blink counter</entry>
|
|
<exit>me->m_blinkTimeEvt.disarm();
|
|
me->m_screenTimeEvt.disarm();</exit>
|
|
<tran trig="BLINK_TIMEOUT">
|
|
<action>me->m_blink_ctr ^= 1U; /* toggle the blink cunter */</action>
|
|
<tran_glyph conn="4,42,3,-1,14">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="SCREEN_TIMEOUT" target="../../5">
|
|
<tran_glyph conn="4,45,3,3,28">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="TIME_TICK">
|
|
<action>me->advance();
|
|
if (me->m_blink_ctr != 0U) {
|
|
// add the text bitmap into the frame buffer
|
|
me->addImageAt(PRESS_BUTTON_BMP,
|
|
(GAME_SCREEN_WIDTH - 55U)/2U,
|
|
(GAME_SCREEN_HEIGHT - 8U)/2U);
|
|
}
|
|
BSP_drawBitmap(l_frame);</action>
|
|
<tran_glyph conn="4,39,3,-1,14">
|
|
<action box="0,-2,12,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="PLAYER_TRIGGER" target="../../6">
|
|
<tran_glyph conn="4,48,3,1,24,6,-2">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,30,22,20">
|
|
<entry box="1,2,6,2"/>
|
|
<exit box="1,4,5,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state name="game_over">
|
|
<entry>me->m_blinkTimeEvt.postEvery(me, BSP_TICKS_PER_SEC/2U); // 1/2 sec
|
|
me->m_screenTimeEvt.postIn(me, BSP_TICKS_PER_SEC*5U); // 5 sec timeout
|
|
me->m_blink_ctr = 0U;
|
|
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*9U)/2U, 0U, "Game Over");</entry>
|
|
<exit>me->m_blinkTimeEvt.disarm();
|
|
me->m_screenTimeEvt.disarm();
|
|
BSP_updateScore(0U); // update the score on the display</exit>
|
|
<tran trig="BLINK_TIMEOUT">
|
|
<action>me->m_blink_ctr ^= 1U; // toggle the blink couner
|
|
BSP_drawNString((GAME_SCREEN_WIDTH - 6U*9U)/2U, 0U,
|
|
((me->m_blink_ctr == 0U)
|
|
? "Game Over"
|
|
: " "));</action>
|
|
<tran_glyph conn="32,80,3,-1,14">
|
|
<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,-19,-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="33,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,4,-4">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state name="screen_saver_hide">
|
|
<entry>BSP_displayOff(); // power down the display
|
|
me->m_screenTimeEvt.postIn(me, BSP_TICKS_PER_SEC*3U); // 3s timeout</entry>
|
|
<exit>me->m_screenTimeEvt.disarm();
|
|
BSP_displayOn(); // power up the display</exit>
|
|
<tran trig="SCREEN_TIMEOUT" target="../../3">
|
|
<tran_glyph conn="34,48,3,1,19,6,-2">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="34,40,17,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->addImageAt(PRESS_BUTTON_BMP,
|
|
(uint8_t)(rnd % (GAME_SCREEN_WIDTH - 55U)),
|
|
(int8_t) (rnd % (GAME_SCREEN_HEIGHT - 8U)));
|
|
BSP_drawBitmap(l_frame);
|
|
me->m_screenTimeEvt.postIn(me, BSP_TICKS_PER_SEC/3U); // 1/3 sec timeout</entry>
|
|
<exit>me->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,21,-15,-4">
|
|
<action box="0,-2,13,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="34,52,17,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 name="playing">
|
|
<entry>static QP::QEvt const takeoff(TAKE_OFF_SIG);
|
|
me->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->POST(&takeoff, me); // post the TAKEOFF sig</entry>
|
|
<exit>static QP::QEvt const recycle(MINE_RECYCLE_SIG);
|
|
me->dispatchToAllMines(&recycle); // recycle all Mines</exit>
|
|
<tran trig="TIME_TICK">
|
|
<action>// render this frame on the display
|
|
BSP_drawBitmap(l_frame);
|
|
me->advance();
|
|
me->plantMine();
|
|
me->dispatchToAllMines(e);</action>
|
|
<tran_glyph conn="4,61,3,-1,14">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="SHIP_IMG">
|
|
<action>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 (me->isWallHit(bmp, x, y)) {
|
|
static QP::QEvt const hit(HIT_WALL_SIG);
|
|
AO_Ship->POST(&hit, me);
|
|
}
|
|
me->addImageAt(bmp, x, y);
|
|
me->dispatchToAllMines(e); // let Mines check for hits</action>
|
|
<tran_glyph conn="4,64,3,-1,14">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="MISSILE_IMG">
|
|
<action>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 (me->isWallHit(bmp, x, y)) {
|
|
static QP::QEvt const hit(HIT_WALL_SIG);
|
|
AO_Missile->POST(&hit, me);
|
|
}
|
|
me->addImageAt(bmp, x, y);
|
|
me->dispatchToAllMines(e); // let Mines check for hits</action>
|
|
<tran_glyph conn="4,67,3,-1,14">
|
|
<action box="0,-2,12,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="MINE_IMG">
|
|
<action>me->addImageAt(Q_EVT_CAST(ObjectImageEvt)->bmp,
|
|
Q_EVT_CAST(ObjectImageEvt)->x,
|
|
Q_EVT_CAST(ObjectImageEvt)->y);</action>
|
|
<tran_glyph conn="4,70,3,-1,14">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="EXPLOSION">
|
|
<action>me->addImageAt(Q_EVT_CAST(ObjectImageEvt)->bmp,
|
|
Q_EVT_CAST(ObjectImageEvt)->x,
|
|
Q_EVT_CAST(ObjectImageEvt)->y);</action>
|
|
<tran_glyph conn="4,73,3,-1,14">
|
|
<action box="0,-2,11,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="SCORE">
|
|
<action>BSP_updateScore(Q_EVT_CAST(ScoreEvt)->score);
|
|
// increase difficulty of the game:
|
|
// the tunnel gets narrower as the score goes up
|
|
//
|
|
me->m_minimal_gap = (uint8_t)(GAME_SCREEN_HEIGHT - 3U
|
|
- Q_EVT_CAST(ScoreEvt)->score/2000U);</action>
|
|
<tran_glyph conn="4,76,3,-1,14">
|
|
<action box="0,-2,6,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="GAME_OVER" target="../../4">
|
|
<action>uint16_t score = Q_EVT_CAST(ScoreEvt)->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, "Score:");
|
|
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,79,3,3,26,-9,2">
|
|
<action box="0,-2,10,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,52,22,29">
|
|
<entry box="1,2,6,2"/>
|
|
<exit box="1,4,5,2"/>
|
|
</state_glyph>
|
|
</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="66,94"/>
|
|
</statechart>
|
|
</class>
|
|
<class name="Ship" superclass="qpcpp::QActive">
|
|
<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="QActive(Q_STATE_CAST(&Ship::initial)), m_x(GAME_SHIP_X), m_y(GAME_SHIP_Y)" visibility="0x00" properties="0x00">
|
|
<code>// empty</code>
|
|
</operation>
|
|
<statechart>
|
|
<initial target="../1">
|
|
<action>me->subscribe(TIME_TICK_SIG);
|
|
me->subscribe(PLAYER_TRIGGER_SIG);
|
|
// object dictionaries...
|
|
QS_OBJ_DICTIONARY(&l_ship);
|
|
// function dictionaries for Ship HSM...
|
|
QS_FUN_DICTIONARY(&Ship::initial);
|
|
QS_FUN_DICTIONARY(&Ship::active);
|
|
QS_FUN_DICTIONARY(&Ship::parked);
|
|
QS_FUN_DICTIONARY(&Ship::flying);
|
|
QS_FUN_DICTIONARY(&Ship::exploding);
|
|
// local signals...
|
|
QS_SIG_DICTIONARY(PLAYER_SHIP_MOVE_SIG, &l_ship);
|
|
QS_SIG_DICTIONARY(TAKE_OFF_SIG, &l_ship);
|
|
QS_SIG_DICTIONARY(HIT_WALL_SIG, &l_ship);
|
|
QS_SIG_DICTIONARY(HIT_MINE_SIG, &l_ship);
|
|
QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, &l_ship);</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->x;\m_y = e->y">me->m_x = Q_EVT_CAST(ObjectPosEvt)->x;
|
|
me->m_y = Q_EVT_CAST(ObjectPosEvt)->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->m_score = 0U; /* reset the score */
|
|
AO_Tunnel->POST(Q_NEW(ScoreEvt, SCORE_SIG, me->m_score), me);</entry>
|
|
<tran trig="TIME_TICK">
|
|
<action>// tell the Tunnel to draw the Ship and test for hits
|
|
AO_Tunnel->POST(Q_NEW(ObjectImageEvt, SHIP_IMG_SIG,
|
|
me->m_x, me->m_y, SHIP_BMP),
|
|
me);
|
|
++me->m_score; // increment the score for surviving another tick
|
|
|
|
if ((me->m_score % 10U) == 0U) { // is the score "round"?
|
|
AO_Tunnel->POST(Q_NEW(ScoreEvt, SCORE_SIG, me->m_score), me);
|
|
}</action>
|
|
<tran_glyph conn="5,33,3,-1,16">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="PLAYER_TRIGGER">
|
|
<action>AO_Missile->POST(Q_NEW(ObjectPosEvt, MISSILE_FIRE_SIG,
|
|
me->m_x, me->m_y + SHIP_HEIGHT - 1U),
|
|
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->m_score += Q_EVT_CAST(ScoreEvt)->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->m_exp_ctr = 0U;</entry>
|
|
<tran trig="TIME_TICK">
|
|
<choice>
|
|
<guard>me->m_exp_ctr < 15U</guard>
|
|
<action>++me->m_exp_ctr;
|
|
// tell the Tunnel to draw the current stage of Explosion
|
|
AO_Tunnel->POST(Q_NEW(ObjectImageEvt, EXPLOSION_SIG,
|
|
me->m_x, (int8_t)((int)me->m_y - 4U + SHIP_HEIGHT),
|
|
EXPLOSION0_BMP + (me->m_exp_ctr >> 2)),
|
|
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>AO_Tunnel->POST(Q_NEW(ScoreEvt, GAME_OVER_SIG, me->m_score), 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::QActive">
|
|
<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="QActive(Q_STATE_CAST(&Missile::initial))" visibility="0x00" properties="0x00">
|
|
<code>// empty</code>
|
|
</operation>
|
|
<statechart>
|
|
<initial target="../1">
|
|
<action>me->subscribe( TIME_TICK_SIG);
|
|
|
|
QS_OBJ_DICTIONARY(&l_missile); // object dictionary for Missile object
|
|
|
|
QS_FUN_DICTIONARY(&Missile::initial); // dictionaries for Missile HSM
|
|
QS_FUN_DICTIONARY(&Missile::armed);
|
|
QS_FUN_DICTIONARY(&Missile::flying);
|
|
QS_FUN_DICTIONARY(&Missile::exploding);
|
|
|
|
QS_SIG_DICTIONARY(MISSILE_FIRE_SIG, &l_missile); // local signals
|
|
QS_SIG_DICTIONARY(HIT_WALL_SIG, &l_missile);
|
|
QS_SIG_DICTIONARY(DESTROYED_MINE_SIG, &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->m_x = Q_EVT_CAST(ObjectPosEvt)->x;
|
|
me->m_y = Q_EVT_CAST(ObjectPosEvt)->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->m_x + GAME_MISSILE_SPEED_X < GAME_SCREEN_WIDTH</guard>
|
|
<action brief="...">me->m_x += GAME_MISSILE_SPEED_X;
|
|
// tell the Tunnel to draw the Missile and test for wall hits
|
|
AO_Tunnel->POST(Q_NEW(ObjectImageEvt, MISSILE_IMG_SIG,
|
|
me->m_x, me->m_y, MISSILE_BMP),
|
|
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->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->m_exp_ctr = 0U;</entry>
|
|
<tran trig="TIME_TICK">
|
|
<choice>
|
|
<guard>(me->m_x >= GAME_SPEED_X) && (me->m_exp_ctr < 15U)</guard>
|
|
<action brief="...">++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
|
|
AO_Tunnel->POST(Q_NEW(ObjectImageEvt, EXPLOSION_SIG,
|
|
me->m_x + 3U,
|
|
(int8_t)((int)me->m_y - 4U),
|
|
EXPLOSION0_BMP + (me->m_exp_ctr >> 2)),
|
|
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::QHsm">
|
|
<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="0x00" properties="0x00"/>
|
|
<operation name="Mine1" type="QHsm(Q_STATE_CAST(&Mine1::initial))" visibility="0x00" properties="0x00">
|
|
<code>// empty</code>
|
|
</operation>
|
|
<statechart>
|
|
<initial target="../1">
|
|
<action>static bool dict_sent = false;
|
|
if (!dict_sent) {
|
|
dict_sent = true;
|
|
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);
|
|
}
|
|
// 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->m_x = Q_EVT_CAST(ObjectPosEvt)->x;
|
|
me->m_y = Q_EVT_CAST(ObjectPosEvt)->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
|
|
AO_Tunnel->POST(Q_NEW(MineEvt, MINE_DISABLED_SIG, MINE_ID(me)), 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->m_exp_ctr = 0U;</entry>
|
|
<tran trig="TIME_TICK">
|
|
<choice>
|
|
<guard brief="still on screen?">(me->m_x >= GAME_SPEED_X) && (me->m_exp_ctr < 15)</guard>
|
|
<action>++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
|
|
AO_Tunnel->POST(Q_NEW(ObjectImageEvt, EXPLOSION_SIG,
|
|
me->m_x + 1U, (int8_t)((int)me->m_y - 4 + 2),
|
|
EXPLOSION0_BMP + (me->m_exp_ctr >> 2)),
|
|
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->m_x >= GAME_SPEED_X</guard>
|
|
<action>me->m_x -= GAME_SPEED_X; // move the mine 1 step
|
|
// tell the Tunnel to draw the Mine
|
|
AO_Tunnel->POST(Q_NEW(ObjectImageEvt, MINE_IMG_SIG,
|
|
me->m_x, me->m_y, MINE1_BMP),
|
|
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)->x;
|
|
uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y;
|
|
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp;</action>
|
|
<choice target="../../../../1">
|
|
<guard brief="collision with MINE1_BMP?">do_bitmaps_overlap(MINE1_BMP, me->m_x, me->m_y, bmp, x, y)</guard>
|
|
<action brief="...">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</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)->x;
|
|
uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y;
|
|
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp;</action>
|
|
<choice target="../../../1">
|
|
<guard brief="collision with MINE1_BMP?">do_bitmaps_overlap(MINE1_BMP, me->m_x, me->m_y, bmp, x, y)</guard>
|
|
<action brief="...">static ScoreEvt const mine1_destroyed(DESTROYED_MINE_SIG, 25U);
|
|
AO_Missile->POST(&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::QHsm">
|
|
<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="0x00" properties="0x00"/>
|
|
<operation name="Mine2" type="QHsm(Q_STATE_CAST(&Mine2::initial))" visibility="0x00" properties="0x00">
|
|
<code>// empty</code>
|
|
</operation>
|
|
<statechart>
|
|
<initial target="../1">
|
|
<action>static bool dict_sent = false;
|
|
if (!dict_sent) {
|
|
dict_sent = true;
|
|
QS_OBJ_DICTIONARY(&l_mine2[0]); // obj. dictionaries for Mine2 pool
|
|
QS_OBJ_DICTIONARY(&l_mine2[1]);
|
|
QS_OBJ_DICTIONARY(&l_mine2[2]);
|
|
QS_OBJ_DICTIONARY(&l_mine2[3]);
|
|
QS_OBJ_DICTIONARY(&l_mine2[4]);
|
|
|
|
QS_FUN_DICTIONARY(&Mine2::initial);// fun. dictionaries for Mine2 HSM
|
|
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);</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->m_x = Q_EVT_CAST(ObjectPosEvt)->x;
|
|
me->m_y = Q_EVT_CAST(ObjectPosEvt)->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
|
|
AO_Tunnel->POST(Q_NEW(MineEvt, MINE_DISABLED_SIG, MINE_ID(me)), 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->m_exp_ctr = 0U;</entry>
|
|
<tran trig="TIME_TICK">
|
|
<choice>
|
|
<guard brief="still on screen?">(me->m_x >= GAME_SPEED_X) && (me->m_exp_ctr < 15)</guard>
|
|
<action>++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
|
|
AO_Tunnel->POST(Q_NEW(ObjectImageEvt, EXPLOSION_SIG,
|
|
me->m_x + 1U, (int8_t)((int)me->m_y - 4 + 2),
|
|
EXPLOSION0_BMP + (me->m_exp_ctr >> 2)),
|
|
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->m_x >= GAME_SPEED_X</guard>
|
|
<action>me->m_x -= GAME_SPEED_X; // move the mine 1 step
|
|
// tell the Tunnel to draw the Mine
|
|
AO_Tunnel->POST(Q_NEW(ObjectImageEvt, MINE_IMG_SIG,
|
|
me->m_x, me->m_y, MINE2_BMP),
|
|
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)->x;
|
|
uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y;
|
|
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp;</action>
|
|
<choice target="../../../../1">
|
|
<guard brief="collision with MINE2_BMP?">do_bitmaps_overlap(MINE2_BMP, me->m_x, me->m_y, bmp, x, y)</guard>
|
|
<action brief="...">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</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)->x;
|
|
uint8_t y = Q_EVT_CAST(ObjectImageEvt)->y;
|
|
uint8_t bmp = Q_EVT_CAST(ObjectImageEvt)->bmp;</action>
|
|
<choice target="../../../1">
|
|
<guard brief="collision with MINE2_MISSILE_BMP?">do_bitmaps_overlap(MINE2_MISSILE_BMP, me->m_x, me->m_y, bmp, x, y)</guard>
|
|
<action brief="...">static ScoreEvt const mine2_destroyed(DESTROYED_MINE_SIG, 45U);
|
|
AO_Missile->POST(&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)
|
|
};
|
|
|
|
$declare(Events::ObjectPosEvt)
|
|
$declare(Events::ObjectImageEvt)
|
|
$declare(Events::MineEvt)
|
|
$declare(Events::ScoreEvt)
|
|
|
|
#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
|
|
};
|
|
|
|
// 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)
|
|
|
|
// obtain instances of the Mines orthogonal components
|
|
QP::QHsm *Mine1_getInst(uint8_t id);
|
|
QP::QHsm *Mine2_getInst(uint8_t id);
|
|
|
|
} // namespace GAME
|
|
|
|
#endif // game_h</text>
|
|
</file>
|
|
<file name="missile.cpp">
|
|
<text>#include "qp_port.h"
|
|
#include "bsp.h"
|
|
#include "game.h"
|
|
|
|
namespace GAME {
|
|
|
|
//Q_DEFINE_THIS_FILE
|
|
|
|
// local objects -------------------------------------------------------------
|
|
$declare(AOs::Missile)
|
|
static Missile l_missile; // the sole instance of the Missile active object
|
|
|
|
// Public-scope objects ------------------------------------------------------
|
|
QP::QActive * const AO_Missile = &l_missile; // opaque pointer
|
|
|
|
// Active object definition --------------------------------------------------
|
|
$define(AOs::Missile)
|
|
|
|
} // namespace GAME</text>
|
|
</file>
|
|
<file name="ship.cpp">
|
|
<text>#include "qp_port.h"
|
|
#include "bsp.h"
|
|
#include "game.h"
|
|
|
|
namespace GAME {
|
|
|
|
//Q_DEFINE_THIS_FILE
|
|
|
|
#define SHIP_WIDTH 5U
|
|
#define SHIP_HEIGHT 3U
|
|
|
|
// 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 ------------------------------------------------------
|
|
QP::QActive * const AO_Ship = &l_ship; // opaque pointer
|
|
|
|
// Active object definition --------------------------------------------------
|
|
$define(AOs::Ship)
|
|
|
|
} // namespace GAME</text>
|
|
</file>
|
|
<file name="tunnel.cpp">
|
|
<text>#include "qp_port.h"
|
|
#include "bsp.h"
|
|
#include "game.h"
|
|
#include <string.h> // for memmove() and memcpy()
|
|
|
|
namespace GAME {
|
|
|
|
Q_DEFINE_THIS_FILE
|
|
|
|
// local objects -------------------------------------------------------------
|
|
$declare(AOs::Tunnel)
|
|
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 = &l_tunnel; // opaque pointer
|
|
|
|
// helper functions ----------------------------------------------------------
|
|
//
|
|
// The bitmap for the "Press Button" 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 "tentacles". 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) }
|
|
};
|
|
|
|
// Active object definition ==================================================
|
|
$define(AOs::Tunnel)
|
|
|
|
//............................................................................
|
|
uint32_t random(void) { // a very cheap pseudo-random-number generator
|
|
// "Super-Duper" 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 >> 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 < Q_DIM(l_bitmap)) && (bmp_id2 < Q_DIM(l_bitmap)));
|
|
|
|
bmp1 = &l_bitmap[bmp_id1];
|
|
bmp2 = &l_bitmap[bmp_id2];
|
|
|
|
// is the incoming object starting to overlap the Mine bitmap?
|
|
if ((x1 <= x2) && (x1 + bmp2->width > x2)) {
|
|
x0 = x2 - x1;
|
|
w = x1 + bmp2->width - x2;
|
|
if (w > bmp1->width) {
|
|
w = bmp1->width;
|
|
}
|
|
for (x = 0; x < w; ++x) { // scan over the overlapping columns
|
|
bits1 = ((uint32_t)bmp2->bits[x + x0] << y2);
|
|
bits2 = ((uint32_t)bmp1->bits[x] << y1);
|
|
if ((bits1 & bits2) != 0) { // do the bits overlap?
|
|
return true; // yes!
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if ((x1 > x2) && (x2 + bmp1->width > x1)) {
|
|
x0 = x1 - x2;
|
|
w = x2 + bmp1->width - x1;
|
|
if (w > bmp2->width) {
|
|
w = bmp2->width;
|
|
}
|
|
for (x = 0; x < w; ++x) { // scan over the overlapping columns
|
|
bits1 = ((uint32_t)bmp1->bits[x + x0] << y1);
|
|
bits2 = ((uint32_t)bmp2->bits[x] << y2);
|
|
if ((bits1 & bits2) != 0U) { // do the bits overlap?
|
|
return true; // yes!
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false; // the bitmaps do not overlap
|
|
}
|
|
|
|
} // namespace GAME</text>
|
|
</file>
|
|
<file name="mine1.cpp">
|
|
<text>#include "qp_port.h"
|
|
#include "bsp.h"
|
|
#include "game.h"
|
|
|
|
namespace GAME {
|
|
|
|
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
|
|
|
|
//............................................................................
|
|
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);
|
|
}
|
|
|
|
// Mine1 class definition ----------------------------------------------------
|
|
$define(AOs::Mine1)
|
|
|
|
} // namespace GAME</text>
|
|
</file>
|
|
<file name="mine2.cpp">
|
|
<text>#include "qp_port.h"
|
|
#include "bsp.h"
|
|
#include "game.h"
|
|
|
|
namespace GAME {
|
|
|
|
Q_DEFINE_THIS_FILE
|
|
|
|
// encapsulated delcaration of the Mine1 HSM ---------------------------------
|
|
$declare(AOs::Mine2)
|
|
|
|
// 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);
|
|
}
|
|
|
|
// Mine1 class definition ----------------------------------------------------
|
|
$define(AOs::Mine2)
|
|
|
|
} // namespace GAME</text>
|
|
</file>
|
|
</directory>
|
|
</model>
|