ついに動くCostco Man

割とあっさりと、ステージの表示までできたと思う。
それってやっぱり、Console版を一回作ってどんな動作をするものを作ろうかというイメージ設計ができているのが大きいんだよね。

つまり、

ただ何も書かずに考えて、何もまとめずソースコードそのまま書こうとするやつは、一生ゲーム作れません

何事も、小さなことの積み重ねと、次を考えて行動することが大事ってことだね。
それでは次に行ってみよう。
次は、実際に荷物押して運べるようにしていこう

Console版では、プレイ画面では以下のようにゲームのループを回していた。

  1. Mapの初期化
    1. Updateで入力受付
    2. Updateでプレイヤーの位置を取得
    3. Updateでプレイヤーの移動
    4. Updateでプレイヤーの移動に伴う荷物の移動の処理
    5. UpdateでClear判定
      1. Clearしていたら状態を変更
      2. それ以外は次へ
    6. すべて更新し終わったらDraw関数で更新後のStageを表示
    7. 入力受付に戻る

大体こんな感じだった(と思う)
この処理はSiv3Dでも大体同じように書いていくことができる(っていうか、できそうな感じにConsole版書いておいたんだ)

しかも、今回のグラフィック表示は、コンソール版のマップをグラフィカルに表示しているだけなので、コンソール版が裏で動いてさえくれれば表示を更新していくだけになる。(とりあえずはね)
入力部分は、コンソール版はstdin(標準入力)を使っていたが、Siv3D版ではSiv3Dの機能を使って入力をゲットしていく
その辺も含めて、必要な機能をConsole版から移植していこう(ほとんどはコピペで済むYO!)

ソースを追加していく

まずは、宣言部。つまり、gameSequence.hの修正をしていこう

Listing. 1: gameSequence.hの修正
gameSequence.h
//Mainから呼ぶやつ
void UpdateTitle(GAME_STATE& _state);
void DrawTitle();
void UpdatePlay(GAME_STATE& _state);
void DrawPlay();
void UpdateClear(GAME_STATE& _state);
void DrawClear();
 
//Mainからは呼ばず、gameSequenceのほうでだけ呼ぶやつ
void DrawStage(Map& _map);
//ちょっと引数を変えたのでこっちに書く
direction GetDirection();
 
 
//Console版から持ってきたやつ
OBJNAME GetObjectNum(Point _pos, Map& _map);
void SetObjtoMap(OBJNAME _obj, Point _pos, Map& _map);
Point GetPlayerPos(Map& _map);
void MoveObject(direction _dir, Map& _map);
bool CheckClear(Map& _map);

実際に入力を受け取る関数GetDirectionの引数はコンソール版ではint cでとってきていたが、関数内でSiv3Dの機能を使って入力を受け取るので引数はいらなくなる
その他は、ほとんどそのまま使える(はず)
次に、それを踏まえて、定義部(gameSequence.cpp)を修正していく

Listing. 2: gameSequence.cppの修正
gameSequence.cpp
//Mainから呼ぶやつ
void UpdateTitle(GAME_STATE& _state)
から
void DrawClear()
{
}
まで追加なしなので省略
 
//Mainからは呼ばず、gameSequenceのほうでだけ呼ぶやつ
void DrawStage(Map& _map)
{
   変更なしで省略
}
//ちょっと引数を変えたのでこっちに書く
direction GetDirection()
{
  //後で直すので省略
}
 
 
//Console版から持ってきたやつ
OBJNAME GetObjectNum(Point _pos, Map& _map)
{
   //コンソール版そのままコピペ
}
void SetObjtoMap(OBJNAME _obj, Point _pos, Map& _map)
{
    //コンソール版そのままでいいよ
}
Point GetPlayerPos(Map& _map)
{
    //コンソール版そのまま
}
void MoveObject(direction _dir, Map& _map)
{
//ここだけ変更
	Point dirVector[5] =
	{
		{ 0, -1 },{ -1,  0 },{ 0, +1 },{ +1,  0 },{ 0,  0 }
	};
//Console版は、これが外に出ていたが(ほかでも使う気がしてたんだよねぇ)この関数でしか使わないので関数ローカルで宣言
    //あとは、コンソール版と同じ!
}
bool CheckClear(Map& _map)
{
    //コンソール版と同じでOK
    //ここだけ、coutは使わないのでコメントにしておこう(グラフィック表示だもんね)
    //cout << "おかたずけ完了!" << endl;
    return true;
}

ここまで変更したら、最後に、入力を取得する関数direction GetDirection()を修正していく
Siv3D使っているので、キー入力は

とかで取得することができる。
コンソール版では、アロー(方向)キーの取得がちょいめんどくさかったのでスルーしたけど(できないわけじゃないんだからね)、
今回は簡単なので、アローキーでもwasdでも動くようにしよう
方向は、globals.hで、

globals.h
//direction方向を表すenum
enum direction
{
	UP, LEFT, DOWN, RIGHT, NONE
};

Siv3Dで複数キーの入力を取得するには、ここを見てほしい。

Listing. 3: GetDirection関数の更新
gameSequence.cpp
direction GetDirection()
{
	if ('w'または上キー)
	{
		return UP;
	}
	else if ('a'または左キー)
	{
		return LEFT;
	}
	else if ('s'または下キー)
	{
		return DOWN;
	}
	else if ('d'または右キー)
	{
		return RIGHT;
	}
	else  //その他の場合
		return NONE;
}

実際に動かしていく

あとは、UpdatePlay内で、GetDirectionを呼び出してプレイヤーの移動方向を取得し、
コンソール版のMoveObjectにぶっこんでやればいいと思う。
使うマップは、さっきincludeで読み込んだmaps[0]を使おう

Listing. 4: caption
void UpdatePlay(GAME_STATE& _state)
{
	direction nextDir = 方向を取得
	MoveObjectを使ってmaps[0]上のプレイヤーをnextDirに動かす!;
	//if (MouseL.down())
	//{
	//	_state = GAME_STATE::CLEAR;
	//}
}

これで、入力があるとmaps[0]のDat[][]にあるデータが書き換えられるので、DrawPlayでは今まで通り書き換えられたデータをマップ表示すればいいだけである。(変更なし)

表示結果

Fig. 1: ここまでの結果

その4 クリア判定とか、その他いろいろ