【Unity2D】Unityでオブジェクトをグリッド移動させる試み

Unity2D

Unity2D ARPG

こんにちは。なおキーヌです。

ブログ毎日更新は331日目になります。

前回「【Unity2D】Physics2D.Boxcastで判定しようとして失敗した話」にて判定の取り方に悩んでいました。

記事書いた後色々試していたのですが、どうも良い感じの状態にならなくて悩んだ結果
オブジェクトはグリッド移動してしまえばいいんじゃないかという結論に至りました。

というのも、ドット移動だと四角タイプのオブジェクトの場合めり込みが無いとき
オブジェクトの隙間に入りにくくなるという現象が起こってしまいます。

これではユーザーのストレスがマッハなのでグリッド移動にすることに決意しました。

グリッド移動だと1つ動かしたら1つの隙間が確定で開くのでそんなことはなくなりますね。

しかしプレイヤーはドット移動のままにしたいので、衝突判定を四角から丸に置き換えました。

こうすることで角に当たってもスイーッと流れるように動いてくれるので引っかかるストレスが減ります。

グリッド移動とは、Unity製のゲームではあんまり使われないかと思うのですが
2Dゲーム(ドット絵時代のドラクエやFFやポケモン等)では基本的な移動処理になります。

私の過去の講座ではプチコンやJavaScriptで実装しています。

簡単に処理内容を言うと

座標が一定の値で割り切れるまで移動処理をし続ける

といった感じです。

グリッド移動がどんなもんかよくわからないという人は

【プチコン4講座】スプライト変数とグリッド移動を覚えよう

【プチコン4講座】RPGを作るためのグリッド移動の実装

【プチコン講座】プレイヤーをRPGぽく操作してみよう:グリッド移動編

【pixi.js】ドラクエ1式の移動と衝突判定を作ってみよう【蟹歩き】

このあたりを見てもらうとよくわかると思います。

それではUnityでグリッド移動処理を学んでみましょう。

グリッド移動は割り切れるまでは処理し続けるようにする

現状Gを押していたらオブジェクトを掴んで離したら離すようになっています。

そして押したり引いたりしてる最中で移動中でもGを話せば強制で解除します。

少しでも動かしたらGを話しても掴み状態を解除しないという処理に置き換えて、
座標がスプライトサイズ(基本は16×16)で割り切れる状態になったら解除するという仕組みにします。

UnityというかC#では割った余りというのは%を使って組みます。

具体的に書くと

// 座標を動かす
this.transform.position.x++;

// 条件で確認
if (this.transform.position.x%16 == 0) {
  Debug.Log("割り切れた");
} else {
  Debug.Log("割り切れてない");
  this.transform.position.x++;
}

分かりやすいように書いているだけなので、実際にはposition.x++何てできませんので注意してください。

例えばx座標が0の時にxが1になったら16では割り切れませんね。

割り切れない場合は座標を加算し続けます。

そして割り切れるようになったら止まる。

これだけです!

これをすると半キャラずらしでめり込むとかも考えなくてよくなるので楽ですね!

Unityで実装するときの注意点は小数点

Unityで1ずつ動かすとカクカクして動いてしまうので、
小数点単で動かすのですが今度はきれいに16で割り切れなくなって条件から抜け出せなくなります。

なので計算する時は小数点を切り離してやる必要がありますね。

小数点切り捨ては「Math.Floor」を使うのはもはやプログラミングではよくあることです。

しかしC#には「Math.Truncate」というのもあるみたいです。

切り捨ての方式が少し違うようなのでしっくりくる方を選択してみてください。

私はFloorの方がしっくりきました。

後は割り切れた時にオブジェクトの座標も補正してあげないといけません。

その時小数点の無い状態を渡してやるとオブジェクトがカクッって不自然に動いて見えてしまいます。

小数点ピクセル補完をしていても少し違和感を覚えちゃうくらいです。

これの対策は実際に設定したい値と設定する前の値の補完をしてくれる関数があればよいですね。

UnityではVector3の関数にLerp()とSlerp()というのがあるのですが、
これが良い感じに保管してくれるそうなのです。

私はまだ使ってないので、そのうち使って解説してみようかなと思ってます。

とりあえず違和感があってもゲームに支障はなさそうなので一旦補完無しで行きます。

オブジェクトを動かすときはプレイヤーもグリッド移動にする

ゼルダの伝説とかを見ていると、普段はドット移動が出来るけど
岩とかを引いたり押したりするときはグリッド移動になっています。

そうしないと色々不都合とそれを直すための補正が必要になってコストが非常に上がってしまうので
ある一定の条件時ではグリッド移動に制限してやる必要があります。

そうしないと本来いけないはずの予定の場所が無理矢理ドット移動でいけるようになったりして
ゲーム自体が崩壊してしまいます。

それはそれで面白そうですが、製作者としては破綻させてはいけませんね(笑)

まぁマリオとかゼルダの伝説とかRTAみてると製作者の意図しない動きでクリアとかしているので
プロが作ったゲームでも穴は沢山あるのでとりあえず完成させてから致命的な部分を潰していく方向で大丈夫だと思います。

あからさまにゲームプレイどころか後の制作に影響が出るような感じだったらその場で直した方がよさそうですね。

次回はこのグリッド移動をしっかりと適用してゲームらしくしていきます。

それでは。