Unity3D+シューティングゲームのオブジェクトプールのチュートリアル

Blogをいつもご覧いただきありがとうございます。

シューティングゲームを作った時に、武器の弾のシステムは様々な書き方がありますが、一番シンプルな書き方は、恐らく弾のオブジェクトをインスタンスして、敵にヒットしたら(コード側ではコライダーやポジションでどちらでも可能です。)、敵と弾一緒に消滅すると思います。

弾を生成する場合の例:

using UnityEngine;
using System.Collections;

public class BulletInstance : MonoBehaviour {
public GameObject BulletPrefab;
// Update is called once per frame
void Update () {                                                                                                            
 GameObject bullet = Instantiate(BulletPrefab, Vector3.zero, Quaternion.identity) as GameObject;   //弾をインスタンス 
}

弾と敵を消滅する場合の例:

using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour {

void OnTriggerEnter(Collider other)
 {
   if (other.tag.CompareTo("Bullet") == 0)
    {
       Destroy(other.gameObject);//弾が消される
       Destroy(this.gameObject);//敵自分が消される
    }
 }
}

この書き方は普通に動くはずですが、でも、常に弾のPrefabをインスタンスしたり、Destroyしたりしたら、メモリー上にとってあまり優しいとはいえません。正直に言うとPC用としてはまだしも、スマートフォンゲームの場合はかなりきびしいものになると思います。
オブジェクトをずっと増やし続けるとゲームのFPSが落ちたり、重くなったり、スマートフォンが熱くなったりするのもおかしくないです。

それをさける為に、考えを逆にするのはどうでしょうか?

プログラム側では、オブジェクトのInstanceやDestroyの場合にリソースを消費しているとしたら、なら、常にInstanceやDestroyしないシステムを作ればいいじゃんないか?

それでは、オブジェクトプールを勉強しましょう!

·オブジェクトプールの概念

オブジェクトプールとは、この先使えるオブジェクトを溜めておく用の倉庫のような存在で、オブジェクトが必要になったら取り出し、使い終わったら戻すことで、なるべく少数のオブジェクト使い回してオブジェクト数及び生成・消滅のコストを抑えるものです。

それでは、実際にUnity3D側で作っていきましょう。

·実装

Step1 Unityの環境作り

Step2 弾のプールシステム

ここで二つのスクリプトが必要です。

  • BulletPool.cs  このスクリプトはオブジェクトプールで、オブジェクトにドラッグドロップする必要はありません。
  • Bullets.cs     このスクリプトは弾のPrefabにドラッグドロップするスクリプトです,弾の方向やスピードをコントロールしています。
実装コード:

BulletPool.cs

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

public class BulletPool : MonoBehaviour {
    //オブジェクトのプールとしてのリストを作る
    List pools = new List();
    // start pos
    Vector3 firstPosition;
    //シングルトン
    private static BulletPool instance;
    private BulletPool() { }
    public static BulletPool GetInstance()
    {
        if (instance == null)
        {
          
            instance = new GameObject("BulletPool").AddComponent();
           
        }
        return instance;

    }
   
    //オブジェクトプールからオブジェクトを取得する
    public GameObject MyInstantiate(GameObject name)
    {
        //オブジェクトプールは空だから、インスタンスする
        if (pools.Count == 0)
        {
            return Instantiate(name, Vector3.zero, Quaternion.identity) as GameObject;
        }
        else 
        {
           
            //もしプールでは空じゃない場合は「0」を取る
            GameObject go = pools[0];
           
            go.SetActive(true);
            //オブジェクトプールから消される
            pools.Remove(go);
            return go;

        }
    }
    //オブジェクトプールを作成
    public void DelayInstantiate(GameObject name)
    {
        //オブジェクトを隠す
        name.SetActive(false);
        //オブジェクトプールに入れる
        pools.Add(name);
    }
}

Bullets.cs

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

public class Bullets : MonoBehaviour
{
    Transform target;
    private void OnEnable()
    {
        //ポジションを初期化する
        target = GameObject.Find("Hero").transform;
        transform.position = target.position;
        //二秒の後でCoroutineを実行する
        StartCoroutine(DelayObject(2f));
    }
    private void Update()
    {
        //弾の移動
        transform.Translate(Vector3.up * Time.deltaTime * 100);
    }
   
    IEnumerator DelayObject(float time)
    {
        yield return new WaitForSeconds(time);
        //弾のプールリストに入れる
        BulletPool.GetInstance().DelayInstantiate(gameObject);
    }

}

 

Step3 Playerのコントロール

弾のプールを実装完了したら、次は発砲の機能や移動の機能が入ってる”PlayerControlManager.cs”を「Hero」のオブジェクトにドラッグドロップしてください。

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

public class PlayerControlManager : MonoBehaviour {

    float _hor_Speed = 1f;    //水平移動の速度
    float _ver_Speed = 1f;  //垂直移動の速度 
    float _topMax = 300f;//Player移動制御の変数
    float _bottomMax = -300f;//Player移動制御の変数
    float _sideMax =177f;//Player移動制御の変数
    float _turnAngle = 45;//回転の角度
    GameObject bulletPrefab;
    void Awake(){
        bulletPrefab = Resources.Load("Prefabs/Bullet") as GameObject;

    }
    void Update()
    {
        Move();
        TurnBody();
        Limit();
        Fire();
    }

    void Fire()//発砲
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            BulletPool.GetInstance().MyInstantiate(bulletPrefab);
        }
    }
    
    void Limit()//移動制御
    {
        if (transform.localPosition.x > _sideMax)
        {
            transform.localPosition = new Vector2(_sideMax, transform.localPosition.y);
        }
        if (transform.localPosition.x <  -_sideMax)
        { 
            transform.localPosition = new Vector2(-_sideMax, transform.localPosition.y); 
        } 
        if (transform.localPosition.y > _topMax)
        {
            transform.localPosition = new Vector2(transform.localPosition.x, _topMax);
        }
        if (transform.localPosition.y < _bottomMax)
        {
        transform.localPosition = new Vector2(transform.localPosition.x, _bottomMax);
        }
    }

    void TurnBody()//機体を回転する
    {
        if (Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.LeftArrow))
        {
            transform.Rotate(new Vector3(0, _turnAngle, 0));
        }
        if (Input.GetKeyDown(KeyCode.D) || Input.GetKeyDown(KeyCode.RightArrow))
        {
            transform.Rotate(new Vector3(0, -_turnAngle, 0));
        }
        if (Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.LeftArrow))
        {
            transform.Rotate(new Vector3(0, -_turnAngle, 0));
        }
        if (Input.GetKeyUp(KeyCode.D) || Input.GetKeyUp(KeyCode.RightArrow))
        {
            transform.Rotate(new Vector3(0, _turnAngle, 0));
        }
    }
    void Move()//Playerの移動
    {
        float ver = Input.GetAxis("Vertical");
        float hor = Input.GetAxis("Horizontal");
        transform.position +=new Vector3(hor * _hor_Speed, ver * _ver_Speed, 0);
    }

 }

   

上記の流れに沿って実装ができたら、プロジェクトをPlayしてください。

こんな感じですね

·注意点:

  • オブジェクトプールは非常に便利です。使う場面として繰り返し利用するオブジェクトを生成する場合に有効です。今回の場合は弾や敵などです。
  • 使う場合によっては逆効果が出る可能性もあります。実際にゲームのジャンルやシステム、オブジェクトの特徴などによって、どのような形式のオブジェクトプールを使うのか考える必要があると思います。
  • オブジェクトを破棄する代わりに隠す(表示しないようにする)ことで、表示的には破棄と同等の効果実現してます。そのおかげでオブジェクトをインスタンス化する際のリソースの無駄な消費を抑えられると思います。

※補足情報としてオブジェクトプールを利用することで、オブジェクトのインスタンス化をできるだけ削減しましたが、既にインスタンスされたオブジェクトはSetActive(false)になっても、まだメモリーの中に存在し、メモリーの容量を占有しています。メモリの占有が完全になくなるわけではありません。

ご覧いただきありがとうございました。

Unity_PostProcessing機能の有効化

あるシーンが、「PostProcessingのエフェクトが適用されているシーンのはずなのに自分のPCで開くと見た目が通常と変わらない。」
上記のような場合は、Unity PostProcessing Stackがインストールされているかをチェックしてみてください。

確認方法は下記のとおりです。
1.メニューバーのWindow->Package Manager をクリック。

inst_PostProcessing_Stack01_Image
inst_PostProcessing_Stack01_Image
Image_of_inst_PostProcessing_Stack02
inst_PostProcessing_Stack02_Image

2.Allのタブ(①)をクリックし、スクロールダウンしてPost Processing(②)を選択します。
3.右上のInstallボタン(③)を押してインストールします。

この手順でシーンのカメラに設定された、Post Processingの効果が確認できると思います。

Unity3D+IK(Inverse Kinematics)のAnima2Dチュートリアル

Blogをいつもご覧いただきありがとうございます。

前回は「Unity3D+Anima2Dチュートリアル」というテーマの記事を投稿しました。

今回はAnima2dのInverse Kinematicsについて説明したいと思います。

Inverse Kinematicsとは何ですか?

Anima2Dには、Inverse Kinematicsのコンポーネントがあります。これを使い、親関係のボーンオブジェクトの子供を動かすと、親も連動し動きます。

例を挙げると、腕と肩の関係のようなものです。(以下省略”IK”です)。

シンプルなアニメーションは、ボーンをいじるだけで充分ですが、もしアニメーションが複雑な場合はかなり時間がかかると思います。

そういう場合は「IK」が便利です。移動させたいボーンを「IK」と繋げればこのボーンのチェーンを丸ごと動かすことができとても便利です。

 

IKの種類は?

 

Anima2DのIKには,IK CCDIK Limb という2種類のIKがあります。

IL Limbは骨を2本しかコントロールできません、余弦定理ですので、今回の場合手足に利用します。

IK CCD は設定に応じて、最大コントロールできる本数がルートボーンまでの全部の骨をコントロールすることができます。今回の場合頭と尻尾に使います。

 

では、前回の引継き、IKの使い方を説明します。
IKをの使い方を説明する前に、先ずAnima2Dの効率をアップでさせる機能を紹介したいと思います。

「PoseManager」というものです。

使い方はとても簡単です。下記の画像のように、前回の「牛」のオブジェクトに「Pose Manager」を入れれば、使えるようになるはずです。

そして、「Create new pose」をクリックしたら、今のスプライトのポジションとローテーションがセーブできます。

一つの「Idle」のポーズを「Save」をクリックしてから、後はどんな調整しても、ただ「Load」ボタンをクリックしたら、最初設定のポーズに戻れます。(ちなみに、「Save」はオーバライドしますので、ご注意ください。)

「Pose Manager」の使い方はここまでです。

それでは、「IK」の使い方の説明に入りましょう。

Step 1: IKをクリエイトします

「牛」のオブジェクトの中に、もう一個の空のオブジェクトを作って、名付け「IK」です。

下記の画像のようにそのオブジェクトに右クリックして、「2D Object」→「IK Limb」をクリックしたら、「IK」が出ます。

では、「IK」のパラメータを説明しましょう。

  • Record:アニメーションモードの間,ボーンのキーフレームを記録します。
  • Target: IKが適用されるボーン。
  • Weight:​IKのポーズに対する影響度。
  • Restore Default Pose: 計算を実行する前に最初のポーズを設定します。
  • Orient Child:ターゲットの子ボーン(使用可能な場合)をIKローテーションに回転させます。
  • Num bonesIKの影響を受けるボーンの数.最大はルートボーンまで。
  • Iterations solverの反復回数。
  • Dampingソルバのステップ速度を制御する.値が小さいと変化が見やすい,大きいと変化が見にくいです。Dampingの値が大きければ、もっと自然に見えるかもしれません。

 

Step 2:「IK」をコントロールしたい関節に配置します

下記の画像のように、三つの「IK」をクリエイトして、分かりやすい名前を付けてから、それぞれにコントロールしたいところに置いてください。

上記の説明の通り、「頭」の部分には、使っているのはIK CCDです。

お気付きだとおもいますが、このグレーのリングを自分が望んでいる所に配置しても、スプライトはまだコントロールできません。

なぜかというと、下記の画像表示の通りに、右側の「Inspector」の「Target」はまだ「None」になっていますので、コントロールできるオブジェクトはまだありません。

では、「Target」に相応の「Bone」オブジェクトに入れてみてください。

設定が終了したら、グレーのリングは青のリングに変わります。

では、下記の画像の手順通りにすれば、左側のコントロールしたい「IK」のオブジェクトをクリックして、右側のリングを移動したら、「牛」全身が一緒に動きます。

注意点:偶にリングを移動しても、欲しい角度に合わせられない場合があったら、下記の画像の状態で「IK」の「Inspector」の「Filp」のチェックを入れてから、もう一度調整すれば、合わせられると思います。

適用後の図:

これで、「IK」のリングを弄れば、簡単に関節が調整できるようになりました。

複雑なボーンが入っているスプライトでは、「IK」はとても役に立ちます。

今回のインバース キネマティクス(IK)の使い方はここまでになります。

では皆さん、次回の内容をご期待ください!

Unity3D+Anima2Dチュートリアル

Blogをいつもご覧いただきありがとうございます。
先日、「Unity+Myo(ジェスチャーを活用して牛乳を搾るゲームを作りました)」というテーマのブログを発表しました。

下記のURLはゲームの映像です。
https://www.youtube.com/watch?v=4Jz7y1n3Iec

その中の「牛」はAnima2Dプラグインを利用して制作しました。Anima2Dの使い方のチュートリアルとして今回はAnima2Dを利用して「牛」を動かしてみましょう!

Anima2Dのメリットは?
  • Unity3Dのアニメーションと同じ感覚で2Dキャラクターが動かせます。
    • スキニングとBoneが付くアニメーションを作ることができます。
    • Spriteの各頂点編集することができます。
    • 全部アニメーション(Unity3Dの標準機能)でコントロールすることができます
Step1 Anima2Dをインストール
  • AssetStoreからAnima2Dを検索し、ダウンロードしてから、インポートをしてください。
Step2 「牛」の画像を分割

上記の画像はまだ分割していない状態です。

ゲームでは「頭」、「足」二本、「体」を分けたいので、こちらで「Gimp2」でこの4つの部分を分割しました。

そして、分割した画像をUnityにインポートして、下記の状態になりました。

画像のInspectorのTexture TypeSprite (2D and UI)に変更するのを忘れないで下さい。

これで、下準備は完了です。

Step3 SpriteMeshを作る

ここから本番ですね。先用意した画像を選択して、右クリックしてSpriteMeshが作れます。( Create→Anima2D→SpriteMesh)

上記のステップで、拡張子が「asset」のファイルができると思います。保存先が分からなくなってしまわぬよう独立のフォルダーを入れるとよいと思います。

Step4 SpriteMeshをSceneに配置

これから、作り上げたSpriteMeshをシーンに配置します。

まず、シーンにempty GameObjectを作って、この中で二つ空のGameObjectを作ります。下記の画像ご参考までに。

そして、SpriteMeshを一個ずつBodyのGameObjectに入れます。(一気に全部選択しても一個ずつしか入りませんので)

全部入れて、元「牛」の四肢のようにポジションを調整したら、下記の画像のようになるかと思います。

Step5 SortingLayer、OrderLayerの調整

ですが、牛の頭が体に隠れてしまってるように見えますので、そこで、OrderLayerの順位を調整します。

  • 先ず、SpriteMeshのSortingLayerを全部同じにします。SpriteMeshのオブジェクトを選択して、右側は下記のようにします。

デフォルトの状態で全部のSpriteMeshのOrderLayerは0になっていますので、一番前に表示したい物のLayerの順位を0より大すると前面に表示できます。

今回の場合は牛の頭を体の前に表示しようと思いますので、頭のオブジェクトを選択して、OrderLayerは1にすれば、一番前に表示できるようになると思います。

これで、SortingLayerとOrderLayerの説明は維持上です。

Step6 Boneを入れる

これがAnima2Dのとても大事な機能です。スプライトに骨を付けることができます。

先ず、先ほど作ったBoneというゲームオブジェクトに右クリックしてください。

下記の画像のように選択します。

こうすれば、新しいBoneオブジェクトがインスタンスされます。自分が分かりやすい名前を決めてください。

そして、「Torso」の中で頭、両足の2DBoneを作って、針みたいなものを相応の所に配置します。

注意点:上記の赤い箇所で示している所は「骨」の長さです、スプライトの大きさに相応して決めてください。

そして、BoneとSpriteMeshを繋げましょう!

下記の画像の通りにそれぞれのBoneオブジェクトをSpriteMeshのSet bonesの所に入れます。

注意点:繋げたくない部分があれば、右クリックで削除してください。

これで、BoneとSpriteMeshは繋がりました。

とは言え、Boneを動かしてみたら、Meshの方は全然ついて来きません。それはなぜでしょうか?次のステップで解決していきます。

Step7 SpriteMeshはBoneと一緒に動かす

SpriteMeshはBoneと一緒に移動できるようにする場合は、先ず、移動させたいSpriteMeshを選択したまま、「Window」をクリックしてください。そして、「Anima2D」→「Sprite Mesh Editor」を押してください。

開いたら、下記の画面が表示します。

注意点:赤い箇所は頂点の数がコントロールできます。今回はデフォルトの設定で十分だと思いますので、デフォルトのままで行きます。

次は「Bind」の方に進みましょう。

設定する前に、先ず右下の「Overlay」をチェックしてください。そして、影響範囲が可視化されてもっとわかりやすくなるのでしょう。

次は右上の「Apply」を押したら、MeshとBoneは一緒に動かすことができるはずです。

全部上記の設定が完了すると、牛の頭を移動しても体のSpriteMeshも一緒に連動して動きます。

次回はインバース キネマティクス(IK)の使い方を説明したいと思います。

Unity+Myo(ジェスチャーを活用して牛乳を搾るゲームを作りました)

Blogをいつもご覧いただきありがとうございます。先日「Myo」のジェスチャーでゲームを作ってみましたので今回はここでジェスチャーの使い方を紹介しようと思います。

下記のURLはゲームの映像です。
https://www.youtube.com/watch?v=4Jz7y1n3Iec

· Myoってどんなもの?

Myoアームバンドは、腕、手首、指のジェスチャーで、デバイスをワイヤレス操作することができます。

下記のURLはMyoの公式サイトです。
https://www.myo.com

· Myoのジェスチャーの紹介

デフォルトで認識するプリセットジェスチャーは下記のとおりです。

· グー(Fist)
· パー(FingersSpread)
· ダブルタップ(DoubleTap)
· 手首で手を左に仰ぐ動作(WaveIn)
· 手首で手を右に仰ぐ動作(WaveOut)
· リラックス(Rest)

「グー」と「パー」を合わせて、モミモミすることができそうなので、私はこの二つのジェスチャーを利用して牛乳を搾るゲームを作りました。それでは、ジェスチャーの部分に入りましょう。

· sdkの導入

環境状況:
Unity2018.1.0f2
SDKバージョン:Windows SDK 0.9.0
Firmware: 1.5.1970
https://developer.thalmic.com/downloads
SDKを持っていない人は上記のサイトからダウンロードできます。

SDKをダウンロードして、Unityにインポートしましたが、エラーが三つ出ました。

エラーが発生しているスクリプト(ColorBoxByPose)をチェックしたら、レンダリングの設定の書き方が古すぎますのでUnity2018.1.0f2(恐らくUnity2017以降のバージョン)では、書き方を変える必要がありますね。

では、そこの書き方を変えましょう!

上記のように修正してエラーが消えるはずです。

次はMyoをコントロールするために、SDKが用意してくれたプリハブをシーンに入れます。

サンプルシーンの中で「Joint」というGameObjectがあります。このGameObjectに存在するスクリプト(JointOrientation)がMyoデバイスの方向を管理しています。これをプリハブにして、自分のシーンに適用します。

方向を制御するスクリプトできたので、次はジェスチャー検出のコードですね。

それでは、ジェスチャー検出用のスクリプトを作りましょう。

そのオブジェクトに自分が作った「gManager」を入れて、ジェスチャー検出のコードを全部このスクリプト内に記述することにします。

これで、SDKのプラグインの導入が完了しました。

· ジェスチャー検出

例:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pose = Thalmic.Myo.Pose;
public class GestureManager : MonoBehaviour {
Public GameObject myo;
ThalmicMyo thalmicMyo;
void Start () {
  thalmicMyo = myo.GetComponent<ThalmicMyo>();
 }
void Update () {
  Fist();
  Stroke()
}
//ジェスチャーは「グー」の時
void Fist()
 {
   if(thalmicMyo.pose == Pose.Fist)
   {
   /*この部分は「グー」の処理の内容
   (牛乳を搾る機能を埋め込みました)
   */
   }
 }
//ジェスチャーは「パー」の時
void Stroke()
 {
  if(thalmicMyo.pose != Pose.Fist || thalmicMyo.pose == Pose.FingersSpread || thalmicMyo.pose == Pose.Rest)
  {
  /*この部分は「パー」の処理の内容
  (ここで手を離す機能と牛を撫でる機能を埋め込みました)
  */
  }
 }
}

「撫でる」機能は正確に言うと「パー」かリラックスの状態で手首や腕を振るという動作です。
上記のコードの通りにvoid Stroke()関数の中にMyoのジャイロの処理を埋め込めば「撫でる」ができます。

例:

void Stroke()
{
  if (thalmicMyo.pose != Pose.Fist || thalmicMyo.pose == Pose.FingersSpread || thalmicMyo.pose ==Pose.Rest)
  {
   if (thalmicMyo.gyroscope.magnitude > 120f)
     {
       //gyroscopeのmagnitudeは120より大きい場合
      //(速く腕を振ると簡単に120を超えます。)
     }
    else if (thalmicMyo.gyroscope.magnitude < 10f)
     {
      //gyroscopeのmagnitudeは10より小さい場合
     //(腕が静止に近い場合)
     }
  }
}

ここまではもう方向変更と簡単な「グー」と「パー」の処理が実現できるようになりました。でもMyoのもう一つのスクリプト(ThalmicMyo)の内容をみていきましょう。

· ThalmicMyo

ThalmicMyoはMyoのSDKの中でコアの部分です。

下記に主要な変数名を説明します。
· ArmSynced:boolタイプの変数で、trueになったらMyoデバイスが検出できます。
·arm:左の腕と右の腕どちらかと設定できます。
·pose:Myoが検出したジェスチャを保存します。UnKnowは今のジェスチャーです。
·accelerometer:加速度の計算用のVector3タイプの変数です。約9.8 m/s^2です。
·gyroscope:今のジャイロの軸のスピードを検出できます。単位は「度/秒」
·isPaired:trueの時にMyoのデータが読み込めます。
·Vibrate:Myoが提供しているバイブレーションタイプです。三つの種類があります。

public enum VibrationType { Short, Medium, Long }

バイブレーションの書き方は下記の通りです。

例:

using VibrationType = Thalmic.Myo.VibrationType;
if(thalmicMyo.pose == Pose.Fist)
{
  thalmicMyo.Vibrate(Vibrate.Short);
}

上記の「撫でる」機能はThalmicMyoの変数を利用して実装してみました。

· 実装して気づいたこと

1.実装してみて素早いジェスチャでは認識までに若干のディレイをかんじました。デバイスの特性上仕方がない点かとおもいますが、頻繫にジェスチャーを素早くおこない操作するゲームはわりと不向きかもしれません。

2.Myo Connect(Mac/Windows上のデフォルトマネージャー)をつかってキャリブレーションを行ったほうがやはり操作感が向上します。(PC用にビルドしたアプリのみで利用可能)

3.キャリブレーションをする時にゲームをする際と同じ腕のポジションでキャリブレーションするとジェスチャの認識向上におすすめです。

4.UnityでAndoroid用のビルドをためすために、有志の方が開発したandroid+UnityのSDKのGitHubにアップされたパッケージを利用してためしました。

ただ、Myo Connectのような、マネージャーソフトがない為キャリブレーション、個人のプロファイルの設定ができないの理由で、腕の方向やコントロール精度は満足いくものにはなりませんでした。

Unity3Dタイルマップ作成時の注意点

Unity3D has a tile map system that allows you to make 2D maps with no programming at all. This tool is available for free with the unity base package and can be expanded with the 2D extras package found in unity’s GitHub. It’s fairly easy to use but if you are not careful when setting it up you could have a hard time.  

Unity3Dのタイルマップはプログラミングなしで簡単2Dのマップを作れるツールです。このツールはUnity3Dのベースパッケージに入ってて、UnityのGitHubにある2D-extrasのパッケージで機能拡張できます。使いやすいものですがセットアップで間違えると痛い目に会います。 

On this post I will be going through a couple details that you should take in account when making your tile map. 

このポストでは、タイルマップを作っている時の4つの注意点をあげます 

1.スプライトシート 

Tiles usually come in sprite sheets. A sprite sheet is an image containing a series of smaller images most commonly of the same size and organized in columns and rows. 

普段はタイルがスプライトシートにあります。スプライトシートというのは小さくて同じサイズの複数のイメージが含められているのイメージをさします。 

After importing a sprite sheet into your project. Unity allows you to divide the sheet into individual tiles. To do this you click on the sprite sheet and look at the inspector, the texture type should be “Sprite (2D and UI)” and the sprite mode set to “Multiple”. To start the division process click on the Sprite Editor button. During this process there are a couple factors you should take in account: 

Unityにインポートをして選択されたままにInspectorで複数のイメージにスライスが可能です。このプロセスに注意点が二つあります。 

  • Pixels per unit :  Before even going into the Sprite Editor make sure that the value of the “Pixels Per Unit” parameter on the inspector is the same size of your tiles. E.g: if your sheet is holding 64×64 px tiles then make the “Pixels per unit” 64. If you forget this step your tiles will have padding or overlap each other. 
  • Pixels Per Unit: 「Sprite Editor」に入る前に「Pixels Per Unit」のパラメータがタイルのピクセルサイズと同じにしないといけません。例えばスプライトシートに64px✖64pxのタイルが入ってたら、「Pixels Per Unit」を64に設定してください。設定が違うとパディングがはいったり、タイルが重なったりします。
  • Pivot: When using the slice tool in the Sprite Editor. Make sure to set the pivot to “center”. If you miss this step the tiles will be offset from the grid in the scene.
  • Pivot: スライスツールを作っているときに、「Pivot」のパラメータが「Center」を選択しないと、タイルがシーンのグリッドからオフセットされます。 

2.コライダー 

Sprites are just the visual part of our tiles. Without colliders, even if we can see the ground, our characters would just fall off the world. Unity made it very easy to add colliders to your grid. Just select the tilemap and add a “Tilemap Collider 2D” component to it. This is fast and easy but it creates a collider for every tile with a sprite on it. This means that even tiles surrounded by other tiles that will never be in contact with anything will also have a collider. I.e: A lot of unnecessary colliders that will never be used and use resources are being created. 

スプライトはタイルの見た目だけのものなのでコライダーを付けないと、床を見えても、キャラクターが突き抜けて落ちます。コライダーを付けるのは簡単にできます。Tilemapのオブジェクトに「Tilemap Collider 2D」というコンポーネントを付けることで付けますが、これで全てのタイルにコライダーが適用されてしまいます。言い換えるならば一回も使わない無駄なコライダーが生成されてリソースを余分に使っています。 

 

To prevent this, we can add an other component. The “Composite Collider 2D” component. This component requires a little bit of setup. When this component is added to your tilemap GameObject, it automatically adds a RigidBody2D component to the object. If you are adding collision to static objects like the ground or a wall, make sure to set the “Body Type” of the RigidBody2D component to “Static” or it will fall down with gravity. Now go back to your “Tilemap Collider 2D” component and tick on the “Used By Composite” box. This will merge you colliders leaving only the outer colliders. 

これを防ぐためもう一個のコンポネントを付けられます。「Composite Collider 2D」というコンポネントです。追加するときに自動でRigidBody2Dが追加されます。もし動かない物のコライダーを作っているときに(床、壁、など)RigidBody2Dの「Body Type」を「Static」にしないと重力で落ちます。最後に「Tilemap Collider 2D」の「Used By Composite」を選択することで内側の無駄なコライダーがなくなります。

 

3.Rule Tiles: 

Rule tiles are part of the “2D extras” package you can find in Unity’s GitHub (https://github.com/Unity-Technologies/2d-extras).  

UnityのGitHubの”2D-extras”のパッケージにRule Tilesという物があります。(https://github.com/Unity-Technologies/2d-extras).  

This tiles can save you a lot of time when map designing, by allowing you to create a set of rules for which sprite is displayed depending on the tiles around it.  

このタイルのルールを設定するとマップをつくる際にタイルのスプライトを周りにあるタイルを見て設定されるので、これレベルデザインの時間を節約できます。 

 

Rule tiles also make it easy to create tile animations. 

そして、タイルアニメーションもつくれます。 

 

One thing to take care of when setting up this rules is the order you add them to the list. When unity is checking your list of rules it stops and selects the first sprite that fulfills the rule. So if you have a more specific set of rules after a very general one, it might be ignored. 

ルールを設定するときの注意点はルールの順番です。Unityがチェックするたびに先にルールに一致するスプライトが選択され、残っているルールを無視します。つまり、幅広いルールを持っているスプライトの次に細かいルールを適用するものがあった場合、幅広いルールに合致して、細かいルールが無視される可能性が高いです。 

 

Getting the tiles to work as you intend them to, might take some time but once you have it set up, it will speed up your map making time. And if you decide to change a sprite midway through the map design, you can just change the sprite for that rule without having to touch the tiles in the scene. A good rule of thumb is to keep the tiles with very specific rules at the top of the list and the more general ones at the bottom. And remember you can drag the rules up and down within the list to change the order easily. 

思った通りに設定するには時間がかかるかもしれませんが、一度設定したら、マップ作りがスピードアップします。そして途中でタイルのスプライトを変更したい場合もシーンにあるタイルを作り直しは必要ないです。そのルールのスプライトを変更することで済みます。経験を積んだら設定時間も減ります。ヒントとしては細かいルールを幅広いルールより先に付けること。リスト内での順番がドラッグで簡単に変更できます。 

4.レイヤー: 

Layers are powerful tools that help us keep rendering orders separate, make pretty overlaps and set colliders to some objects while ignoring others. But it’s important you keep track of the layer you are working on at all times, because just as any other software that uses layers like Photoshop or Gimp, editing the wrong layer will cause you problems. So if you run into some weird behavior like colliding into clouds, falling through the ground or tiles not animating correctly, make sure you check everything is on the right layer. To help you with this Unity has an option to gray out all layers except the one you are working on. This option can be turned on by changing the “Focus On” parameter located on the Scene window to “Tilemap.  

レイヤーは非常に便利なツールでレンダリング順を設定するのに役立ちますが、PhotoshopやGimpのように間違えたレイヤーに間違えたタイルを入れるミスは起こりやすいので気を付けないといけません。雲にぶつかったり、床を突き抜けたり、タイルアニメーションが変になったりしていた場合は、レイヤーに正しくアサインされているかの確認をおすすめします。レイヤーに関するトラブルを防ぐためにUnityには変更中のレイヤー以外のレイヤーをグレーアウトする機能を持っています。シーンにあるの「Focus On」パラメータを「Tilemap」に変更することで起動されます。