見下ろし2Dマップ上でプレイヤーを動かす

前回テキストデータで壁と通路の2Dマップを作成しました。
その内容をベースに作成したマップ上でプレイヤーを動かすというのを実装してみます。

この記事はシリーズものとなっています。

プレイヤーを動かす仕組み

作業に入る前にどういう仕様なのか整理してみます。

  1. 十字キーの入力を受け付ける
  2. 押された方向にプレイヤーを動かす
  3. 進行方向が壁の場合は動かない

こんな感じでプレイヤーを動かせれば成功ではないでしょうか。
では作っていきます。

プレイヤースクリプトの作成

スクリプト作成

ではまずプレイヤーを動かすためのC#スクリプトを作成します。
シンプルにPlayerとしました。
作成したPlayerスクリプトをPrefabのPlayerにアタッチします。

入力を受け付ける

次にPlayerスクリプトの中身を作っていきましょう。
まず十字キーの入力を受け取れるようにします。
Update関数内に記述します。
一旦このような感じにしておきます。

実行してみると入力したキーに応じてログが確認できます。

方向を定義する

入力は無事受け付けたようですので、続いてPlayerがどの方向を向いているかを定義します。
列挙型を使います。
そしてUpdate関数内で受け取った入力によって方向を変えて行きます。

確認のためログでdirectionを出してみましょう。

キーによって方向を変更したことが確認出来ました。

移動の実装

1マス移動の考え方

ではここから実際にプレイヤーを移動させる処理を書いていきます。
1マスずつ移動させたいと思います。
マップは現在(x座標,y座標)という感じで左上から右下にかけて(0,0)(0,1)(0,2)…のように碁盤の目のような感じでVector2Int型で並んでいます。
それにマップチップのサイズをかけて隙間なく埋めていました。

この仕組を使ってプレイヤーを動かして行こうと思います。
入力されたキーがプレイヤーの現在位置から、上ならy方向に+1、右ならx方向に+1、下はyが-1、左はxが-1という感じになると思います。
例えば先程の図でプレイヤーが下に向かうとすればyを-1してマップチップサイズをかければ下に1マス移動するということになります。

プレイヤーの座標を取得する

それでは最初にプレイヤーの座標を取得したいと思います。
そのためにPlayerスクリプトでそれ用の変数を定義します。
次にマップ生成時にPlayerも生成されていますので、前回作ったMapGeneratorスクリプトも修正していきます。

まずPlayerスクリプト

続いてMapGeneratorスクリプトの_createMap関数を修正します。

修正箇所は一つで実際にループ内でマップチップを生成しているときにマップのタイプがプレイヤーの場合はPlayerのcurrentPosに現在のposを代入しています。
これで現在のプレイヤーの座標が取得出来ました。

移動用の配列を準備する

続いて実際に上下左右に移動する際の値を配列で準備しておきます。

このようなInt型の二次元配列を用意しました。
先程作ったDIRECTIONと対応させたいので、この並びになっています。
一つ注意ですが、上を押したらyが+1なのにこの配列だとyが-1になっています
これは前回MapGeneratorで作成したScreenPosでYの値に対して上下の位置を正しくするためにマイナスをかけていたので、その関係で移動用の配列でもYは上下の値が反転しています。

MapGeneratorを取得しておく

プレイヤーの移動も座標かけるマップチップのサイズを利用しますので、前回作ったMapGeneratorのScreenPos関数を利用したいと思います。
まずMapGeneratorの方を修正していきます。
具体的にはPlayerスクリプトでもMapGeneratorを取得できるようにInstantiate時にMapGenerator(HierarchyではMapManager)の子要素にします。
続いてScreenPos関数をpublicにします。

MapGeneratorはこのような感じで、

続いてPlayerスクリプトのStart関数で親要素(MapManager)からMapGeneratorを取得します。

これでPlayerスクリプトから後で使う、MapGeneratorのScreenPos関数を使用することができます。
念のためマップチップがMapManagerの子要素になっているか確認しておきます。

ちゃんと子要素になっていましたね。

移動用の関数を作る

続いてキーを押されたときの移動用関数を作成します。
また、現在位置(currentPos)から次の位置に移動する用の変数も準備します。
今回は移動用の関数は_move、次の位置の変数はnextPosとしました。

Playerスクリプトはこのようになっています。

_move関数の処理の流れは下記の通りです。

  1. directionを使ってmove配列からVector2Int型を取得し、currentPosにプラスしてnextPosに代入
  2. MapGeneratorのScreenPos関数で実際Playerが動く1マス分のゲーム上の位置を自身のlocalPositionに代入し移動
  3. currentPosにnextPosを代入し上書きして現在置を更新

このような感じです。

では実際に動かしてみましょう。

無事に1マスづつ動きました。
現状ではご覧の通り、壁を貫通していきますのでこれを直していきましょう。

壁貫通を防止

MAP_TYPE取得用の関数作成

進む方向が壁なのか、通路なのかがわかれば解消できそうです。
前回MapGeneratorでMAP_TYPE型の二次元配列、mapTableというものを作りました。
これを利用すれば進む先のMAP_TYPEが取得できそうです。
まずMapGenerator側でPlayerがMAP_TYPEを取得できる関数を作ります。
GetNextMapTypeとしました。引数にはVector2Int型を取ります。
それと列挙型MAP_TYPEは前回ではprivateになっていましたので、Playerからも取得できるようにpublicに修正します。

Player側でMAP_TYPEを取得する

では最後にPlayer側で進行方向の情報を取得して通路なら移動する実装をしてきます。
_move関数内を少し修正するだけで終わります。

このようになりました。
MapGeneratorのGetNextMapTypeに次の座標nextPosを渡し、戻ってきたMAP_TYPEがWALL以外なら進めるという処理です。
注意点としてMAP_TYPEがGROUNDなら進める、とすると最初に読み込んだマップデータでPLAYERが1,1に存在しますので、そのマス目は通れなくなるため、このようにしました。
では実際に動かしてみます。

壁にガンガンぶつかっているのですが、貫通すること無く、無事に通路だけを移動してくれました。
移動方向によってプレイヤーの画像を変えたり、歩くアニメーションをつけたり、スムーズに1マスを移動させるなどするとより雰囲気が出るかも知れませんね。
ここまでの内容は前回のものも含めてgithubにアップしておきますのでよろしければ参考にしてみて下さい。
github

前回のマップ生成の記事はこちらになります。

いずれこの内容を使って私の大好きなウィザードリィのような疑似3Dの実装をやってみようかと思います。

関連記事

最後までご覧頂いてありがとうございました。