kenogadget’s blog

kenogadgetです。ケノ。

tilemapでキャラの当たったタイルを取得したい[Unity]

tilemapのhexagon、気になりますよね。僕は使ったことないですけど。

kenoです。

さて、ひとつ前の記事でtilemapをスクリプトで操る方法というのをご紹介したんですが、今回の記事では続いてマウスで指定したタイルを取得するというような処理を思いついたのでご紹介したい。

 

仕組み(Structure)

まず、概観してみましょう。

デフォルトの機能では、tilemap colliderなどを使って簡単に当たったタイルを取得するという機能はないようです。また、マウスでクリックしたタイルを取得するという機能もないですよね。そこで考えたんですが、

・もしもタイルの座標とUnityのxy座標がぴったり一致していたら、

という条件付きですが、この条件のもとならマウスでクリックしたタイルを取得することができるのでは?と考えています。

具体的には、マウスのクリックした座標を取得し、その座標をもとに同じ座標にあるタイルを取得するという流れです。

 

具体的な方法 - 準備

まず、Unityで作業をしましょう。

ヒエラルキーで右クリック「2D Object→tilemap→Rectangular」でtilemapを作成します。

それからプロジェクトタブにSpritesフォルダーを作成し、その中にお好きなSpriteを4つほど入れましょう。

これがtileになりますが、僕は超簡単にペイントソフトで256×256のspriteを5つ連結した画像を作成しました。使いたい方がいれば保存してどうぞ。↓

maptip

この画像のように連結している画像をインポートした場合はSprite Editorで分割してから使いましょう。

なんか参考になるサイトを入れたかったですが、ちょっとあんまりないので後日別の記事で紹介します。

 

Spriteを分割できたら、上部のメニュー「Window→2D→Tile pallete」を押してパレットを表示しましょう。

グリッドで区切られた空間があると思うので、そこにタイルにしたいspriteを投げ入れます。

 

あとは、好きなタイルを選択してSceneタブで好きなようにステージ等を作りましょう。

ここで、tilemapのtransformを拡大縮小することでマス目を伸ばしたりすることができるんですが、これをするとのちの作業に影響するので(1, 1, 1)にしときます。

 

具体的な方法 - スクリプト

さて、ひとつ前の記事でも説明しましたが、今座標がどのようになっているかというと、Unity2Dの原点は(0,0)にあります。さて、tilemapの原点はどこでしょうか。

 

(0,0)を左下にもつタイル、(0,0)から見たら右上のこのタイルです。

タイルの原点

タイルの情報を指定するにはVector3Intでタイルのx,yを指定して取得します。(Vector3と書いてあるが、zは使わないと思う)

Vector3IntはInt型だけを許容する3つの値を持った配列ですね。

こちらもひとつ前の記事で紹介しましたがマウスの位置からクリックしたタイルを取得するには、マウスの指している座標の小数点を切り捨てすればよいのでした。

具体的なスクリプトは以下の通り。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;

public class GetClickTile : MonoBehaviour
{
    [SerializeField]
    Tilemap tilemap;

    private TileBase tile = null;

    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            //マウスの座標を3D空間の座標に変換
            Vector3 mousepos = Camera.main.ScreenToWorldPoint(Input.mousePosition);

            Vector3Int p = Vector3Int.zero;
            //小数点を切り捨て
            p.x = (int)Mathf.Floor(mousepos.x);
            p.y = (int)Mathf.Floor(mousepos.y);
            p.z = 0;


            if (tilemap.HasTile(p))
            {
                tile = tilemap.GetTile(p);
                Debug.Log(tile.name);
            }
            
            //tileをつかって何かする
        }
    }
}

このスクリプトを作成し、ヒエラルキーで新しいGameObjectを作ってこれをアタッチ、インスペクターでtilemapをアタッチしたら、おそらくクリックしたタイルの名前がコンソールに表示されるんじゃないでしょうか。

スクリプトの中では、Input.GetMouseButtonDown(0)で左クリックのタイミングを取得し、その中でCamera.main.ScreenToWorldPoint(Input.mousePosition);を使ってマウスの座標をとっています。

Input.mousePositionだけでいいじゃないかと思うかもしれないですが、これは画面の左下を(0,0)、右上を(解像度の幅分のピクセル数,解像度の高さ分のピクセル数)でとった時のマウスの位置座標を返してきます。

これだとUnityの2D空間(真ん中が(0,0)のxy座標)とは別物になってしまうので変換が必要なんですね。

次にMathf.Floor関数を使ってマウス座標の小数点を切り捨てています。

ちなみにマイナスの場合はというと、こちらもうまくできているんですね。感心しました。

2D空間の座標とtilemapの座標のところで説明したように、例えば0.6→0となると都合がよいのですが、-1.5→-1と切り捨てされてしまうとちょっと困ったことになるんですね。

しかしよくできてる。Mathf.Floorなら-1.5→-2という風に、より下の値に切り捨ててくれる。

逆に言うと1.5→1、-1.5→-1に切り捨ててほしい人は注意が必要ですね。

あとはこれをtilemapのgetTileに渡してしまえば完了です。

 

このシステムを応用すると、マウスのクリックした座標じゃなくてキャラクターの座標なんかを渡せばその下の座標のタイルを取得するなど当たり判定や取得判定なんかもできそうですね。

 

ぜひ使ってみてください!

kenoでスタ。また。