ピンポンゲーム(簡易版)。(5)


id:akkera102 さんから頂いたコーディングに対するご指摘を別タイトルにアウトプットしてみるテスト。


最初に謝っておきます。
switch 〜 case での default: に対するアサートはよく分かってないので入れてません。
処理的に nop だから良いんじゃね?という適当さが見てとれます。>ヲレ


昨年春先にシーン遷移学習中に書いてみた、今見ると凄く微妙なコードのリファインです。
ゲーム的にはなーんも変わってないのですが
そのまま NDS サンプルコード置き場に置くのも頂けない出来栄えだったので手直ししてみた次第です。


元ネタは GBDK 本にあったサンプルゲームです。
TeamKNOx さんのとことは別の方のものです。
速度が一定とか角度が一定とか乱数使ってないとかは元ネタ通りなのであしからずです。


C言語超入門 Windowsゲームボーイのプログラムを作ろう!


ピンポンゲームの基本動作はこの本で成程と学習したのですが
ソースの方は良くも悪くも入門書という具合だったのでゲームの挙動以外全て書き直してます。
元ネタがゲームボーイプログラムということでフォントは GBDK 風のものに差し替えてます。


NDS Homebrew 用に利用可能なフォントリソース。(5)
http://d.hatena.ne.jp/dumbo001/20090902/p1


昨年併せて作って公開したダブルスクリーン版は今回同時作業してなかったのでありません。
多分そのうち用意すると思います。


プロジェクト一式はいつも通り以下サイトからダウンロードできます。


Nitro Developer Style
http://page.freett.com/ntr/


Ping Pong


main.c

/*---------------------------------------------------------------------------------
	
	Ping Pong
	
	version 0.01
	Jan 02, 2010
	
	By. REGEKATSU
	
---------------------------------------------------------------------------------*/

#include <nds/ndstypes.h>
#include <nds/interrupts.h>
#include <nds/arm9/input.h>

#include "Bg.h"
#include "Title.h"
#include "Config.h"
#include "Pingpong.h"


typedef enum{
	MAIN_INIT, 
	MAIN_TITLE, 
	MAIN_CONFIG, 
	MAIN_PINGPONG
}MAIN_ACT;

typedef struct{
	u16 act;
}MainStatus;


static MainStatus st_main = {MAIN_INIT};


void main_Init(void);


//---------------------------------------------------------------------------------
int main(void){
//---------------------------------------------------------------------------------
	
	while(1) {
		
		swiWaitForVBlank();
		
		scanKeys();
		
		
		switch(st_main.act){
			
		case MAIN_INIT:
			main_Init();
			st_main.act = MAIN_TITLE;
			break;
			
		case MAIN_TITLE:
			Title_Update();
			
			if(Title_IsExit()){
				st_main.act = MAIN_CONFIG;
			}
			break;
			
		case MAIN_CONFIG:
			Config_Update();
			
			if(Config_IsExit()){
				st_main.act = MAIN_PINGPONG;
			}
			break;
			
		case MAIN_PINGPONG:
			Pingpong_Update();
			
			if(Pingpong_IsExit()){
				st_main.act = MAIN_TITLE;
			}
			break;
			
		default:
			break;
			
		}
		
	}
	
}

//---------------------------------------------------------------------------------
void main_Init(void){
//---------------------------------------------------------------------------------
	
	Bg_Init();
	Pingpong_Clear();
	
}

//---------------------------------------------------------------------------------


Bg.h

/*---------------------------------------------------------------------------------
	
	bg module header
	
	version 0.01
	Jan 02, 2010
	
	By. REGEKATSU
	
---------------------------------------------------------------------------------*/

#ifndef _BG_H_
#define _BG_H_


#ifdef __cplusplus
extern "C" {
#endif


void Bg_Init(void);

void Bg_DrawClear(void);
void Bg_DrawString(int x, int y, char *string);
void Bg_DrawNumber(int x, int y, int number);


#ifdef __cplusplus
}
#endif

#endif	// _BG_H_


Bg.c

/*---------------------------------------------------------------------------------
	
	bg module routine
	
	version 0.01
	Jan 02, 2010
	
	By. REGEKATSU
	
---------------------------------------------------------------------------------*/

#include <stdio.h>
#include <string.h>
#include <nds/arm9/console.h>
#include "Bg.h"
#include "font.h"


typedef struct{
	
	PrintConsole bottom_cons;
	ConsoleFont font;
	
}BgStatus;


static BgStatus st_bg;


//---------------------------------------------------------------------------------
void Bg_Init(void){
//---------------------------------------------------------------------------------
	
	//initStatus
	memset(&st_bg, 0, sizeof(st_bg));
	
	//initConsole
	st_bg.bottom_cons = *consoleDemoInit();
	
	//initConsoleFont
	st_bg.font.gfx = (u16*)fontTiles;
	st_bg.font.bpp = 4;
	st_bg.font.asciiOffset = 0;
	st_bg.font.numChars = 256;
	st_bg.font.convertSingleColor = true;
	
	consoleSetFont(&st_bg.bottom_cons, &st_bg.font);
	
	//initPalette
	BG_PALETTE_SUB[0] = RGB15(31, 31, 31);
	BG_PALETTE_SUB[255] = RGB15(0, 0, 0);
	
	//selectConsole
	consoleSelect(&st_bg.bottom_cons);
	
}


//---------------------------------------------------------------------------------
void Bg_DrawClear(void){
//---------------------------------------------------------------------------------
	
	printf("\x01b[2J");
	
}

//---------------------------------------------------------------------------------
void Bg_DrawString(int x, int y, char *string){
//---------------------------------------------------------------------------------
	
	printf("\x01b[%d;%dH%s", y, x, string);
	
}

//---------------------------------------------------------------------------------
void Bg_DrawNumber(int x, int y, int number){
//---------------------------------------------------------------------------------
	
	printf("\x01b[%d;%dH%d", y, x, number);
	
}

//---------------------------------------------------------------------------------


Title.h

/*---------------------------------------------------------------------------------
	
	title module header
	
	version 0.01
	Jan 02, 2010
	
	By. REGEKATSU
	
---------------------------------------------------------------------------------*/

#ifndef _TITLE_H_
#define _TITLE_H_


#ifdef __cplusplus
extern "C" {
#endif


void Title_Update(void);
bool Title_IsExit(void);


#ifdef __cplusplus
}
#endif

#endif	// _TITLE_H_


Title.c

/*---------------------------------------------------------------------------------
	
	title module routine
	
	version 0.01
	Jan 02, 2010
	
	By. REGEKATSU
	
---------------------------------------------------------------------------------*/

#include <nds/ndstypes.h>
#include "Title.h"
#include "Bg.h"
#include "Pingpong.h"


typedef enum{
	TITLE_INIT, 
	TITLE_EXIT
}TITLE_ACT;

typedef struct{
	u16 act;
}TitleStatus;


static TitleStatus st_title = {TITLE_INIT};


void title_Init(void);
void title_Exit(void);


//---------------------------------------------------------------------------------
void Title_Update(void){
//---------------------------------------------------------------------------------
	
	switch(st_title.act){
		
	case TITLE_INIT:
		title_Init();
		break;
		
	case TITLE_EXIT:
		title_Exit();
		break;
		
	default:
		break;
		
	}
	
}

//---------------------------------------------------------------------------------
void title_Init(void){
//---------------------------------------------------------------------------------
	
	Bg_DrawClear();
	Bg_DrawString(7, 8, "P i n g  P o n g");
	Bg_DrawString(9, 14, "High Score:");
	Bg_DrawNumber(20, 14, Pingpong_GetHighScore());
	
	st_title.act = TITLE_EXIT;
	
}

//---------------------------------------------------------------------------------
void title_Exit(void){
//---------------------------------------------------------------------------------
	
	st_title.act = TITLE_INIT;
	
}

//---------------------------------------------------------------------------------
bool Title_IsExit(void){
//---------------------------------------------------------------------------------
	
	return (st_title.act == TITLE_INIT) ? true : false;
	
}

//---------------------------------------------------------------------------------


Config.h

/*---------------------------------------------------------------------------------
	
	config module header
	
	version 0.01
	Jan 02, 2010
	
	By. REGEKATSU
	
---------------------------------------------------------------------------------*/

#ifndef _CONFIG_H_
#define _CONFIG_H_


#ifdef __cplusplus
extern "C" {
#endif


void Config_Update(void);
bool Config_IsExit(void);


#ifdef __cplusplus
}
#endif

#endif	// _CONFIG_H_


Config.c

/*---------------------------------------------------------------------------------
	
	config module routine
	
	version 0.01
	Jan 02, 2010
	
	By. REGEKATSU
	
---------------------------------------------------------------------------------*/

#include <nds/ndstypes.h>
#include <nds/arm9/input.h>
#include "Config.h"
#include "Bg.h"
#include "Pingpong.h"


#define CONFIG_POS_X 13
#define CONFIG_POS_Y 10


typedef enum{
	CONFIG_INIT,
	CONFIG_EXEC,
	CONFIG_EXIT
}CONFIG_ACT;

typedef struct{
	u16 act;
}ConfigStatus;


static ConfigStatus st_config = {CONFIG_INIT};


void config_Init(void);
void config_Exec(void);
void config_Exit(void);
void config_SelectLevel(void);


//---------------------------------------------------------------------------------
void Config_Update(void){
//---------------------------------------------------------------------------------
	
	switch(st_config.act){
		
	case CONFIG_INIT:
		config_Init();
		break;
		
	case CONFIG_EXEC:
		config_Exec();
		break;
		
	case CONFIG_EXIT:
		config_Exit();
		break;
		
	default:
		break;
		
	}
	
}

//---------------------------------------------------------------------------------
void config_Init(void){
//---------------------------------------------------------------------------------
	
	int level;
	
	Pingpong_ClearLevel();
	level = Pingpong_GetLevel();
	
	Bg_DrawString(CONFIG_POS_X, CONFIG_POS_Y    , "easy");
	Bg_DrawString(CONFIG_POS_X, CONFIG_POS_Y + 1, "normal");
	Bg_DrawString(CONFIG_POS_X, CONFIG_POS_Y + 2, "hard");
	Bg_DrawString(CONFIG_POS_X - 1, CONFIG_POS_Y + level, "*");
	
	st_config.act = CONFIG_EXEC;
	
}

//---------------------------------------------------------------------------------
void config_Exec(void){
//---------------------------------------------------------------------------------
	
	if(keysDown() & KEY_SELECT){
		config_SelectLevel();
		
	}else if(keysDown() & KEY_START){
		st_config.act = CONFIG_EXIT;
		
	}
	
}

//---------------------------------------------------------------------------------
void config_Exit(void){
//---------------------------------------------------------------------------------
	
	st_config.act = CONFIG_INIT;
	
}

//---------------------------------------------------------------------------------
void config_SelectLevel(void){
//---------------------------------------------------------------------------------
	
	int level;
	
	level = Pingpong_GetLevel();
	Bg_DrawString(CONFIG_POS_X - 1, CONFIG_POS_Y + level, " ");
	
	Pingpong_IncLevel();
	level = Pingpong_GetLevel();
	Bg_DrawString(CONFIG_POS_X - 1, CONFIG_POS_Y + level, "*");
	
}

//---------------------------------------------------------------------------------
bool Config_IsExit(void){
//---------------------------------------------------------------------------------
	
	return (st_config.act == CONFIG_INIT) ? true : false;
	
}

//---------------------------------------------------------------------------------


Pingpong.h

/*---------------------------------------------------------------------------------
	
	pingpong module header
	
	version 0.01
	Jan 02, 2010
	
	By. REGEKATSU
	
---------------------------------------------------------------------------------*/

#ifndef _PINGPONG_H_
#define _PINGPONG_H_


#ifdef __cplusplus
extern "C" {
#endif


void Pingpong_Clear(void);
void Pingpong_Update(void);
bool Pingpong_IsExit(void);

int Pingpong_GetHighScore(void);

int Pingpong_GetLevel(void);
void Pingpong_IncLevel(void);
void Pingpong_ClearLevel(void);


#ifdef __cplusplus
}
#endif

#endif	// _PINGPONG_H_


Pingpong.c

/*---------------------------------------------------------------------------------
	
	pingpong module routine
	
	version 0.01
	Jan 02, 2010
	
	By. REGEKATSU
	
---------------------------------------------------------------------------------*/

#include <string.h>
#include <nds/ndstypes.h>
#include <nds/arm9/input.h>
#include "Pingpong.h"
#include "Bg.h"


#define CONSOLE_WIDTH_MIN 0
#define CONSOLE_WIDTH_MAX 31
#define CONSOLE_HEIGHT_MIN 0
#define CONSOLE_HEIGHT_MAX 23

#define PADDLE_WIDTH_MIN 1
#define PADDLE_WIDTH_MAX 3

#define LEVEL_MIN 0
#define LEVEL_MAX 2


typedef enum{
	PINGPONG_INIT, 
	PINGPONG_BEGINE, 
	PINGPONG_EXEC, 
	PINGPONG_MISS, 
	PINGPONG_END, 
	PINGPONG_EXIT
}PINGPONG_ACT;

typedef struct{
	
	u16 act;
	
	u32 wait;
	
	int ball;	// 持ちボール数
	int score;	// スコア
	int high_score;	// ハイスコア
	
	int px;	// パドルX座標
	int py;	// パドルY座標
	int bx;	// ボールX座標
	int by;	// ボールY座標
	int dx;	// ボールX移動方向
	int dy;	// ボールY移動方向
	
	int level;	// ゲームレベル
	
}PingpongStatus;


static PingpongStatus st_pingpong;


#define WAIT_RATE(x) (3-(x))


void pingpong_Init(void);
void pingpong_Begine(void);
void pingpong_Exec(void);
void pingpong_Miss(void);
void pingpong_End(void);
void pingpong_Exit(void);

void pingpong_ExecPaddle(void);
void pingpong_ExecBall(void);
void pingpong_ExecStatus(void);

bool pingpong_IsExecBall(void);
bool pingpong_IsMiss(void);
bool pingpong_IsEnd(void);


//---------------------------------------------------------------------------------
void Pingpong_Clear(void){
//---------------------------------------------------------------------------------
	
	memset(&st_pingpong, 0, sizeof(st_pingpong));
	
}

//---------------------------------------------------------------------------------
void Pingpong_Update(void){
//---------------------------------------------------------------------------------
		
		switch(st_pingpong.act){
			
		case PINGPONG_INIT:
			pingpong_Init();
			break;
			
		case PINGPONG_BEGINE:
			pingpong_Begine();
			break;
			
		case PINGPONG_EXEC:
			pingpong_Exec();
			break;
			
		case PINGPONG_MISS:
			pingpong_Miss();
			break;
			
		case PINGPONG_END:
			pingpong_End();
			break;
			
		case PINGPONG_EXIT:
			pingpong_Exit();
			break;
			
		default:
			break;
			
		}
	
}

//---------------------------------------------------------------------------------
void pingpong_Init(void){
//---------------------------------------------------------------------------------
	
	st_pingpong.ball = 3;
	st_pingpong.score = 0;
	st_pingpong.wait = WAIT_RATE(st_pingpong.level);
	Bg_DrawClear();
	
	st_pingpong.act = PINGPONG_BEGINE;
	
}

//---------------------------------------------------------------------------------
void pingpong_Begine(void){
//---------------------------------------------------------------------------------
	
	st_pingpong.px = 15;
	st_pingpong.py = 21;
	st_pingpong.bx = 5;
	st_pingpong.by = 5;
	st_pingpong.dx = 1;
	st_pingpong.dy = 1;
	Bg_DrawClear();
	
	st_pingpong.act = PINGPONG_EXEC;
	
}

//---------------------------------------------------------------------------------
void pingpong_Exec(void){
//---------------------------------------------------------------------------------
	
	if(st_pingpong.wait != 0){
		st_pingpong.wait--;
		return;
	}
	
	st_pingpong.wait = WAIT_RATE(st_pingpong.level);
	
	//バドルの更新。
	pingpong_ExecPaddle();
	
	//ボールの更新。
	// パドルが2フレーム更新する最中、ボールは1フレーム更新させる。
	// (ボールよりパドルが早く動けるようにする。)
	if(pingpong_IsExecBall()){
		pingpong_ExecBall();
	}
	
	//ステータスの更新。
	pingpong_ExecStatus();
	
	//ゲームミスの確認。
	if(pingpong_IsMiss()){
		Bg_DrawString(14, 11, "miss");
		st_pingpong.wait = 60;
		st_pingpong.act = PINGPONG_MISS;
	}
	
}

//---------------------------------------------------------------------------------
void pingpong_Miss(void){
//---------------------------------------------------------------------------------
	
	if(st_pingpong.wait != 0){
		st_pingpong.wait--;
		return;
	}
	
	st_pingpong.ball--;
	
	//ゲームオーバーの確認。
	if(pingpong_IsEnd()){
		
		Bg_DrawClear();
		Bg_DrawString(10, 11, "Game Over!!");
		st_pingpong.wait = 180;
		st_pingpong.act = PINGPONG_END;
		
	}else{
		
		st_pingpong.act = PINGPONG_BEGINE;
		
	}
	
}

//---------------------------------------------------------------------------------
void pingpong_End(void){
//---------------------------------------------------------------------------------
	
	if(st_pingpong.wait != 0){
		st_pingpong.wait--;
		return;
	}
	
	st_pingpong.act = PINGPONG_EXIT;
	
}

//---------------------------------------------------------------------------------
void pingpong_Exit(void){
//---------------------------------------------------------------------------------
	
	st_pingpong.act = PINGPONG_INIT;
	
}

//---------------------------------------------------------------------------------
void pingpong_ExecPaddle(void){
//---------------------------------------------------------------------------------
	
	//前回のパドル画像を消去。
	Bg_DrawString(st_pingpong.px, st_pingpong.py, "   ");
	
	//現在のパドル位置を更新。
	if(keysHeld() & KEY_LEFT){
		
		if(st_pingpong.px > CONSOLE_WIDTH_MIN)
			st_pingpong.px--;
		
	}else if(keysHeld() &KEY_RIGHT){
		
		if(st_pingpong.px <= CONSOLE_WIDTH_MAX - PADDLE_WIDTH_MAX)
			st_pingpong.px++;
		
	}
	
	//現在のパドル画像を描画。
	Bg_DrawString(st_pingpong.px, st_pingpong.py, "---");
	
}

//---------------------------------------------------------------------------------
void pingpong_ExecBall(void){
//---------------------------------------------------------------------------------
	
	//ボールの移動。
	
	//ボールが画面左端の場合、移動方向を右へ変更する。
	if(st_pingpong.bx <= CONSOLE_WIDTH_MIN){
		st_pingpong.dx = -st_pingpong.dx;
		
	}
	//ボールが画面右端の場合、移動方向を左へ変更する。
	else if(st_pingpong.bx >= CONSOLE_WIDTH_MAX){
		st_pingpong.dx = -st_pingpong.dx;
		
	}
	//ボールが画面上端の場合、移動方向を下へ変更する。
	else if(st_pingpong.by <= CONSOLE_HEIGHT_MIN){
		st_pingpong.dy = -st_pingpong.dy;
		
	}
	
	
	//ボールとパドルの当り判定。
	
	if( st_pingpong.by == st_pingpong.py - 1 ){
		
		//ボールがパドルに当たった場合、移動方向を上へ変更する。
		if( (st_pingpong.bx >= st_pingpong.px -1) && (st_pingpong.bx <= st_pingpong.px + PADDLE_WIDTH_MAX) ){
			
			st_pingpong.dy = -st_pingpong.dy;
			
			//スコアの加算。
			st_pingpong.score++;
			
			//ハイスコアの更新。
			if(st_pingpong.score > st_pingpong.high_score){
				st_pingpong.high_score = st_pingpong.score;
			}
			
		}
		
	}
	
	
	//ボールの描画。
	
	//前回のボール画像を消去。
	Bg_DrawString(st_pingpong.bx, st_pingpong.by, " ");
	
	//現在のボール位置を更新。
	st_pingpong.bx += st_pingpong.dx;
	st_pingpong.by += st_pingpong.dy;
	
	//現在のボール画像を描画。
	Bg_DrawString(st_pingpong.bx, st_pingpong.by, "O");
	
}

//---------------------------------------------------------------------------------
void pingpong_ExecStatus(void){
//---------------------------------------------------------------------------------
	
	Bg_DrawString(0, 23, "ball:");
	Bg_DrawNumber(5, 23, st_pingpong.ball);
	
	Bg_DrawString(8, 23, "score:");
	Bg_DrawNumber(14, 23, st_pingpong.score);
	
}

//---------------------------------------------------------------------------------
bool pingpong_IsExecBall(void){
//---------------------------------------------------------------------------------
	
	static u32 i = 0;
	
	i++;
	
	return (i % 2 == 0) ? true:false;
	
}

//---------------------------------------------------------------------------------
bool pingpong_IsMiss(void){
//---------------------------------------------------------------------------------
	
	return (st_pingpong.by > st_pingpong.py) ? true : false;
	
}


//---------------------------------------------------------------------------------
bool pingpong_IsEnd(void){
//---------------------------------------------------------------------------------
	
	return (st_pingpong.ball <= 0) ? true : false;
	
}

//---------------------------------------------------------------------------------
bool Pingpong_IsExit(void){
//---------------------------------------------------------------------------------
	
	return (st_pingpong.act == PINGPONG_INIT) ? true : false;
	
}

//---------------------------------------------------------------------------------
int Pingpong_GetHighScore(void){
//---------------------------------------------------------------------------------
	
	return st_pingpong.high_score;
	
}

//---------------------------------------------------------------------------------
int Pingpong_GetLevel(void){
//---------------------------------------------------------------------------------
	
	return st_pingpong.level;
	
}

//---------------------------------------------------------------------------------
void Pingpong_IncLevel(void){
//---------------------------------------------------------------------------------
	
	if(st_pingpong.level < LEVEL_MAX){
		st_pingpong.level++;
		
	}else if(st_pingpong.level >= LEVEL_MAX){
		st_pingpong.level = LEVEL_MIN;
	}
	
}

//---------------------------------------------------------------------------------
void Pingpong_ClearLevel(void){
//---------------------------------------------------------------------------------
	
	st_pingpong.level = LEVEL_MIN;
	
}

//---------------------------------------------------------------------------------