【Unity】2Dタイルマップ13 Playerが扉の前に移動したら扉を開く
Unity 2020.2.1f1 Personal(2021年3月)
前回の続きです!
今回はIsometricな2Dタイルマップにて、
扉のTileの前に来た時にドアTileを消して建物の中に入る機能を実装していきます。
TilePaletteにTileを登録する
まずはTilePaletteにTileを登録します。
以下のSpriteをUnityにアップして下さい。
stone_block.png
stone_wall.png
stone_wall_door_open.png
door_close.png
各SpriteはPixel per Unitを32、Filter ModeをPoint(no filter)に設定します。
またstone_wall、stone_wall_door_open、door_closeにColliderを設定します。
Sprite EditorのCustom Physics Shapeから設定できます。
stone_wallのCustom Physics Shape
stone_wall_door_openのCustom Physics Shape
door_closeのCustom Physics Shape
これらの設定が完了したら4つのSpriteをTilePaletteに登録します。
TilePaletteの作成についてはこちらの過去記事をご参照ください。
今回は名前を「IsometricPalette」、Tileに高さを与えるのでGridをIsometric Z as Yで新規作成して下さい。
TilePaletteに各Spriteを登録
Tilemapの作成とTileの配置
続いて登録したTileをSceneに配置していきます。
まずはTIlemapオブジェクトを作成します。
Hierarchyから2D Object > Tilemap > Isometric Z as Yで作成します。
作成したTilemapオブジェクトのTilemapRenderer > ModeをIndividualに変更します。
またTilemap Collider2Dをつけておきます。
今回選択したIsometric Z as YはTileのposition.zの値によって高さを表現することができます。
Isometric Z as Yを使う時はカメラ設定のTransparency Sort Modeを変更する必要があります。
高さの解説とTransparency Sort Modeの設定はこちらの記事をご参照下さい。
hiyotama.hatenablog.com
それではTileを配置していきます。
まずはZ Position:0から配置します。
TilePaletteのZ Positionを0に設定
Tileを配置
stone_wall_door_openタイルとstone_wallタイルを配置しました。
この2つの間にdoor_closeタイルを配置します。
door_closeを間に配置
door_closeタイルが消えた時にstone_wall_door_openのドア部分が見える仕掛けです。
続いてZ Position: 4のTileを配置していきます。
Z Positionを4に設定
Tileを配置
stone_blockタイルを3つ置いてTileの配置は完了です。
Playerの作成
続いてPlayerを作成します。
hiyotama.hatenablog.com
こちらの過去記事を参照してPlayerオブジェクトとControllerオブジェクトを作成して下さい。
Inspectorのみこちらにも掲載しておきます。
PlayerオブジェクトにはPlayer.cs・CircleCollider2D・Rigidbody2Dを取り付ける
ControllerオブジェクトにはPlayerController.csをつけPlayerとCameraを設定する
以上でプレイヤーを動かすことができるようになりました。
Playerがドアの前に来た時にドアを開く
最後にPlayerがドアの前に来た時にドアを開く処理を実装していきます。
先ほど作成したControllerオブジェクトにTilemapController.csを取り付けます。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Tilemaps; public class TilemapController : MonoBehaviour { public static TilemapController instance; [SerializeField] Tilemap defaultTilemap; private Vector3Int beforePlayerCellPos; private void Awake() { if (instance == null) instance = this; else Destroy(this.gameObject); } public void CheckCloseDoor(Vector3 playerPos) { Vector3Int playerCellPos = defaultTilemap.WorldToCell(playerPos); if (beforePlayerCellPos != playerCellPos) { OpenDoor(playerCellPos - Vector3Int.up); OpenDoor(playerCellPos - Vector3Int.down); OpenDoor(playerCellPos - Vector3Int.right); OpenDoor(playerCellPos - Vector3Int.left); beforePlayerCellPos = playerCellPos; } } private void OpenDoor(Vector3Int cellPos) { var tile = defaultTilemap.GetTile(cellPos); if (tile && tile.name == "door_close") { defaultTilemap.SetTile(cellPos, null); } } }
TilemapController.cs
CheckCloseDoorメソッドにPlayerの位置情報を送り、そこからPlayerが現在いるTileのCell位置を割り出します。
現在Cell位置が前フレームのCell位置と違う場合、Playerの前後左右のCell位置を引数にOpenDoorメソッドを呼び出します。
OpenDoorメソッドではGetTileでタイルを取得し、名前が「door_close」だった場合のみタイルを削除しています。
TilemapController.csのdefaultTilemapに今回作成したTilemapを設定します。
最後にPlayer.csからTilemapController.csのCheckCloseDoorメソッドを呼び出す記述を追加します。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { private readonly float speed = 0.03f; private void Update() { TilemapController.instance.CheckCloseDoor(transform.position); } public void MoveUp() { transform.position = new Vector3(transform.position.x + speed, transform.position.y + (speed / 2f), transform.position.z); } public void MoveDown() { transform.position = new Vector3(transform.position.x - speed, transform.position.y - (speed / 2f), transform.position.z); } public void MoveLeft() { transform.position = new Vector3(transform.position.x - speed, transform.position.y + (speed / 2f), transform.position.z); } public void MoveRight() { transform.position = new Vector3(transform.position.x + speed, transform.position.y - (speed / 2f), transform.position.z); } }
Player.cs
UpdateメソッドにてTilemapControllerのCheckCloseDoorメソッドを毎フレーム呼び出しチェックしています。
** 結果
Playerがドア手前のTileの上に乗った時にドアのTileが削除されドアが開きます。
今回は以上となります。
ありがとうございました〜。