これは ドリコムAdvent Calendar 19日目の記事です。
18日目は ikkou さんの アドベントカレンダーでニコニコカレンダーの話を書きたかった です。
asiramと申します。
現在はサーバサイドエンジニアをやっております。
まだまだぺーぺーです。
最近Unity2Dを触っていますが、これだけ知っておければかなりの範囲の2Dゲームをカバー出来そう、という要素があるように感じています。
まだまだ触りたてなので、間違いがあったら指摘してください...!
今回はよく使うコンポーネントやクラスのメソッドなどを紹介します。
言語はC#です。
おそらくここに書かれているものをひと通り知っていればいろんな2Dゲームが作れると思います!
Unity2Dのこれだけは覚えておけ!集
コンポーネント編
Sprite Renderer
言わずもしれたスプライトを表示させるためのコンポーネントです。
とりあえず、「Sprite」に設定したスプライトを表示出来ます
Transform
オブジェクトの位置・回転・大きさを決定するコンポーネントです。
空のGameObjectを作成した場合でも必ずアタッチされています。
この図では、位置(Position)が(1,0,0)、回転が(0,0,90)、大きさが(3,3,1)となっています。
回転はわかりやすく言うと、オブジェクトに対応する軸方向へ串を指し、串を回して該当する角度を回転させてやるイメージです。
大きさ(Scale)は、各軸方向に何倍のスケールで表示するかを表しています
transform.position = new Vector3(-1, 0);
このようにtransformのpositionにVector3を設定すれば、オブジェクトの位置を変える事ができます。
しかし、いきなり大幅にオブジェクトの位置を変えてしまうといわゆるワープになってしまい不自然です。
次の項目のRigidbody 2DコンポーネントのvelocityやAddForce()を使用して自然に移動するようにしましょう。
Rigidbody 2D
Rigidbody2Dは、物理挙動を担当するコンポーネントです。
物理エンジンの恩恵を受けられるようになり、重力を簡単にオブジェクトに掛けられたり、力をオブジェクトに加えて動かしたり出来ます。
上の図はRigidbody2Dをデフォルト設定のままアタッチした状態です。
このまま実行すると、オブジェクトは下に向かって落ちていきます。
これは、Gravity Scaleが1に設定されており、オブジェクトが重力の影響を受けるからです。
Gravity Scaleを0に設定すれば重力の影響を受けずに、その場にとどまり続けます。
Vector2 velocity
Rigidbody2Dが持つ、速度を表すプロパティです。
rigidbody2D.velocity = direction * speed;
このとき、directionはVector3(後半で説明します)でspeedはfloat値です。
どの方向にどれだけ速度を出すか、という感じです。
たとえば上記画像のオブジェクトのGravity Scaleを0にして、
void Start () {
rigidbody2D.velocity = transform.up * 1;
}
とすると、オブジェクトはオブジェクトの上方向に向かって動きます。
void AddForce(Vector2 force)
オブジェクトに力を加えるためのメソッドで、引数にはVector2を加える力としてとります
rigidbody2D.AddForce(new Vector2(0, 5));
これをStart()で一回だけ呼べば一回だけ力が加えられる事になりますが、Update()で何回も呼ぶと何回も力を加えることになるのでオブジェクトはだんだん加速していきます。
Gravity Scaleが0に設定されていれば重力の影響を受けないので、一回力を加えればそのままの速度を保ちます。
重力が設定されていれば、力を加えた後だんだん速度が落ちていきます。
Collider 2D
いわゆる当たり判定というやつです。
Collider2Dがアタッチされたオブジェクト同士の衝突を検知します。
Collider2Dはその形状によって、いくつかのクラスに別れており、「Box Collider 2D」「Circle Collider 2D」「Polygon Collider 2D」などがあります。
図の状態は、bouyaオブジェクトにRigidbody2DとBoxCollider2Dがアタッチされており、そのまま実行すると重力によってオブジェクトは落下します。
このとき、地面にあたるオブジェクト(黄色い線みたいなもの)にBoxCollider2Dをアタッチしておくと、地面オブジェクトとbouyaオブジェクトが衝突し、bouyaオブジェクトは地面に立っているような状態になります。
void OnCollisionEnter2D(Collision2D coll)
「何かオブジェクトが衝突したら、〜する」というパターンはよくあるかと思います。
自身に衝突したら呼ばれるイベントハンドラが、各衝突のタイミング別に定義されています。
「OnCollisionEnter2D()」は、自身に何らかのオブジェクトが入ってきたら(衝突したら)呼ばれるイベントハンドラです。
void OnCollisionEnter2D(Collision2D coll){
Destroy(coll.gameObject);
}
このように使えば、何らかのオブジェクトが衝突したとき、衝突した他のオブジェクトを削除出来ます。
引数のcollには衝突したオブジェクトを格納したCollision2Dオブジェクトが渡されます。
「OnCollisionEnter2D()」の他に、衝突し続けているときに毎フレームごとに呼ばれる「OnCollisionStay2D()」や衝突状態から離れた時に呼ばれる「OnCollisionExit2D()」イベントハンドラなどがあります。
やりたいことによって使い分けましょう。
クラス編
Vector3とVector2
Vector3とVector2は要するにベクトルというやつです。
向きと大きさを持ったアレです。
Vector2は二次元で用いるベクトルなので、
Vector2 v = new Vector2(35, 35);
このようにxとyの値を指定してインスタンスを作成します。
上記のVector2オブジェクトは以下の様な状態です。
Vector3はx,yに加えzも加えたベクトルを表すクラスです。
基本的に使えるプロパティやメソッドは同じです。
float magnitude
ベクトルの長さを表すプロパティです。
上記の図の緑色矢印の長さを返してくれます。
float sqrMagnitude
ベクトルの長さの2乗を返すプロパティです。
magnitudeより軽量で、ベクトル同士を比較するのに適しています
Vector2 normalized
1の長さのベクトル(magnitudeが1であるVector2オブジェクト)を返すプロパティです。
単位ベクトルというやつで、該当ベクトルの向きだけを取り出せます。
このプロパティに数値xなどを掛けてあげれば、任意の向きを向いた長さxのVector2オブジェクトが出来上がります。
Mathf
Unityではゲームを作る上で便利な数学関数が追加されたMathfクラスを使うことができます。
float Clamp(float value, float max, float min)
valueを最大max、最小minにおさめてくれるメソッドです。
float v = Mathf.Clamp(34.13f, 20, 32);
このようにするとvalueがmaxの32を超えているので、vは32になります。
float Round(float f)
小数点以下を四捨五入を行い、整数を返すメソッドです。
他にもいろいろあります!
Input
入力を司るクラスです。
キーボードからの入力や加速度センサからの入力を取得できたりします。
float GetAxisRaw(string axisName)
指定した入力から入力値を取得できます。
この値をrigidbody2dのvelocityやAddForce()に上手く渡してあげれば、それだけでオブジェクトの移動を実現することができます!
以下のようにすれば、キーボードの上下キーと左右キーからの入力を得られます。
float x = Input.GetAxisRaw ("Horizontal"); //左右
float y = Input.GetAxisRaw ("Vertical"); //上下
bool GetKeyDown(string name)
指定したキーがその瞬間に押されたかどうかをbool値で返します。
if(Input.GetKeyDown("space"))
print("space key was pressed");
Touch
今どきのスマホはみんなタッチスクリーンを備えています。
タッチ情報を得られるクラスがTouchクラスです。
Touchクラスのインスタンスを得るには、InputクラスのGetTouch()メソッドを使用します。
引数には何番目のタッチかのindexを与えます(複数の指でタッチしていた場合は0と1を与えられます)。
Touch touch = Input.GetTouch(0);
Vector2 position
タッチされた場所の座標が格納されているプロパティです。
TouchPhase phase
タッチがどの状態かを示すプロパティです。
TouchPhaseには画面に指が触れたときを表す「Began」、画面上で指が動いたときを表す「Moved」などの5種類の値が定義されいます。
phaseの値によってプログラムの挙動を変えれば、様々なことが出来ると思います。
たとえば、Beganのときにタップされた位置を取っておいて、Moveしたら前回の位置との差分を見てオブジェクトを移動するためのVector2を作ったり... と言った感じです。
よく使うメソッド編
Object Instantiate(Object original, Vector3 position, Quaternion rotation)
UnityEngine名前空間のObjectクラスが持つstaticメソッドです。
引数originalにGameObjectを指定すると、クローンが作成されます。
クローンを作成する位置をposition、回転度をrotationで指定出来ます。
良くやるパターンとしては、あるGameObject型変数にプレハブを設定しておいて、Instantiateでクローンするという使い方です。
GameObject prefab; //エディタのインスペクターで設定しておく
...
Instantiate(prefab, transform.position, transform.rotation); //自身と同じ位置同じ回転度でprefabのクローンを作成
Coroutine StartCoroutine(IEnumerator routine)
「〜を〜秒(フレーム)後に実行したい」などのときに使えるのがコルーチンです。
StartCoroutine()メソッドはコルーチンを開始するメソッドで、MonoBehaviourクラスに定義されています。
void Start(){
StartCoroutine(WaitAndPrint());
}
IEnumerator WaitAndPrint(){
yield return new WaitForSeconds(3);
Debug.Log("Hello");
}
上記のようにすると、Start()が呼ばれてから3秒後に「Hello」とログに表示されます。
GameObject Find(string name)
ゲームオブジェクト名からGameObjectを取得をするメソッドです。
自身以外のオブジェクトに何かしたいときなどに使います。
GameObject go = GameObject.Find("bouya"); //bouyaという名前のGameObjectを取得
GameObjectの名前は、エディタのインスペクターで設定する他に、nameプロパティで設定する事が出来ます。
似たメソッドとして、GameObjectをTagから探せるFindWithTag()というメソッドもあります。
Component GetComponent<T>()
GameObjectにアタッチされたコンポーネントを取得する際に使います。
例えば、スクリプトをアタッチしておいて、そのクラスのインスタンスが欲しいときなどです。
ジェネリクス指定が無く、引数にタイプを指定する同名メソッドもありますが、こちらの方がキャストしなくて済むので良いかと思います。
Bouyaクラスを持つスクリプトがアタッチされていた場合に以下のようにすると、Bouyaオブジェクトを取得する事が出来ます。
Bouya bouya = gameObject.GetComponent<Bouya>();
これでBouyaクラスに定義されているメソッドを呼びたい放題です。
最後に
まだまだある気がしてならないのですが、時間的に厳しそうなのでこんなところでかんべんしてください。
こうやって改めてまとめてみると、新たな発見があったり知らないメソッドを見つけたりと、自分にも嬉しい事がありました。
誰かがこの記事を見て、Unityを始めたり、ゲームを作るのが難しすぎて出来なさそうという思いを払拭してもらえたらと思います。
明日は20日のshioriharaさんです
ご期待ください!