トップページに戻る / GCCページに戻る / SDL目次


13 戦闘画面 準備

第11章までで、おっさんに話しかけるところまでできるようになりました。あとは、RPG上のイベントですが、おっさんに話しかけた時に戦闘開始というイベントを作ることを目標に、しばらくフィールドが面から離れて、戦闘画面を作っていきます。

RPGといえば戦闘が華。戦闘画面ができれば一応RPGとしての骨格が出来上がったといえるのではないでしょうか。

戦闘画面はフィールド画面と操作内容等全然違うので新たにソースコードを書きます。最終的には合体させますが。

レイヤーの考え方はこちらでも使えるので、レイヤー構造体、及びレイヤー処理関数は流用します。

戦闘画面は、味方キャラを書くのが面倒なのでサイドビューではなくフロント形式にします。

サンプルプログラムの敵キャラは、このサイトで最強の攻撃力を持つ彼にしましょう。

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>

/* ウインドウ設定 */
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
#define BPP 32

/* フォント設定 */
#define FONT_NAME "ipag-mona.ttf"
#define FONT_SIZE 24

/* 共通フォント */
TTF_Font *font;

/* 色 */
const SDL_Color color_black = {0x00, 0x00, 0x00};

/* レイヤー構造体 */
typedef struct{
	SDL_Surface *surface;	/* サーフェス */
	int use;		/* 使用有無 */
	int visible;		/* 表示有無 */
	SDL_Rect src_rect;	/* コピー元矩形 */
	SDL_Rect dst_rect;	/* コピー先矩形 */
} type_layer;

/* レイヤー番号列挙体 */
enum enm_layer{
	lyrBackground = 0,	/* 背景 */
	lyrEnemy,		/* 敵 */
	lyrText,		/* メッセージ */
	lyrEnd			/* 「ダミー」 */
};

/* グローバル変数 */
type_layer g_game_layers[lyrEnd];	/* レイヤー */

/* ここから関数 */

/* レイヤーのsrc_rectのサイズをサーフェスサイズに指定する */
int update_layer_rect_size(type_layer *layers, int index){
	(layers + index)->src_rect.w = (layers + index)->surface->w;
	(layers + index)->src_rect.h = (layers + index)->surface->h;
	return 0;
}

/* SDL_Rectを0で初期化 */
int init_rect(SDL_Rect* rect){
	/* memset0でもよかったな */
	rect->x = 0;
	rect->y = 0;
	rect->w = 0;
	rect->h = 0;
	return 0;
}

/* レイヤーのsrc_rectとdst_rectを初期化 */
int init_layer_rect(type_layer* layer, int index){
	init_rect(&((layer + index)->src_rect));
	init_rect(&((layer + index)->dst_rect));
	return 0;
}

/* レイヤーの可視状態を設定する */
int set_layer_visible(type_layer *layers, int index, int flag){
	(layers + index)->visible = flag;
	return 0;
}

/* サーフェス破棄 */
int drop_surface(SDL_Surface *surface){
	SDL_FreeSurface(surface);
	return 0;
}

/* レイヤーの破棄 */
int drop_layer(type_layer *layer, int index){
	drop_surface((layer + index)->surface);
	(layer + index)->use = 0;
	set_layer_visible(layer, index, 0);
	return 0;
}

/* レイヤーの描画 */
int update_display(){
	SDL_Surface *video_surface = SDL_GetVideoSurface();
	int iLoop;

	for(iLoop = 0; iLoop < lyrEnd; iLoop ++){
		if(g_game_layers[iLoop].visible == 1){
			/* サーフェスの複写 */
			SDL_BlitSurface(
				g_game_layers[iLoop].surface,
				&g_game_layers[iLoop].src_rect,
				video_surface,
				&g_game_layers[iLoop].dst_rect
			);
		}
	}

	/* サーフェスフリップ */
	SDL_Flip(video_surface);

	return 0;
}


/* レイヤーの初期化 */
int init_layers(){

	int iLoop;

	/* 矩形初期化 */
	for(iLoop = 0; iLoop < lyrEnd; iLoop ++){
		init_layer_rect(g_game_layers, iLoop);
		g_game_layers[iLoop].use = 0;
	}

	/* バックグラウンド */
	g_game_layers[lyrBackground].surface =
		IMG_Load("bg.jpg");
	update_layer_rect_size(g_game_layers, lyrBackground);
	g_game_layers[lyrBackground].use = 1;
	set_layer_visible(g_game_layers, lyrBackground, 1);

	/* 敵 */
	g_game_layers[lyrEnemy].surface =
		IMG_Load("penguin_nuke.png");
	update_layer_rect_size(g_game_layers, lyrEnemy);
	g_game_layers[lyrEnemy].use = 1;
	set_layer_visible(g_game_layers, lyrEnemy, 1);

	/* 文字 */
	g_game_layers[lyrText].surface =
		TTF_RenderUTF8_Blended(font, "核ペンギンが現れた", color_black);
	update_layer_rect_size(g_game_layers, lyrText);
	g_game_layers[lyrText].use = 1;
	set_layer_visible(g_game_layers, lyrText, 1);
	g_game_layers[lyrText].dst_rect.y = 200;

	return 0;
}

/* 全レイヤーの破棄 */
int drop_layers(){
	int iLoop;
	for(iLoop = 0; iLoop < lyrEnd; iLoop ++){
		if(g_game_layers[iLoop].use == 1){
			drop_layer(g_game_layers, iLoop);
		}
	}
	return 0;
}

/* メイン関数 */
int main(int argc, char* argv[]){
	SDL_Event event;
	int exit_prg = 0;

	SDL_Init(SDL_INIT_EVERYTHING);

	TTF_Init();

	SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, BPP, SDL_HWSURFACE);

	/* フォント読み込み */
	font = TTF_OpenFont(FONT_NAME, FONT_SIZE);

	/* 画像読み込み */
	init_layers();

	/* 描画 */
	update_display();

	/* イベントループ */
	while(exit_prg == 0){	
		if(SDL_PollEvent(&event)){
			switch(event.type){
			case SDL_KEYDOWN:
				switch(event.key.keysym.sym){
				case SDLK_UP:
					break;
				case SDLK_DOWN:
					break;
				case SDLK_RIGHT:
					break;
				case SDLK_LEFT:
					break;
				case SDLK_ESCAPE:
					exit_prg = 1;
					break;
				case SDLK_SPACE:
					break;
				default:
					break;
				}

				break;
			default:
				break;
			}
		}
		SDL_Delay(1);
	}

	drop_layers();

	TTF_CloseFont(font);

	TTF_Quit();

	SDL_Quit();

	return 0;
}

とりあえず適当な素材を並べてみました。背景画像は某Public Domain素材です。ESCで終了というだけのプログラムです。レイヤーがそのままうまく使えそうです。フロント形式でもウインドウ配置の仕方は無限なので、悩むところ。現在のところベタ書きなので次回以降色々変えていきます。


/

indexに戻る