Help us understand the problem. What is going on with this article?

UnityでRPGを作るpart2 2Dトップビューのマップと衝突判定

はじめに

前回はこちら
UnityでRPGを作るpart1 歩行アニメーションと操作 - Qiita

前回にキャラクターを歩行させるコードを書いたので今回は

  • 2Dマップの作成
  • 作成したマップのオブジェクトに衝突判定を設定する

をやっていこうと思います。
ちなみに今回の完成物はこちら。だいぶゲームっぽくなります。
そして今回 記述するコードの少なさに感動しました (Unity初心者 雑感)

一応
これは勉強の備忘録として作っていますが、やっぱりこういったいかにもなAssetがStoreで提供されていたりします(便利か。はまだ使ってないのでわかりませんが)
RPG Map Editor - Asset Store
さすがみんなのUnity。とりあえず探してみるのもアリです :thumbsup:

1. 2Dマップの作製

まずは、マップ用の素材を準備します。
さすがにマップの素材を1から作るのはしんどいので、今回はこちらのサイトの素材を利用させていただきます。 :pray:
マップチップ - ぴぽや倉庫

画像をDLしたら前回同様に Sprite Editorを利用して、
32x32画像なので、 Sliceでいい感じに設定して画像のように分割します
image.png

で、前回は キャラクターの画像に対して Pixel Per Unit = 1と設定していましたが
今回は、1マス = 1キャラクター に一つのチップをあわせるために32x32画像だから
Pixel Per Unit = 32を設定します。

ちなみにこの工程は、RPGツクールのようなタイル状にいろんなマス画像が1枚のファイルになったものを分割するための工程なので、一つずつ読み込む場合などは適宜無視してください。

TileMapとTilePalette

RPGツクール触ったことがある人ならわかるだろう…あのマップ編集機能。
マップチップをイラスト編集のように簡単にできるアレですが
Unityもそれっぽいのあるよ(?)といことで、TileMapとTilePaletteです。

名前のとおりですが、タイルの画像を設定して、それをマップ上にタイルのように敷き詰めるための機能です。

Sceneに新しく足していきます。
右クリック -> 2D Object -> Tilemapで新しいTilemapが追加できます。

そうすると、Gridというオブジェクトが追加されてその中に今回編集対象のTilemapのシーンが追加されています。

次に上部メニュー Window -> 2D -> Tile Paletteを押すと
いかにもな画面がダイアログで表示されます(画像はパレット追加済みの状態です)

画像の左上に見えるプルダウンを押すと、Create New Paletteという項目があるので
押して新しいパレットを作成します。とりあえず設定は下の通り。

項目 概要
Name わかりやすければ。
Grid Rectangle(default)
CellSize Automatic。作成する大きさが決まってるなら設定するぐらいでOKなはず

これで、新しいパレットが作成されます。
後々を考えると、「ダンジョン」「城下町」みたいなくくりでしっかり分けておくと管理しやすいかも?

次に先程 Sprite Editorで分割したマップ画像を Paletteにドラッグ&ドロップすると
タイルを保存するために、保存先のフォルダを指定する画面がでるので
とりあえず専用のフォルダを作成してChooseを押します。

image.png
こうすると、分割したマップ画像内のそれぞれのタイルが一つの画像としてフォルダに保存されていきます。

補足
パレットにいれたけど、いらない。といった場合は
先程パレット作成時に選んだプルダウンメニューのとなりにある Editという項目を押すことで
編集ができます。消しゴムを選んで、パレットのタイルを選択すれば消えます。
このあとに行うTilemapの編集時は Edit状態をもう一度押してOFFにしましょう。

Tilemapの編集

最初にSceneに用意したTilemapにマップを書いて作成していきましょう。
image.png

雰囲気でわかると思いますが

  • Tile Paletteから書きたいタイルを選択
  • Tile Palette上部のペンを選択
  • その下にあるActive Tilemapを選択
    • 複数のTilemapがある場合は切り替える必要があります
    • Scene一覧にある方をクリックして選択しても切り替えられます
  • 画面真ん中で思いのままに描いていく

だけで、最初に見せた完成形のようなマップが完成します。
ただ、Tilemapが1枚だけでは 草原の地面の上に木を生やすといったことができないので、複数のTileMapを利用していきます。
後々の衝突判定などでも有用になってくるので、次にレイヤーについて説明します。

レイヤーの上下関係を設定する

前回のキャラ作成では、複数のオブジェクトを扱わなかったのですが、今回からマップとキャラクターを扱うようになるため、単純に追加していくと下のようにキャラクターがマップの後ろに隠れてしまうという現象に行き当たると思います。

image.png

そこで、各オブジェクトにレイヤーの位置関係を設定していきます。
現在キャラやマップのオブジェクトには xxx RendererというComponentがセットされていると思います。

  • キャラ(Sprite) : Sprite Renderer
  • マップ(Tilemap) : Tilemap Renderer

そのComponentに Sorting Layerという項目があるので、そこを選択し
Add Sorting Layer...という項目をクリックすると下の画像のような画面が表示されます。

Sorting Layersの項目の右下にある+を押して、画像のように

  • 歩行可能なタイルを配置するレイヤー
  • 移動できない(山や水のような)タイルを配置するレイヤー(後述)
  • キャラクターが表示されるレイヤー

を作成してさきほどの画面に戻り、 Sorting Layerからそれぞれの作成したレイヤーを設定しましょう。
これで、キャラクターがマップの上に表示される筈です。

これで、ページ先頭に表示した完成物と同じ見た目になります

歩けるタイルと歩けないタイルを分ける

次の項目として説明していく衝突判定の前段階です。
重ねて表示したいタイルがあったりする場合にレイヤーを分けますが、それだけではなく
特定のレイヤーをまるごと衝突判定の対象とすることで、マップの実装が楽になります。

完成物から歩けるTilemapを除くとこのような状態になっています

衝突判定の設定などは次項。

2. マップに衝突判定を設定していく

半分コード。半分Unityな項目です。
マップを作ると「歩けない道」が当然のように作っていくことになるので
ここでは、その設定と衝突判定に伴うキャラクターの操作を制御する実装をしていきます。

やることは 山や川はすすめずにぶつかるようにする。 です

とりあえず コリジョン Collision という単語を覚えておきましょう。
検索のときに重要です :innocent:

Collider2Dを追加する

キャラやマップのオブジェクトにコンポーネントを足していきます。

  • キャラ(Sprite) : Box Collider 2D
  • マップ(Tilemap) : Tilemap Collider 2D

昔ながらのゲーム(というコンセプト)なので衝突判定は厳密にやりません。ので、細かく調整をする必要もありません。
上を追加すると、それぞれ緑色の枠のようなものが表示されます。
以降、この衝突判定領域を示す緑の枠を Colliderと表記します。

体の上部だけは判定を除いて重なるようにする場合
Box Collider 2Dの項目にある Edit Colliderというボタンを押して、Colliderの大きさを調整します。
Box Colliderをセットした場合、Spriteの大きさにあわせてColliderが設定されるので、
それを全長の半分に設定した状態が下です。
image.png

マップ(Tilemap Collider 2D)の方はデフォルトで、読み込んだ画像の透明じゃない部分がColliderとして設定されていると思います。

image.png
これはタイルの元になっている画像を選択してinspectorを見ると
Collider Typeが Spriteになっていると思います。

これをGridに変えると、タイルにあわせた四角の部分がColliderとして設定されます。
この設定を全部変える場合、画像をすべて選択した状態で変更することで一気に切り替えることができます。
改めて編集画面を見ると、タイルにあわせたColliderに変わっていると思います。

image.png

RigitBody2Dの設定をDynamicにする

前回は「昔なつかしいRPGなので」 body type: kinematicに設定していましたが
Body Type : Kinematicは標準の衝突判定が無効になります

ただDynamicにするだけだと物理演算が有効になってしまい、キャラクターが画面外に落ちていってしまうのでGravity Scale を 0にすることで、落ちなくなります
が、これだけでは足りません。

constraintsの設定で回転を止める

物理演算自体は有効なため、前述の設定だけだとCollider同士のぶつかったときに力が働いた方向にグルングルン回転することがあります。

あまり正確な図ではないですが、イメージ的には下の通り。

とりあえず、なんのコッチャな方もいるかと思いますが、とりあえず書いてあるとおりに実装して完成したら、あとでぜひ試してみてください……カオスですw
(下のtweetでは Gravity Scaleが1の状態で見ています)

そういった回転を抑えるためにコードで Regitbody2Dに対して
下記のような設定を行います。

this.rigidBody.constraints = RigidbodyConstraints2D.FreezeRotation;

constraints まさに制約ですね
これで、上記のようなクルクルは発生しなくなります。

2019/09/23 追記
コメントご指摘より
UI上でもFreeze Rotationの設定ができるみたいです
設定項目は Rigidbody2Dの下の項目 (確認済み)
image.png

ご指摘ありがとうございました :pray:
2019/09/23 追記 : ここまで

ソレ以外の設定はこちらをご覧ください。
RigidbodyConstraints - Unity スクリプトリファレンス

コードを書く

毎度最後のコードのターンです。今回はゆるっと説明します。
前回からの説明なので、キャラクターにこのクラスはbind済みであるとします。

ここでは前回作った MoveControllerを修正します
UnityでRPGを作るpart1 歩行アニメーションと操作 - Qiita

MoveController.cs
public class MoveController : MonoBehaviour {
    public readonly float SPEED = 0.1f;
    private Rigidbody2D rigidBody;
    private Vector2 input;

    void Start() {
        this.rigidBody = GetComponent<Rigidbody2D>();
        // 衝突時にobjectを回転させない設定
        this.rigidBody.constraints = RigidbodyConstraints2D.FreezeRotation;
    }

    private void Update() {
        // 入力を取得
        input = new Vector2(
            Input.GetAxis("Horizontal"),
            Input.GetAxis("Vertical"));
    }

    private void FixedUpdate() {
        if (input == Vector2.zero) {
            return;
        }
        // 既存のポジションに対して、移動量(vector)を加算する
        rigidBody.position += input * SPEED;
    }
}

Unity先輩強すぎませんか?

…すいませんちょっと感動しました。なぜかというと
「衝突判定されたら、座標を戻す」的な処理を一切かかなくていいみたいです。
上のコードだけで次のように「山や川にぶつかったら移動させない」みたいな動きができます。

完成物確認

ほぼUnityのUI上の設定だけでできました。

まとめ

Unityってすごいですね(ボキャ貧)

最初は「衝突とみなされたら、コード上で位置を戻す」とかやらなきゃいけないのかと思っていましたが、ソレが不要というのはありがたい。
ただ、この衝突判定のために 2Dトップビューでは不要な物理演算(Dynamic)を有効にして、Gravityを0にしたり回転を無効にしたりやっているので、あとで辛い目をみるかは…今考えても仕方ないので今後発生したら書きます :innocent:

次は

  • 人や宝箱に対してボタンを押したらイベントの実行
  • アイテム情報の管理

的なものでもやっていこうかなと思います。

_tybt
しがないエンジニア。楽しくモノづくりがしたい。 静的型付けをしてくれる言語が好きで、愛のない変数名は駆逐する。 ゆるい話ははてブに書いてます。もっとゆるいのはtwitterに書いてます。 落ち着いたらゲーム制作再開したい
http://tyabata.hatenablog.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした