kazumalab tech log

流行りとリラックマと嵐が大好きです。技術的ログ。

ゲームでよくある現在地を表す地図をUnityで表示させる方法

かずまです。

ゲーム画面のどちらかに小さいマップ、現在地が表示されているコンテンツもあります。
これUnityだったらめっちゃ簡単じゃない?と思って実装してみました、のメモです。

いや、自分でやると簡単だけどここに書くのは大変でした…。


今回は作ってるゲームに導入してみました。
イメージはこんな感じです。

(注意)今回はキー入力によるプレイヤーの動き、Nav Mesh AgentによるEnemyの動きが付いているという前提で行っています。

f:id:kazumalab:20160823020831g:plain

Playerは白、Enemyは赤です。

用意するもの

Player,Enemyの画像

f:id:kazumalab:20160823025457p:plain,w100,h100
実際使っているのは白色で、カラー指定しています。
以下の文ではこのUI画像のことをplayer_imageと呼びます。

Mapと同じ形の画像

今回は正方形の地形なので正方形の画像を用意しました。
以下の文ではUI画像のことをmap_imageと呼びます。

マップの作り方(これは面倒。。。笑)

1. 見下ろしたスクショをとる
f:id:kazumalab:20160823042935p:plain

2. PhotoShop等に取り込んでトリミングしてpngで保存

3. Unityのスケール × 10のPixelで新規作成
f:id:kazumalab:20160823043158p:plain

4. 先ほどトリミングしたのを入れて両端をあわせる
f:id:kazumalab:20160823043343p:plain

これでpngの透過で保存してUnityに突っ込む!
ほんと遠回りで面倒。いい方法ないですかね。

UIの設定

Canvas以下に空オブジェクトを生成し、名前をMaskに変更します。
次にMaskの設定します。
f:id:kazumalab:20160823023717p:plain
Mask内はこんな感じです。
f:id:kazumalab:20160823023928p:plain

Maskを設定する

f:id:kazumalab:20160823024147p:plain

今回は形を自由に変形させたかったので、Rect Mask 2Dは使わずにMaskを利用しました。
MaskのComponentにImageとMaskを追加します。
サイズは大体300 × 300ぐらいがいいかも・・・?
ImageのColorはmap_imageがない部分の色になるので暗めを入れておきます。

ImageのSpriteは円の白をPhotoshopで作り、それをいれました。
Materialを設定してしまうとMaskできないのでMaterialは空にします。

子オブジェクトの設定

Mask以下にMapの画像を入れます。
Enemyを使う場合はenemy_imageをmapの子オブジェクトとします。

map_imageの設定

サイズはMap(Object)に合わせてサイズを調整します。
ちょっとわかりにくいですが、
f:id:kazumalab:20160823030820p:plain
20、15というのはUnity上のスケールの事を表しています。
この場合、map_imageはScale width = 200, height = 150にします。全部終わったあとにずれていればサイズを変更することもあります。

位置はMaskの中心に持って行きます。
f:id:kazumalab:20160823035759g:plain
三角のやつも持って行きます。


ちょっと小さいとやりにくいです。

player_imageの配置、設定

先ほどのPlayerのイメージ画像をCanvas以下に表示します。
サイズは自分で調整してください。
位置はMaskの中心に表示します。

f:id:kazumalab:20160823035355g:plain

UIの設定は結構面倒ですがこれでOKです。

Player(GameObject)の設定とスクリプト

Player(GameObject)の設定

まずはPlayerのPosition (0, player.transform.position.y, 0)にします。
y軸は0にすると足などが地面を突き抜けてしまうので、そこは個人で調節します。

スクリプト

スーパークラスをCharactorMainController.csでそれをPlayer.cs , Enemy.csで継承しています。

解説

わかりにくいかと思います。
player_imageは動いているように見えますがmap_image自体が動いて、必ず中心にいます。
Mapのイメージの(0, 0)の位置とPlayer (GameObject)の (0, 0)は同じということになります。
Playerが位置(15, 15)に行くとmap_imageは位置(-15 * 10, -15 * 10)となります。

map_image (-94.7, -62.7)
f:id:kazumalab:20160823051630p:plain

Player (9.47, 6.27)
f:id:kazumalab:20160823051659p:plain

次にEnemyです。
enemy_imageは動いています。しかもEnemy(GameObject)と同じ座標関係になります。
さらにmap_imageの子オブジェクトなので親が動くと子も勝手に移動します。
つまりlocalPositionにしている理由はenemy_imageのmap_image内で位置(50, 50)であれば実際Enemyは位置(5, 5)にいることになります。

map_image (90 , 62.7)
f:id:kazumalab:20160823051858p:plain
Enemy (9, 6.27)
f:id:kazumalab:20160823051924p:plain

PlayerのInspector

f:id:kazumalab:20160823042032p:plain

EnemyのInspector(Enemyを入れる場合のみ)

f:id:kazumalab:20160823042112p:plain
EnemyではMapImageは使いませんがスーパークラスで定義しているので一応入れます。

もっと良い書き方ありそう・・・。

さて再生します。
大体合っていればOKです。

f:id:kazumalab:20160823043626g:plain

最後に

わからないところや間違っているところ、こうした方がいいというのがあれば気軽にチャットでお知らせください。
個人的にぱぱっと作ったのでいろいろ手間が入っています。