📄 tunnel.c
字号:
/****************************************************************************** Product: "Fly'n'Shoot" game example* Last Updated for Version: 4.0.00* Date of the Last Update: Apr 06, 2008** Q u a n t u m L e a P s* ---------------------------* innovating embedded systems** Copyright (C) 2002-2008 Quantum Leaps, LLC. All rights reserved.** This software may be distributed and modified under the terms of the GNU* General Public License version 2 (GPL) as published by the Free Software* Foundation and appearing in the file GPL.TXT included in the packaging of* this file. Please note that GPL Section 2[b] requires that all works based* on this software must also be made publicly available under the terms of* the GPL ("Copyleft").** Alternatively, this software may be distributed and modified under the* terms of Quantum Leaps commercial licenses, which expressly supersede* the GPL and are specifically designed for licensees interested in* retaining the proprietary status of their code.** Contact information:* Quantum Leaps Web site: http://www.quantum-leaps.com* e-mail: info@quantum-leaps.com*****************************************************************************/#include "qp_port.h"#include "game.h"#include "bsp.h"#include <string.h> /* for memmove() and memcpy() */Q_DEFINE_THIS_FILE/* Tunnel Active Object ....................................................*/typedef struct TunnelTag { QActive super; /* extend the QActive class */ QTimeEvt blinkTimeEvt; /* time event for blinking */ QTimeEvt screenTimeEvt; /* time event for screen changes */ QHsm *mines[GAME_MINES_MAX]; /* active mines */ QHsm *mine1_pool[GAME_MINES_MAX]; QHsm *mine2_pool[GAME_MINES_MAX]; uint8_t blink_ctr; /* blink counter */ uint8_t last_mine_x; uint8_t last_mine_y; uint8_t wall_thickness_top; uint8_t wall_thickness_bottom; uint8_t minimal_gap;} Tunnel; /* the Tunnel active object */static QState Tunnel_initial (Tunnel *me, QEvent const *e);static QState Tunnel_final (Tunnel *me, QEvent const *e);static QState Tunnel_active (Tunnel *me, QEvent const *e);static QState Tunnel_playing (Tunnel *me, QEvent const *e);static QState Tunnel_demo (Tunnel *me, QEvent const *e);static QState Tunnel_game_over (Tunnel *me, QEvent const *e);static QState Tunnel_screen_saver (Tunnel *me, QEvent const *e);static QState Tunnel_screen_saver_n_pixels(Tunnel *me, QEvent const *e);static QState Tunnel_screen_saver_1_pixel (Tunnel *me, QEvent const *e);/* Helper functions ........................................................*/static void Tunnel_advance(Tunnel *me);static void Tunnel_plantMine(Tunnel *me);static void Tunnel_addImageAt(Tunnel *me, uint8_t bmp, uint8_t x, int8_t y);static void Tunnel_dispatchToAllMines(Tunnel *me, QEvent const *e);static uint8_t Tunnel_isWallHit(Tunnel *me, uint8_t bmp, uint8_t x_pos, uint8_t y_pos);static void randomSeed(uint32_t seed);static uint32_t random(void);static Tunnel l_tunnel; /* the sole instance of the Tunnel active object *//* global objects ----------------------------------------------------------*/QActive * const AO_Tunnel = (QActive *)&l_tunnel;/*opaque pointer to Tunnel *//* local objects -----------------------------------------------------------*/static uint32_t l_rnd; /* random seed */static uint8_t l_walls[GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8];static uint8_t l_frame[GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8];/*..........................................................................*/void Tunnel_ctor(void) { uint8_t n; Tunnel *me = &l_tunnel; QActive_ctor(&me->super, (QStateHandler)&Tunnel_initial); QTimeEvt_ctor(&me->blinkTimeEvt, BLINK_TIMEOUT_SIG); QTimeEvt_ctor(&me->screenTimeEvt, SCREEN_TIMEOUT_SIG); for (n = 0; n < GAME_MINES_MAX; ++n) { me->mine1_pool[n] = Mine1_ctor(n); /* instantiate Mine1 in the pool */ me->mine2_pool[n] = Mine2_ctor(n); /* instantiate Mine2 in the pool */ me->mines[n] = (QHsm *)0; /* mine 'n' is unused */ } me->last_mine_x = 0; /* the last mine at the right edge of the tunnel */ me->last_mine_y = 0;}/* HSM definition ----------------------------------------------------------*//*..........................................................................*/QState Tunnel_initial(Tunnel *me, QEvent const *e) { uint8_t n; (void)e; /* avoid the "unreferenced parameter" warning */ for (n = 0; n < GAME_MINES_MAX; ++n) { QHsm_init(me->mine1_pool[n], (QEvent *)0);/*initial tran. for Mine1 */ QHsm_init(me->mine2_pool[n], (QEvent *)0);/*initial tran. for Mine2 */ } randomSeed(1234); /* seed the pseudo-random generator */ QActive_subscribe((QActive *)me, TIME_TICK_SIG); QActive_subscribe((QActive *)me, PLAYER_TRIGGER_SIG); QActive_subscribe((QActive *)me, PLAYER_QUIT_SIG); QS_OBJ_DICTIONARY(&l_tunnel); /* object dictionary for Tunnel object */ QS_OBJ_DICTIONARY(&l_tunnel.blinkTimeEvt); QS_OBJ_DICTIONARY(&l_tunnel.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_n_pixels); QS_FUN_DICTIONARY(&Tunnel_screen_saver_1_pixel); 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); return Q_TRAN(&Tunnel_demo);}/*..........................................................................*/QState Tunnel_final(Tunnel *me, QEvent const *e) { (void)me; /* avoid compiler warning */ switch (e->sig) { case Q_ENTRY_SIG: { /* clear the screen */ memset(l_frame, (uint8_t)0, (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8)); BSP_drawBitmap(l_frame, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT); QF_stop(); /* stop QF and cleanup */ return Q_HANDLED(); } } return Q_SUPER(&QHsm_top);}/*..........................................................................*/QState Tunnel_active(Tunnel *me, QEvent const *e) { switch (e->sig) { case MINE_DISABLED_SIG: { Q_ASSERT((((MineEvt const *)e)->id < GAME_MINES_MAX) && (me->mines[((MineEvt const *)e)->id] != (QHsm *)0)); me->mines[((MineEvt const *)e)->id] = (QHsm *)0; return Q_HANDLED(); } case PLAYER_QUIT_SIG: { return Q_TRAN(&Tunnel_final); } } return Q_SUPER(&QHsm_top);}/*..........................................................................*/QState Tunnel_demo(Tunnel *me, QEvent const *e) { switch (e->sig) { case Q_ENTRY_SIG: { me->last_mine_x = 0; /* last mine at right edge of the tunnel */ me->last_mine_y = 0; /* set the tunnel properties... */ me->wall_thickness_top = 0; me->wall_thickness_bottom = 0; me->minimal_gap = GAME_SCREEN_HEIGHT - 3; /* erase the tunnel walls */ memset(l_walls, (uint8_t)0, (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8)); QTimeEvt_postEvery(&me->blinkTimeEvt, (QActive *)me, BSP_TICKS_PER_SEC/2); /* every 1/2 sec */ QTimeEvt_postIn(&me->screenTimeEvt, (QActive *)me, BSP_TICKS_PER_SEC*20); /* 20s timeout */ me->blink_ctr = 0; /* init the blink counter */ return Q_HANDLED(); } case Q_EXIT_SIG: { QTimeEvt_disarm(&me->blinkTimeEvt); QTimeEvt_disarm(&me->screenTimeEvt); return Q_HANDLED(); } case BLINK_TIMEOUT_SIG: { me->blink_ctr ^= 1; /* toggle the blink cunter */ return Q_HANDLED(); } case SCREEN_TIMEOUT_SIG: { return Q_TRAN(&Tunnel_screen_saver); } case TIME_TICK_SIG: { Tunnel_advance(me); if (me->blink_ctr != 0) { /* add the text bitmap into the frame buffer */ Tunnel_addImageAt(me, PRESS_BUTTON_BMP, (GAME_SCREEN_WIDTH - 55)/2, (GAME_SCREEN_HEIGHT - 8)/2); } BSP_drawBitmap(l_frame, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT); return Q_HANDLED(); } case PLAYER_TRIGGER_SIG: { return Q_TRAN(&Tunnel_playing); } } return Q_SUPER(&Tunnel_active);}/*..........................................................................*/QState Tunnel_game_over(Tunnel *me, QEvent const *e) { switch (e->sig) { case Q_ENTRY_SIG: { QTimeEvt_postEvery(&me->blinkTimeEvt, (QActive *)me, BSP_TICKS_PER_SEC/2); /* 1/2 sec */ QTimeEvt_postIn(&me->screenTimeEvt, (QActive *)me, BSP_TICKS_PER_SEC*5); /* 5 sec timeout */ me->blink_ctr = 0; BSP_drawNString((GAME_SCREEN_WIDTH - 6*9)/2, 0, "Game Over"); return Q_HANDLED(); } case Q_EXIT_SIG: { QTimeEvt_disarm(&me->blinkTimeEvt); QTimeEvt_disarm(&me->screenTimeEvt); BSP_updateScore(0); /* update the score on the display */ return Q_HANDLED(); } case BLINK_TIMEOUT_SIG: { me->blink_ctr ^= 1; /* toggle the blink couner */ BSP_drawNString((GAME_SCREEN_WIDTH - 6*9)/2, 0, ((me->blink_ctr == 0) ? "Game Over" : " ")); return Q_HANDLED(); } case SCREEN_TIMEOUT_SIG: { return Q_TRAN(&Tunnel_demo); } } return Q_SUPER(&Tunnel_active);}/*..........................................................................*/QState Tunnel_playing(Tunnel *me, QEvent const *e) { uint8_t x; int8_t y; uint8_t bmp; switch (e->sig) { case Q_ENTRY_SIG: { static QEvent const takeoff = { TAKE_OFF_SIG, 0 }; me->minimal_gap = GAME_SCREEN_HEIGHT - 3; /* erase the walls */ memset(l_walls, (uint8_t)0, (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8)); QActive_postFIFO(AO_Ship, &takeoff); /* post the TAKEOFF sig */ return Q_HANDLED(); } case Q_EXIT_SIG: { QEvent recycle; recycle.sig = MINE_RECYCLE_SIG; Tunnel_dispatchToAllMines(me, &recycle); /* recycle all Mines */ return Q_HANDLED(); } case TIME_TICK_SIG: { /* render this frame on the display */ BSP_drawBitmap(l_frame, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT); Tunnel_advance(me); Tunnel_plantMine(me); Tunnel_dispatchToAllMines(me, e); return Q_HANDLED(); } case SHIP_IMG_SIG: case MISSILE_IMG_SIG: { x = (uint8_t)((ObjectImageEvt const *)e)->x; y = (int8_t)((ObjectImageEvt const *)e)->y; bmp = (uint8_t)((ObjectImageEvt const *)e)->bmp; /* did the Ship/Missile hit the tunnel wall? */ if (Tunnel_isWallHit(me, bmp, x, y)) { QEvent const hit = { HIT_WALL_SIG, 0}; if (e->sig == SHIP_IMG_SIG) { QActive_postFIFO(AO_Ship, &hit); } else { QActive_postFIFO(AO_Missile, &hit); } } Tunnel_addImageAt(me, bmp, x, y); Tunnel_dispatchToAllMines(me, e); /* let Mines check for hits */ return Q_HANDLED(); } case MINE_IMG_SIG: case EXPLOSION_SIG: { x = (uint8_t)((ObjectImageEvt const *)e)->x; y = (int8_t)((ObjectImageEvt const *)e)->y; bmp = (uint8_t)((ObjectImageEvt const *)e)->bmp; Tunnel_addImageAt(me, bmp, x, y); return Q_HANDLED(); } case SCORE_SIG: { BSP_updateScore(((ScoreEvt const *)e)->score); /* increase difficulty of the game: * the tunnel gets narrower as the score goes up */ me->minimal_gap = GAME_SCREEN_HEIGHT - 3 - ((ScoreEvt const *)e)->score/2000; return Q_HANDLED(); } case GAME_OVER_SIG: { uint16_t score = ((ScoreEvt const *)e)->score; char str[5]; BSP_updateScore(score); /* clear the screen */ memset(l_frame, (uint8_t)0, (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8)); BSP_drawBitmap(l_frame, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT); /* Output the final score to the screen */ BSP_drawNString((GAME_SCREEN_WIDTH - 6*10)/2, 1, "Score:"); str[4] = '\0'; /* zero-terminate the string */ str[3] = '0' + (score % 10); score /= 10; str[2] = '0' + (score % 10); score /= 10; str[1] = '0' + (score % 10); score /= 10; str[0] = '0' + (score % 10); BSP_drawNString((GAME_SCREEN_WIDTH - 6*10)/2 + 6*6, 1, str); return Q_TRAN(&Tunnel_game_over); } } return Q_SUPER(&Tunnel_active);}/*..........................................................................*//* A random-pixel screen saver to avoid damage to the display */QState Tunnel_screen_saver(Tunnel *me, QEvent const *e) { switch (e->sig) { case Q_INIT_SIG: { return Q_TRAN(&Tunnel_screen_saver_n_pixels); } case PLAYER_TRIGGER_SIG: { return Q_TRAN(&Tunnel_demo); } } return Q_SUPER(&Tunnel_active);}/*..........................................................................*/QState Tunnel_screen_saver_n_pixels(Tunnel *me, QEvent const *e) { switch (e->sig) { case Q_ENTRY_SIG: { QTimeEvt_postIn(&me->screenTimeEvt, (QActive *)me, BSP_TICKS_PER_SEC*60); /* 60s timeout */ /* clear the screen */ memset(l_frame, (uint8_t)0, (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8)); return Q_HANDLED(); } case Q_EXIT_SIG: { QTimeEvt_disarm(&me->screenTimeEvt); return Q_HANDLED(); } case SCREEN_TIMEOUT_SIG: { return Q_TRAN(&Tunnel_screen_saver_1_pixel); } case TIME_TICK_SIG: { uint8_t n = 4; /* generate 4 random pixels on the display */ while ((n--) != 0) { uint32_t rnd = random(); l_frame[rnd % (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT/8)] = (uint8_t)(1 << ((rnd >> 8) & 0x7)); } BSP_drawBitmap(l_frame, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT); return Q_HANDLED(); } } return Q_SUPER(&Tunnel_screen_saver);}/*..........................................................................*/QState Tunnel_screen_saver_1_pixel(Tunnel *me, QEvent const *e) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -