0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Longan Nanoを使ってみる 13 ~ステージの遷移とゲームオーバー~

Last updated at Posted at 2022-03-07

前の記事

Longan Nanoを使ってみる 12 ~ボールのロス

全体の目次

Longan Nanoを使ってみる 1 ~ビルド環境の構築~
Longan Nanoを使ってみる 2 ~デバッガの環境設定~
 Sipeed RISC-V Debugger
Longan Nanoを使ってみる 3 ~デバッガの使用方法~
Longan Nanoを使ってみる 4 ~printfを使ったデバッグ~
Longan Nanoを使ってみる 5 ~ゲームのプロジェクトを作成~
Longan Nanoを使ってみる 6 ~文字出力~
 Longan Nanoを使ってみる ~FONTX2ファイルを作る~
Longan Nanoを使ってみる 7 ~外枠とブロックを書く~
 Longan Nanoを使ってみる ~謎の画像表示関数~
Longan Nanoを使ってみる 8 ~ボールを動かす~
Longan Nanoを使ってみる 9 ~A/Dコンバータから入力~
Longan Nanoを使ってみる 10 ~パドルを動かす~
Longan Nanoを使ってみる 11 ~ボタンの入力
Longan Nanoを使ってみる 12 ~ボールのロス~
Longan Nanoを使ってみる 13 ~ステージの遷移とゲームオーバー~
Longan Nanoを使ってみる 14 ~PWMとサウンド~
Longan Nanoを使ってみる 15 ~音楽を鳴らす~
Longan Nanoを使ってみる 16 ~とりあえずのまとめ~

はじめに

ここでは、前回の記事の続きとして、ステージを遷移する処理とゲームオーバーの処理を実装する。

ステージの遷移は、ブロックがすべて消えた時に発生するイベントで、ブロックの配置を初期化してゲームを再開させる。ゲームオーバーは、ライフがゼロになったときに発生し、ゲームを終了させてアイドル状態に戻す。

注意

このページは、quiita.com で公開されています。URLがqiita.com以外のサイト、例えばjpdebug.comなどのページでご覧になっている場合、悪質な無許可転載サイトで記事を見ています。正しい記事は、https://qiita.com/BUBUBB/items/7ce85ada67a3f6d1944d からリンクしています。

無許可転載サイトでの権利表記(CC BY SA 2.5、CC BY SA 3.0とCC BY SA 4.0など)は、不当な表示です。
正確な内容は、qiitaのページで参照してください。

ゲームオーバーの実装

ゲームオーバー処理は、基本的にボールのロスとほとんど同じになる。違いは、表示する文字列(--MISS!--ではなく-GAMEOVER-)と、時間経過後の遷移先(STATE_STARTGAMEではなくSTATE_IDLE)だけ。

これを踏まえた実装は次のようになる。 参考用に、STATE_BALLLOSSの処理も含めてある。

game.c

       :
       :
            case STATE_BALLLOSS:{               // ボールロス
                static u16 waitCnt = 0;

                // ライフがないならゲームオーバーに遷移
                if (LifeCnt == 0) {
                    gameState = STATE_GAMEOVER;
                    break;
                }
                // 画面に"-- MISS! --"と表示させる
                LCD_ShowString(5,80,(const unsigned char *)"-- MISS! --",WHITE);
                // 一定時間が経過するか、ボタンが押されたらゲームの再開に遷移する
                waitCnt++;
                if (waitCnt == 0x100 || CheckP1Button()) {
                    LCD_Clear(BLACK);
                    waitCnt = 0;
                    gameState = STATE_STARTGAME;
                }
               break;
            }

            case STATE_GAMEOVER:{
                /*ゲーム-オーバー処理*/
                static u16 waitGameOverCnt = 0;
                // 画面に"-- MISS! --"と表示させる
                LCD_ShowString(5,80,(const unsigned char *)"-GAMEOVER-",WHITE);
                // 一定時間が経過するか、ボタンが押されたらゲームの再開に遷移する
                waitGameOverCnt++;
                if (waitGameOverCnt == 0x100 || CheckP1Button()) {
                    LCD_Clear(BLACK);
                    waitGameOverCnt = 0;
                    gameState = STATE_IDLE;
                }                
                break;
            }
       :
       :      

ステージクリア

ステージ変数の追加

同じように、ステージのクリアも実装することができる。現在、ステージについては全く考慮されていないのでステージの変数を用意して、初期化を行う必要がある。ステージはプログラム内にグローバル変数として用意し、初期化はゲームの開始時(STATE_IDLE→STATE_STARTGAMEへの遷移時)に行えばよいだろう。

現在、ブロックの初期化はblock.c内の InitBlock関数で行われているが、これはステージを意識しておらず、常に同じようにブロックを配置する。ゲーム性を高めるため、ステージごとにブロックの配置を変えられるようにしておく。

とりあえず、簡単のため、ステージに応じて、ブロック配置の最初の位置や段数を変えられるようにしておく。InitBlock関数に引数でステージを受け取り、ブロック配置の開始位置と終了位置をあらかじめテーブルで用意しておく。

game.c

#include "lcd/lcd.h"
#include "led.h"
#include "memory.h"
   :
   :
int LifeCnt = 0;
int Score = 0;
int Stage= 1;                      // ステージ(追加)
         :
         :
            case STATE_IDLE:{
                u16 cnt = heartBeat & 0xFF;
             :
                if (CheckP1Button()) {
                    LCD_Clear(BLACK);
                    Score = 0;
                    LifeCnt = 3;
                    Stage = 1;     // ステージを初期化してゲーム開始(追加)
                    InitBlock(Stage);  // 引数を追加
                    gameState = STATE_STARTGAME;
                }
                break;
            }

block.h

 :
void  InitBlock(int Stage);        // 引数を追加
void DrawBlock();
void blockCheck(struct BALLINFO* bi);
#endif

block.c

// ブロックのテーブルを初期化する
//
void InitBlock(int Stage)
{
	// ステージごとのブロック位置をテーブルで保持
	static int BlockStart[] = {3,4,5,2,2,1,0,0};
	static int BlockEnd[] =   {6,7,8,7,8,9,8,9};

	int stageWork = (Stage-1) & 0x7; // ステージは0~7を繰り返す
    // ブロックテーブルを初期化する。
	memset((void *)blockmtx,0,sizeof(blockmtx));
    blkCnt = 0;

    for (int i = 0;i<BLOCK_CNT_H;i++) {
        for (int j = BlockStart[stageWork];j<BlockEnd[stageWork];j++) {  // 用意されたテーブルに従いブロック配置
            blockmtx[i][j].item = 1;
	        blockmtx[i][j].x1 = i * BLOCK_SIZE_W + (GAMEAREA_X0 + 2);
	        blockmtx[i][j].y1 = j * BLOCK_SIZE_H + (GAMEAREA_Y0 + 2);
	        blockmtx[i][j].x2 = blockmtx[i][j].x1 + BLOCK_SIZE_W  - 2 ;
	        blockmtx[i][j].y2 = blockmtx[i][j].y1 + BLOCK_SIZE_H  - 3 ;            
            blkCnt++;
        }
    }
    blkBrk = blkCnt;
}

ステージクリアの状態を作成

まず、ステージクリアの状態を定義する。Longan Nanoを使ってみる 12 ~ボールのロスで追加したように、ヘッダとゲームのメインに状態を追加する。

game.h

enum GAMESTATE {
	STATE_INIT,			// 初期化処理中
	STATE_IDLE,
	STATE_STARTGAME,	// ゲーム開始(初期化中)
	STATE_INGAME,		// ゲーム中
	STATE_NEXTSTAGE,	// 次のステージに進む (追加)
	STATE_BALLLOSS,		// ボールのロス
	STATE_GAMEOVER,		// ゲームオーバー処理中
};

game.c

    
    while (TRUE) { 
		timer_enable(TIMER5);               // タイマーを有効にする
        // タイマーのウェイト処理。wakeFlagが割り込みルーチン内で1になるまで無限ループする
          :
        switch (gameState) {
            case STATE_INGAME:{
        		drawDeleteBall(FALSE);			// ひとつ前のボールを消す
	            u8 ret= moveBall();
                  :
                  :
                break;                
            }
            case STATE_NEXTSTAGE:{
                /*ここに処理を追加 */
               break;                
            }

ステージクリア処理の実装

ステージクリア処理も、ボールロスやゲームオーバー処理とほとんど同じ。違いは、ほとんど表示する文字列(--MISS!--ではなくWELL DONE!と、時間経過後の遷移先(STATE_STARTGAME)。
ただし、このままSTATE_STARTGAME(ボールロス時の遷移先)に遷移してしまうと、ブロックがない状態でゲームが開始されてしまう。そのため、遷移前にブロックの初期化処理を行う必要がある。

game.c

             :
            case STATE_NEXTSTAGE:{
                static u16 waitNextCnt = 0;

                // 画面に"WELL DONE!"と表示させる
                LCD_ShowString(5,80,(const unsigned char *)"WELL DONE!",WHITE);
                // 一定時間が経過するか、ボタンが押されたらブロックを初期化してゲームの再開に遷移する
                waitNextCnt++;
                if (waitNextCnt == 0x100 || CheckP1Button()) {
                    LCD_Clear(BLACK);
                    waitNextCnt = 0;
                    Stage++;
                    InitBlock(Stage);                    
                    gameState = STATE_STARTGAME;
                }
               break;                
            }
             :

プログラム中、
Stage++;
InitBlock(Stage);
の2行がステージを1つ進めて、ブロックを開始する処理になる。

プログラムのテスト

プログラムを実行すると、ボールを3回ミスすると最初の画面に戻るようになっている。
また、ブロックをすべて消すと、ステージクリアになる。

テストを容易にするため、main.cの中の、Game関数の引数を、TRUE(自動操作)、FALSE(手動操作)に適宜切り替える。

ここまででできたこと

ゲームオーバー時の処理を実装し、さらにステージクリアの際の状態を追加、実装を行った

次の記事に進む

Longan Nanoを使ってみる 14 ~PWMとサウンド1/2~

今回の追加を反映したソースコード

block.h

#ifndef __block_h__
#define __block_h__

// 表示されるブロックの規定値
#define BLOCK_CNT_H	7           // ブロックは横に7個
#define BLOCK_CNT_V 21          // ブロックは縦に最大21個
#define BLOCK_SIZE_W 11         //  ブロックの横幅は11ドット
#define BLOCK_SIZE_H 6          // ブロックの縦は6ドット

// ブロックのテーブル
// 画面上はBLOCK_CNT_H x BLOCK_CNT_Vのマス目に分類され、そこにあるブロックの
// 種類が item に入っている。
// テーブルには、事前にこのブロックが存在する矩形の情報が入っており、ボールとの
// 衝突判定ではこの座標が使われる。
struct BLOCKINFO {
    unsigned char  item;
	unsigned char  x1;
	unsigned char  y1;
	unsigned char  x2;
	unsigned char  y2;
};

//全体のブロック数と、残りのブロック数。ブロックが少なくなったらボールの速度を上げる、などに使用する。
extern int blkCnt;			// 総ブロック数
extern int blkBrk;			// 残りブロック数

void  InitBlock(int Stage);
void DrawBlock();
void blockCheck(struct BALLINFO* bi);
#endif

block.c

#include "lcd/lcd.h"
#include "led.h"
#include "memory.h"
#include "gd32vf103.h"
#include "game.h"
#include "ball.h"
#include "wall.h"
#include "block.h"
#include "paddle.h"


// ブロックのテーブル
// 画面上はBLOCK_CNT_H x BLOCK_CNT_Vのマス目に分類され、そこにあるブロックの
// 種類が item に入っている。
// テーブルには、事前にこのブロックが存在する矩形の情報が入っており、ボールとの
// 衝突判定ではこの座標が使われる。
struct BLOCKINFO blockmtx[BLOCK_CNT_H][BLOCK_CNT_V];

//全体のブロック数と、残りのブロック数。ブロックが少なくなったらボールの速度を上げる、などに使用する。
int blkCnt = 0;			// 総ブロック数
int blkBrk = 0;			// 残りブロック数


// ブロックのテーブルを初期化する
//
void InitBlock(int Stage)
{
	// ステージごとのブロック位置
	static int BlockStart[] = {3,4,5,2,2,1,0,0};
	static int BlockEnd[] =   {6,7,8,7,8,9,8,9};

	int stageWork = (Stage-1) & 0x7; // ステージは0~7を繰り返す
    // ブロックテーブルを初期化する。
	memset((void *)blockmtx,0,sizeof(blockmtx));
    blkCnt = 0;

    for (int i = 0;i<BLOCK_CNT_H;i++) {
        for (int j = BlockStart[stageWork];j<BlockEnd[stageWork];j++) {
            blockmtx[i][j].item = 1;
	        blockmtx[i][j].x1 = i * BLOCK_SIZE_W + (GAMEAREA_X0 + 2);
	        blockmtx[i][j].y1 = j * BLOCK_SIZE_H + (GAMEAREA_Y0 + 2);
	        blockmtx[i][j].x2 = blockmtx[i][j].x1 + BLOCK_SIZE_W  - 2 ;
	        blockmtx[i][j].y2 = blockmtx[i][j].y1 + BLOCK_SIZE_H  - 3 ;            
            blkCnt++;
        }
    }
    blkBrk = blkCnt;
}

// ブロックすべてを描画する
// ブロック崩しでは、ブロックが1つだけ表示される、ということはない(消えていくだけ)ので、
// 表示は無条件で全ブロックを表示させれば良いことになる。
void DrawBlock()
{
	static u16 colTbl[]  = {RED,  BLUE,     GREEN     ,MAGENTA,CYAN,     YELLOW};

	for (u8 i = 0 ; i< BLOCK_CNT_H;i++) {
		for (u8 j = 0; j<BLOCK_CNT_V;j++) {
			u16 col = colTbl[j % 6];
			if (blockmtx[i][j].item == 1) {
				LCD_Fill(blockmtx[i][j].x1,blockmtx[i][j].y1,blockmtx[i][j].x2,blockmtx[i][j].y2,col);
			}
		}
	}
	

}

//
// ブロック反射チェック
// この時点では、BALLINFOの座標は移動済みの座標になっている。
//
void blockCheck(struct BALLINFO* bi)
{
	// 一つ前の座標
	int chkx = CVT_AXIS(bi->oldx);
	int chky = CVT_AXIS(bi->oldy);
	// 座標がある位置のブロック番号を求める
	int xNow = CVT_AXIS(bi->x);
	int yNow = CVT_AXIS(bi->y);
	int xidx = (xNow - (GAMEAREA_X0+2)) /BLOCK_SIZE_W;
	int yidx = (yNow - (GAMEAREA_Y0+2)) / BLOCK_SIZE_H;

	// 現在のボールの位置が、ブロックの中にある場合、衝突処理を行う
	if (blockmtx[xidx][yidx].item != 0 && GetOrthant(xNow,yNow, blockmtx[xidx][yidx].x1 ,blockmtx[xidx][yidx].y1,blockmtx[xidx][yidx].x2,blockmtx[xidx][yidx].y2) == 5) {
		blkBrk--;							// 残ブロック数を1つ減らす
		// ボールの新しい位置は、ブロックの内側なので、座標はひとつ前の位置に戻さないといけない。
		BallBack(bi);

		// 難易度調整
		if (blkBrk <= (blkCnt / 2)) {				// 残ブロックスが全ブロック数の半分以下になったら
			bi->SpeedMask  |= SPDMSK_BLOCKCNT_1;	// スピードレベル1
		} 
		if (blkBrk <= (blkCnt / 4)) {				// 残ブロックスが全ブロック数の1/4分以下になったら
			bi->SpeedMask |= SPDMSK_BLOCKCNT_2;		// スピードレベル2
		}

		// ボールを跳ね返す。
		u8 pos = GetOrthant(chkx,chky, blockmtx[xidx][yidx].x1 ,blockmtx[xidx][yidx].y1,blockmtx[xidx][yidx].x2,blockmtx[xidx][yidx].y2);
		if (pos == 2 || pos== 8) {
            BallSwapY(bi);
		} else if (pos == 4 || pos == 6) {
            BallSwapX(bi);
		} else {
            BallSwapX(bi);
            BallSwapY(bi);
		}

		// ブロックは消す
		blockmtx[xidx][yidx].item = 0;	 
		LCD_Fill(blockmtx[xidx][yidx].x1,blockmtx[xidx][yidx].y1,blockmtx[xidx][yidx].x2,blockmtx[xidx][yidx].y2,BLACK);

		// スコアの処理
		if (bi->SpeedMask & SPDMSK_BACKWALL) {		// 裏に入っていたらスコアは増量
			Score = Score + 2;
		} else {
			Score = Score + 1;
		}
	}
}

game.h

#ifndef __GAME_H__
#define __GAME_H__
extern void Game(bool);

// ゲームの表示領域
#define GAMEAREA_X0   0
#define GAMEAREA_Y0   20
#define GAMEAREA_X1   79
#define GAMEAREA_Y1  148

enum GAMESTATE {
	STATE_INIT,			// 初期化処理中
	STATE_IDLE,
	STATE_STARTGAME,	// ゲーム開始(初期化中)
	STATE_INGAME,		// ゲーム中
	STATE_NEXTSTAGE,	// 次のステージに進む
	STATE_BALLLOSS,		// ボールのロス
	STATE_GAMEOVER,		// ゲームオーバー処理中
};

extern int LifeCnt;
extern int Score;

unsigned char GetOrthant(int x , int y , int x1, int y1 , int x2 , int y2);
#endif

game.c

#include "lcd/lcd.h"
#include "led.h"
#include "memory.h"
#include "gd32vf103.h"
#include "game.h"
#include "ball.h"
#include "block.h"
#include "paddle.h"
#include "button.h"

enum GAMESTATE gameState;	    // ゲームの状態
volatile u8 WakeFlag = 0;       // このフラグが1になると、処理が開始される

int LifeCnt = 0;
int Score = 0;
int Stage= 1;                      // ステージ

//
// 割り込みハンドラ。タイマーにより指定した周期で非同期に呼び出される
//
void TIMER5_IRQHandler(void)
{
    if(SET == timer_interrupt_flag_get(TIMER5, TIMER_INT_FLAG_UP)){
        timer_interrupt_flag_clear(TIMER5, TIMER_INT_FLAG_UP);
    	WakeFlag = 1;
	    
        static u8 oeFlag;
        if (oeFlag == 0) {
            gpio_bit_reset(GPIOB, GPIO_PIN_8); //OE#
            oeFlag = 1;
        } else {
            gpio_bit_set(GPIOB, GPIO_PIN_8); //OE#
            oeFlag = 0;
        }
    }
}

//
// タイマーの初期化
//
void timer5_config(int Cnt)
{
    // タイマーのパラメータを設定する。
	// タイマーの16ビットプリスケーラには54MHzが入力される・・・はずだが、108MHzが入力されるように振舞っている。
	// それを、10000分周(timer_initpara.prescaler = 10000-1)すると、おおよそ108,000,000/10000= 10.8Khz
    // それを、引数の cnt回数えて(timer_initpara.period = Cnt;)タイマーの周期を決める。
	// 例えば、cntが30の時は、10,800 / 30 =360で、360Hzとなる。
    timer_parameter_struct timer_initpara;
    rcu_periph_clock_enable(RCU_TIMER5);
    timer_deinit(TIMER5);
    timer_struct_para_init(&timer_initpara);
    timer_initpara.prescaler         = 10000 - 1;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = Cnt;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_init(TIMER5, &timer_initpara);
    timer_auto_reload_shadow_enable(TIMER5);
    timer_interrupt_enable(TIMER5, TIMER_INT_UP);

    // 割り込みを有効にして、タイマー5を設定する
    eclic_global_interrupt_enable();
	eclic_set_nlbits(ECLIC_GROUP_LEVEL3_PRIO1);
	eclic_irq_enable(TIMER5_IRQn,1,0);
    
    // タイマーを開始する
    timer_enable(TIMER5);
}



// 外枠とスコア、ライフ残を表示する
void DrawBORDER()
{
	LCD_DrawLine(GAMEAREA_X0,GAMEAREA_Y1,GAMEAREA_X0,GAMEAREA_Y0,WHITE);
	LCD_DrawLine(GAMEAREA_X0,GAMEAREA_Y0,GAMEAREA_X1,GAMEAREA_Y0,WHITE);
	LCD_DrawLine(GAMEAREA_X1,GAMEAREA_Y0,GAMEAREA_X1,GAMEAREA_Y1,WHITE);

	LCD_ShowString(0,0,(const u8 *)"SCORE:",WHITE);
	LCD_ShowString(10,160-12,(const u8 *)"LIFE:",WHITE);
	char life[3];
	sprintf(life,"%1d",LifeCnt);
	LCD_ShowString(55,160-12,(u8 *)life,WHITE);
	u8 scr[12];
	sprintf((char *)scr,"%5d0",Score);
	LCD_ShowString(38,0,scr,WHITE);	
}


// 座標が、矩形の外側に対して、どの象限にいるのかを返す関数
//    1         2        3
//        +---------+
//   4    |    5    |    6
//        +---------+
//   7         8         9    
unsigned char GetOrthant(int x , int y , int x1, int y1 , int x2 , int y2)
{
	bool bLowerX1 =  (x < x1);
	bool bUpperX2 =  (x > x2);
	bool bLowerY1 =  (y < y1);
	bool bUpperY2 =  (y > y2);

    
	if (bLowerX1) {
        return bLowerY1 ? 1: (bUpperY2 ? 7:4);
	} else if (bUpperX2) {
        return bLowerY1 ? 3: (bUpperY2 ? 9:6);
	} else {
        return bLowerY1 ? 2: (bUpperY2 ? 8:5);
	}
}


//
// メイン処理
//
void Game(bool isDemo) 
{
    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);	// B8をデバッグに使う

    // 初期化処理
    gameState = STATE_INIT;             // ステータスを初期化にする
    timer5_config(100);                  // タイマーの初期化を行う
    LCD_Init();
    LCD_Clear(BLACK);
	Adc_init();



    u16 tick = 0;                       // LEDを点滅させるためのカウンターを初期化
    gameState = STATE_IDLE;             //初期化処理が終了したのでゲーム開始処理を行う
    static u16 heartBeat = 0;            // 状態遷移ループのカウンタ
    
    while (TRUE) { 
		timer_enable(TIMER5);               // タイマーを有効にする
        // タイマーのウェイト処理。wakeFlagが割り込みルーチン内で1になるまで無限ループする
		
        while(WakeFlag == 0) {
            delay_1ms(10);
            break;
        }

        tick = (tick + 1) & 0x8FFF;     // LEDの点滅用カウンタのインクリメント
		WakeFlag = 0;                   // タイマーのウエイトフラグを初期化する

        heartBeat = (heartBeat+1) & 0x7FFF;
        
        switch (gameState) {
            case STATE_IDLE:{
                u16 cnt = heartBeat & 0xFF;
                if (cnt == 0x00) {
                    LCD_ShowString(5,40,(const unsigned char *)"PUSH BUTTON",WHITE);
                    LCD_ShowString(5,60,(const unsigned char *)" TO START  ",WHITE);
                } else if (cnt == 0x80) {
                    LCD_ShowString(5,40,(const unsigned char *)"PUSH BUTTON",RED);
                    LCD_ShowString(5,60,(const unsigned char *)" TO START  ",RED);
                }
                if (CheckP1Button()) {
                    LCD_Clear(BLACK);
                    Score = 0;
                    LifeCnt = 3;
                    Stage = 1;
                    InitBlock(Stage);
                    gameState = STATE_STARTGAME;
                }
                break;
            }
            case STATE_STARTGAME:{
                /*ゲームの開始処理 */

                DrawBORDER();               //外枠とライフ残、スコアを画面に表示させる
                DrawBlock();
                InitBallPos(0,NULL);
				InitPaddle();
                gameState = STATE_INGAME;
                break;
            }
            case STATE_INGAME:{
        		drawDeleteBall(FALSE);			// ひとつ前のボールを消す
	            u8 ret= moveBall();
	            if (ret == 0) {                 // すべてのボールがなくなったら
                    LifeCnt--;
                    gameState = STATE_BALLLOSS; // ボールロスの状態に遷移させる
                    break;
                } else if (ret == 2) {          // ブロックがすべてなくなったら
                    gameState = STATE_NEXTSTAGE;
                    break;
                }
        		drawDeleteBall(TRUE);			// ひとつ前のボールを消す
				breakout_PaddleCtrl(isDemo);			// パドルを動かす
                break;                
            }
            case STATE_NEXTSTAGE:{
                static u16 waitNextCnt = 0;

                // 画面に"WELL DONE!"と表示させる
                LCD_ShowString(5,80,(const unsigned char *)"WELL DONE!",WHITE);
                // 一定時間が経過するか、ボタンが押されたらブロックを初期化してゲームの再開に遷移する
                waitNextCnt++;
                if (waitNextCnt == 0x100 || CheckP1Button()) {
                    LCD_Clear(BLACK);
                    waitNextCnt = 0;
                    Stage++;
                    InitBlock(Stage);                    
                    gameState = STATE_STARTGAME;
                }
               break;                
            }
            case STATE_BALLLOSS:{               // ボールロス
                static u16 waitCnt = 0;

                // ライフがないならゲームオーバーに遷移
                if (LifeCnt == 0) {
                    gameState = STATE_GAMEOVER;
                    break;
                }
                // 画面に"-- MISS! --"と表示させる
                LCD_ShowString(5,80,(const unsigned char *)"-- MISS! --",WHITE);
                // 一定時間が経過するか、ボタンが押されたらゲームの再開に遷移する
                waitCnt++;
                if (waitCnt == 0x100 || CheckP1Button()) {
                    LCD_Clear(BLACK);
                    waitCnt = 0;
                    gameState = STATE_STARTGAME;
                }
               break;
            }
            case STATE_GAMEOVER:{
                /*ゲーム-オーバー処理*/
                static u16 waitGameOverCnt = 0;
                // 画面に"-- MISS! --"と表示させる
                LCD_ShowString(5,80,(const unsigned char *)"-GAMEOVER-",WHITE);
                // 一定時間が経過するか、ボタンが押されたらゲームの再開に遷移する
                waitGameOverCnt++;
                if (waitGameOverCnt == 0x100 || CheckP1Button()) {
                    LCD_Clear(BLACK);
                    waitGameOverCnt = 0;
                    gameState = STATE_IDLE;
                }                
                break;
            }
        }

    }
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?