Cosmic Hooligun 予告編
夏休みだもん、ゲーム。。。
もう夏休みも終わりだし、さすがに追加はないかなと思った諸君。甘かったね
次作るゲームは、昔懐かしい(ってよくWebに書いてるけどどんな世代に向けて言ってんだろう。。。)スペースインベーダーに似たゲームを作っていこう。
スペースインベーダーはタイトーのゲームで、Pong(Table TENNIS) ⇒ Break OUT(ブロック崩し) ⇒ スペースインベーダー ⇒ ギャラクシアン ⇒ ゼビウス、の流れを作った現代のシューティングゲームの北京原人であり、ネアンデルタール人であり、ミトコンドリアであり、デオキシリボ核酸である。
これを知らず、作らずして、ほかのゲームを考えるとはおこがましいにもほどがあり、ゲームとは何かを考える良い機会でもあると思う。
とりあえず、初めの目標はこれ
予定では、ここまでに
- 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);
なんか大変そうだよねぇ。。。
処理が複雑になってくると、こんな感じでたくさんの関数が増えてくる。
この関数たちを、目的によって呼び分けていかなければならないのだけれども、現在の構造体+関数型のプログラムでは簡略化に限界がある。
とりあえず今回はこのまま何とか作っていこうと思う。
まずは、準備として今回のファイル構成
- gameSequence.h
- ゲームに登場する関数たちと、構造体、グローバル変数の宣言が書いてある。
- gameSequence.cpp
- ゲームに登場する関数たちの本体(定義)が書き連ねられている
- Main.cpp
- 上の2つで作った関数を組み合わせて、ゲームのロジックを実行するためのファイル
今回から、めんどくさくなるのでglobals.hはやめておいた。
ゲームに使うデータたち
今までは全部バラバラにゲームのステートやプレイヤーの構造体などを持っておいて、関数に渡してきたが、だんだんあほくさくなってきたので(本当は、必要ないものまで関数に変更可能な状態で渡すのは、誤変更などが起こり危険なので、あまり良くないが、)今回は、ゲームに必要ないろんなデータを丸っと全部やり取りするようにしてみた。
ゲームに必要なデータが増えたら、
- gameSequence.h
struct gameData { //ここに必要なデータを並べていく };
ゲームに出てくる、オブジェクトはほぼすべて、以下の構造体で表される
- 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に移す
さすがに、今までと同じすぎるので説明は省略する。
- 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フォルダを作ってその下に入れとく。(と、フォルダとファイル名指定でファイル読み込めるので便利)