当たり判定の続き、今度は荷物を押す編

現在の状況は、自分が動いた時の隣の座標にあるオブジェクトの接触判定をし、オブジェクトごとに処理を切り替える
という処理をしている。ここで言う隣、とは自分が移動しようとしている方向に座標を+1した位置である。

  • 隣のオブジェクトが、
    • 床の場合
      • 現在、自分がゴール上:
        • 自分の位置をGOALにし、隣をHUMANに
      • 現在、自分が非ゴール上:
        • 自分の位置をFLOORにし、隣をHUMANに
    • 壁の場合
    • 何もしない(動かない)
    • ゴールの場合
      • 現在、自分がゴール上:
        • 自分の位置をGOALにし、隣をHUMAN_ON_GOALに
      • 現在、自分が非ゴール上:
        • 自分の位置をFLOORにし、隣をHUMAN_ON_GOALに

という処理のスイッチを行った。
同様に、残りすべての場合において処理を書いていくことで、当たり判定の処理が完成する。
残っているのは、

  • 隣のオブジェクトが
    • 荷物の場合
    • ゴール上の荷物の場合

である。
今までの場合は、動くことのないオブジェクトとの接触判定をしていたが、今度はこれまでと違い、このゲームにおいてはプレイヤー自身以外では、
唯一プレイヤーがその意図通りに動かすこととができるオブジェクトである荷物(LUGG)に関する処理を書いていく。

プレイヤーが荷物に接触すると、その荷物はプレイヤーの移動方向に「押される」ことになる。
これが、このゲームの肝になる部分で、荷物をプレイヤーが押すという操作を繰り返し、すべての荷物をゴールまで運ぶというのがゲームの目的となる。
この、荷物が押される、ということについてよく考察してみよう。
(さきほどまでと同様に、隣=進行方向に+1した位置)
プレイヤーの隣の位置のオブジェクトが荷物だった時に、荷物の隣の位置が移動可能なオブジェクトであれば荷物を動かさなければならない。

隣の隣を取得

隣の位置は、directionと、dirVectorを使うと

//dirVectorとdirection これらはもう前に定義済み
Point dirVector[5] = 
{
	{ 0, -1 },{ -1,  0 },{ 0, +1 },{ +1,  0 },{ 0,  0 }
};
enum direction
{
	UP, LEFT, DOWN, RIGHT, NONE
};
//現在のプレイヤー位置
Point pp = GetPlayerPos(_map);
//移動予定のプレイヤー位置
Point nextPos = {pp.x + dirVector[_dir].x, pp.y + dirVector[_dir].y};
//移動予定のプレイヤー位置の隣
Point nextNextPos = {nextPos.x + dirVector[_dir].x, nextPos.y + dirVector[_dir].y};

このような処理で取得できそう。
あとは、隣の位置のオブジェクトと、隣の隣のオブジェクトがどう動くかを全パターン並べてみよう。
図にすると以下のようになる。

Fig. 1: 荷物を押すときの全パターン列挙

パターンを整理

OBJNAME crr = ppの位置のオブジェクト名
OBJNAME next = nextPosの位置のオブジェクト名
OBJNAME nextNext = nextNextPosの位置のオブジェクト名

この時に、nextとnextNextによって以下のように処理を分ける

  • next, nextNext
  • LUGG、WALL
    • この場合は、壁押しなので何もしないでbreak
  • LUGG、FLOOR
    • nextNextPosにLUGGをセット(荷物を隣(FLOOR)に移動)
    • nextPosにHUMANをセット
      • crrがHUMANの時
        • ppにFLOORをセット
      • crrがHUMAN_ON_GOALの時
        • ppにGOALをセット
  • LUGG、GOAL
    • nextNextPosにLUGG_ON_GOALをセット(荷物を隣(GOAL)に移動)
    • nextPosにHUMANをセット
      • crrがHUMANの時
        • ppにFLOORをセット
      • crrがHUMAN_ON_GOALの時
        • ppにGOALをセット
  • LUGG_ON_GOAL、FLOOR
    • nextNextPosにLUGGをセット(荷物を隣(FLOOR)に移動)
    • nextPosにHUMAN_ON_GOALをセット
      • crrがHUMANの時
        • ppにFLOORをセット
      • crrがHUMAN_ON_GOALの時
        • ppにGOALをセット
  • LUGG_ON_GOAL、GOAL
    • nextNextPosにLUGG_ON_GOALをセット(荷物を隣(GOAL)に移動)
    • nextPosにHUMAN_ON_GOALをセット
      • crrがHUMANの時
        • ppにFLOORをセット
      • crrがHUMAN_ON_GOALの時
        • ppにGOALをセット

気合の入りすぎた漢らしいこの方法は、賛否両論あるかもしれないが、今回はこの方法でやっていく
(現段階で、この方法以外のやり方はオーバースペックだと思われるためと、状態を列挙して、それをもれなく処理するということはゲームのキャラクタ制御において基本事項となるため、今のうちにこのぐらいのものはできるようになろう)

総合すると

Listing. 1: 漢のSwitch-Case文
switch(next)
	{
	case FLOOR:
                //ごにょごにょ
		break;
	case WALL:
                //ごにょごにょ
		break;
	case GOAL:
                //ごにょごにょ
		break;
	case LUGG:
		switch (nextnext)
		{
		case FLOOR:
                    //ごにょごにょ
			break;
		case GOAL:
                    //ごにょごにょ
			break;
		default:
			break;
		}
		break;
	case LUGG_ON_GOAL:
		switch (nextnext)
		{
		case FLOOR:
                    //ごにょごにょ
			break;
		case GOAL:
                    //ごにょごにょ
			break;
		default:
			break;
		}
		break;
	default:
		break;
	}
}

もう少し整理できるかもしれないが、こんな感じで許してちょんまげマーチ

実行結果

自分で動かしてみよう!
変な動きしてたら、判定に漏れがある。

見えないときはクリックして最大化してみてね。マップは、その1当たりでサンプルに出した一番簡単そうなマップを使用!

Map sampleStage = {
	5,5,
  {
	{1, 1, 1, 1, 7, 7, 7, 7, 7, 7},
	{1, 3, 0, 1, 1, 7, 7, 7, 7, 7},
	{1, 0, 2, 0, 1, 7, 7, 7, 7, 7},
	{1, 0, 4, 0, 1, 7, 7, 7, 7, 7},
	{1, 1, 1, 1, 1, 7, 7, 7, 7, 7},
	{7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
	{7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
	{7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
	{7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
	{7, 7, 7, 7, 7, 7, 7, 7, 7, 7}
  }
};

その6 クリア判定など。へ

  • game-engineer/classes/2023/something-else/summertime-special-cource/costcoman-console-5.txt
  • 最終更新: 3年前
  • by root