Cosmic Hooligun 予告編

もう夏休みも終わりだし、さすがに追加はないかなと思った諸君。甘かったね
次作るゲームは、昔懐かしい(ってよくWebに書いてるけどどんな世代に向けて言ってんだろう。。。)スペースインベーダーに似たゲームを作っていこう。
スペースインベーダーはタイトーのゲームで、Pong(Table TENNIS) ⇒ Break OUT(ブロック崩し) ⇒ スペースインベーダー ⇒ ギャラクシアン ⇒ ゼビウス、の流れを作った現代のシューティングゲームの北京原人であり、ネアンデルタール人であり、ミトコンドリアであり、デオキシリボ核酸である。
これを知らず、作らずして、ほかのゲームを考えるとはおこがましいにもほどがあり、ゲームとは何かを考える良い機会でもあると思う。

とりあえず、初めの目標はこれ

Fig. 1: とりあえずの目標、「弾撃って当たる」

予定では、ここまでに

Listing. 1: シューティングゲームの基本動作ができるまでのヘッダファイルの中身
gameSequence.h
//Mainから直で呼ぶやつ
void UpdateTitle(gameData& _dat);
void DrawTitle(gameData& _dat);
void UpdatePlay(gameData& _dat);
void DrawPlay(gameData& _dat);
void UpdateClear(gameData& _dat);
void DrawClear(gameData& _dat);
void UpdateGameOver(gameData& _dat);
void DrawGameOver(gameData& _dat);
void InitGameData(gameData& _dat);
 
//Mainから直では呼ばないやつ
void InitPlayer(gameChar& _player);
void InitEnemy(gameChar& _enemy);
void SetCharaRect(gameChar& _gamechar, SizeF _size);
void InitPlayerBullet(gameData& _dat);
//void InitEnemyBullet(EnemyBullet& _eb);
 
direction GetDirection();
void UpdatePlayer(gameData& _dat);
void DrawPlayer(gameChar& _player);
void DrawEnemy(gameChar& _enemy);
 
//void UpdateEnemy(gameChar& _enemy);
 
int GetAlivePlayerBulllet(PlayerGun& _playerGun);
void FirePlayerBullet(gameData& _dat);
void UpdatePlayerBullet(PlayerGun& _playerGun);
void DrawPlayerBullet(PlayerGun& _playerGun);
 
//爆発関係
void InitExplosionFlames(Explosion& _explosion);
int GetAliveExplotion(Explosion& _explosion);
void FireFlame(Explosion& _explosion, Vec2 _pos);
void UpdateExplosion(Explosion& _explosion);
void DrawExplosions(Explosion& _explosion);
 
//当たり判定
void PlayerBulletVsEnemies(gameData& _dat);

なんか大変そうだよねぇ。。。

処理が複雑になってくると、こんな感じでたくさんの関数が増えてくる。
この関数たちを、目的によって呼び分けていかなければならないのだけれども、現在の構造体+関数型のプログラムでは簡略化に限界がある。
とりあえず今回はこのまま何とか作っていこうと思う。
まずは、準備として今回のファイル構成

  1. gameSequence.h
    • ゲームに登場する関数たちと、構造体、グローバル変数の宣言が書いてある。
  2. gameSequence.cpp
    • ゲームに登場する関数たちの本体(定義)が書き連ねられている
  3. Main.cpp
    • 上の2つで作った関数を組み合わせて、ゲームのロジックを実行するためのファイル

今回から、めんどくさくなるのでglobals.hはやめておいた。

今までは全部バラバラにゲームのステートやプレイヤーの構造体などを持っておいて、関数に渡してきたが、だんだんあほくさくなってきたので(本当は、必要ないものまで関数に変更可能な状態で渡すのは、誤変更などが起こり危険なので、あまり良くないが、)今回は、ゲームに必要ないろんなデータを丸っと全部やり取りするようにしてみた。

ゲームに必要なデータが増えたら、

Listing. 2: gameData構造体の作成
gameSequence.h
struct gameData
{
//ここに必要なデータを並べていく
};

ゲームに出てくる、オブジェクトはほぼすべて、以下の構造体で表される

Listing. 3: gameChar型の追加
gameSequence.h
struct gameChar
{
	Vec2 pos;     //位置
 
	bool isAlive; //生死
	Texture tex;  //画像
	double speed; //動作速度
	RectF rect;   //バウンディングボックス
	Vec2 moveDir; //方向ベクトル
};
  • Vec2 pos;
    • 位置(型:Vec2)
    • キャラクタの(多分中心)位置 x、yの実数データ
  • bool isAlive;
    • 生死
    • キャラクタの生死の情報 bool型
  • Texture tex;
    • 画像
    • キャラクタの画像(アニメーションある時はアニメーションシート(後述))
    • Texture型
  • double speed;
    • 移動速度
  • RectF rect;
    • バウンディングボックス
    • キャラクタを囲む四角形、当たり判定や移動の処理で使う
    • キャラクタと同じ大きさとは限らない
  • Vec2 moveDir;
    • 方向ベクトル
    • この方向に speedで移動する

gameDataにプレイヤーと敵を一匹追加する

gameSequence.h
struct gameData
{
	gameChar Enemy;
	gameChar Player;
};

グローバルに使ういつものやつを追加

globals.hを廃止したけど、そっちあったいつも使いそうなやつ(ゲームシーケンスに関するものなど)をgameSequence.hに移す
さすがに、今までと同じすぎるので説明は省略する。

Listing. 4: いつものenumとかをgameSequence.hに追加
gameSequence.h
enum GAME_STATE
{
	TITLE, PLAY, CLEAR, GAMEOVER
};
 
enum direction
{
	UP, LEFT, DOWN, RIGHT, NONE
};
 
struct gameChar
{
	Vec2 pos;
 
	bool isAlive;
	Texture tex;
	double speed;
	RectF rect;
	Vec2 moveDir;
};

ついでにいつものゲームステートもgameDataに入れちゃおう。

gameSequence.h
struct gameData
{
	GAME_STATE gState;
	gameChar Enemy;
	gameChar Player;
};

そんで、いつものゲームシーケンスをGAME_STATEではなく、gameDataを渡すようにしてしまおう。
いつものやつからMain.cppを以下のように変更しよう。

Main.cpp
void Main()
{
	gameData gDat;
	gDat.gState = GAME_STATE::TITLE;
 
	FontAsset::Register(U"font", FontMethod::MSDF, 48, Typeface::Bold);
 
	while (System::Update())
	{
		switch (gDat.gState)
		{
		case TITLE:
			UpdateTitle(gDat);
			DrawTitle(gDat);
			break;
		case PLAY:
			UpdatePlay(gDat);
			DrawPlay(gDat);
			break;
		case CLEAR:
			UpdateClear(gDat);
			DrawClear(gDat);
			break;
		case GAMEOVER:
			UpdateGameOver(gDat);
			DrawGameOver(gDat);
			break;
		default:
			break;
		}
	}
}

これで、一応、全部が全部グローバル変数状態、からは脱出して少し進化できると思おう。
いつも通り、クリックで以下のシーンを1周遷移できるようにソースコード書こう。(省略)

gameSequence.h
//Mainから直で呼ぶやつ
void UpdateTitle(gameData& _dat);
void DrawTitle(gameData& _dat);
void UpdatePlay(gameData& _dat);
void DrawPlay(gameData& _dat);
void UpdateClear(gameData& _dat);
void DrawClear(gameData& _dat);
void UpdateGameOver(gameData& _dat);
void DrawGameOver(gameData& _dat);

自機の画像は、みんなphotshop使えるんだから自分で作成してもいいし、フリーのゲーム素材を使ってもよいので入手しましょう。
Sprite(背景透過有り)のPng画像がいいと思う。
何も見つけられない人はKennyさんとこの画像とか、この辺からダウンロードするとよい

僕はこの辺のやつを使いましたよっと。
どれでもよいので、Sip3DプロジェクトのAppフォルダにimagesフォルダを作ってその下に入れとく。(と、フォルダとファイル名指定でファイル読み込めるので便利)

Space Hooligun の制作その2 へ

  • game-engineer/classes/2023/something-else/summertime-special-cource/cosmichooligun-1.txt
  • 最終更新: 2年前
  • by root