Unityは「ゲームを簡単に作れるようにする」ソフトですが、他のプログラミング経験がないままで利用するとScriptが分からなくてつまずいてしまいます。ここでは、Unityで利用するC#に絞って、Scriptの仕組みを解説します。
Scriptのエディタで出てくる簡単な解説は以下で記していますので、一度読んでからこちらを参考にして下さい。
[超初心者向け]やっと納得、Unityを初めて触ると出てくるC#の何だあれの答え
ここでは少しずつ、Scriptを解説していきます。
#連続したオブジェクトを定義する配列
同じ型のものを複数で定義して、連続して同じ処理を施したり、値などを加えて順位を出すなど、配列を用いるとまとめて処理が可能になり、Scriptを簡単にできます。
#配列の基本
リファレンスの中で、複数の連続したデータを扱う場面があります。
GameObject.GetComponents
public Component[] GetComponents(Type type);
public T[] GetComponents();
引用元:[https://docs.unity3d.com/ja/current/ScriptReference/GameObject.GetComponents.html]
(https://docs.unity3d.com/ja/current/ScriptReference/GameObject.GetComponents.html)
このGetCompornents
は、コンポーネントの型を指定して(上記のT
)、それに該当する自身のGameObject
にアタッチされたコンポーネントを取得するものです。
コードのサンプルでは、以下のように書いてあります。
HingeJoint[] hingeJoints;
hingeJoints = GetComponents<HingeJoint>();
この処理を実行すると、HingeJoint
型のアタッチされたコンポーネントが、配列hingeJoints
に格納されます。
##配列の定義
配列は、型と[]
で定義します。
型[] オブジェクト名;
int[] i; //int型の配列
float[] f; //float型の配列
Vector3[] v; //Vecotor3型の配列
GameObject[] gameObjects; //GameObject型の配列
##初期化と要素数
配列に含まれるオブジェクトを要素と呼び、その数を要素数として定義します。上記の場合は要素数が無いので、それを後から配列が代入されることで数が決まります。要素数の変更は、決定後にできません。
定義時に初期化
int[] i={10,20,30};
これで定義される配列は、以下になります。
参照 | i[0] | i[1] | i[2] |
---|---|---|---|
要素 | 10 | 20 | 30 |
参照は以下の形で指標をしていします。
int sum =i[0]+i[1]+i[2]; //3要素の合計
要素数だけ定義すると要素数だけ確定しますが要素は未定義になります。
要素数だけ初期化
定義時に要素数だけ決めておきます、あとから要素の値は変えられます。
int[] a= new int[5];
a[0]=10;
a[3]=-1;
これで定義される配列は以下になります。不定の要素の値は、内容が保証されません。
参照 | a[0] | a[1] | a[2] | a[3] | a[4] |
---|---|---|---|---|---|
要素 | 10 | デフォルト指定値 | デフォルト指定値 | -1 | デフォルト指定値 |
int型の場合、指定値は0になります。配列の型に依存し設定される値はかわります。
規定のデフォルト値は、こちらを参照してください。
[https://msdn.microsoft.com/ja-jp/library/83fhsxwc.aspx]
(https://msdn.microsoft.com/ja-jp/library/83fhsxwc.aspx)
参照型(class
など)の配列の場合は、未定義部分にはnull
が入ります。
GameObject partyGameObject[5];
a[0] = GameObject.Find("MainPlayer");
a[2] = GameObject.Find("SubPlayer");
これで定義される配列は以下になります。不定の要素の値は、内容が保証されません。
参照 | a[0] | a[1] | a[2] | a[3] | a[4] |
---|---|---|---|---|---|
要素 | "MainPlayer"のGameObject
|
null |
"SubPlayer"のGameObject
|
null |
null |
値型と参照型の違いは、こちらを参照して下さい。
[値型と参照型(MSDN)
https://msdn.microsoft.com/ja-jp/library/cc406735.aspx]
(https://msdn.microsoft.com/ja-jp/library/cc406735.aspx)
要素数不定で後から代入
後から配列をnew演算子で作成し、代入することが可能です。
int[] a;
a = new int[] { 8, -2, 4 };
参照 | a[0] | a[1] | a[2] |
---|---|---|---|
要素 | 8 | -2 | 4 |
##配列の処理
配列は連続したデータ型なので、まとめた処理をする場合に便利です。以下は、リファレンスにあるMesh
コードの抜粋です。
void Update() {
Mesh mesh = GetComponent<MeshFilter>().mesh;
Vector3[] vertices = mesh.vertices;
Vector3[] normals = mesh.normals;
int i = 0;
while (i < vertices.Length) {
vertices[i] += normals[i] * Mathf.Sin(Time.time);
i++;
}
mesh.vertices = vertices;
}
引用元:Mesh
https://docs.unity3d.com/ja/current/ScriptReference/Mesh.html
このScriptはUpdate
関数で配列verticesに入っているポリゴンの頂点を1秒間で1°、三角関数のsin
で動かす物です。Mesh
コンポーネントを有するGameObjectならなんでも有効ですので試してみて下さい。
頂点を動かしている演算は、以下の部分です。
vertices[i] += normals[i] * Mathf.Sin(Time.time);
normalsに入っているのが法線ベクトルで、長さが1になる単位ベクトルになっています。それを三角関数sin
をかけているので、±1の距離で頂点が動きます。
頂点数がもし5つであれば、以下のコードでも代用できます。
vertices[0] += normals[0] * Mathf.Sin(Time.time);
vertices[1] += normals[1] * Mathf.Sin(Time.time);
vertices[2] += normals[2] * Mathf.Sin(Time.time);
vertices[3] += normals[3] * Mathf.Sin(Time.time);
vertices[4] += normals[4] * Mathf.Sin(Time.time);
これで用意すると頂点数が変わった場合に対応が出来ません。それを可変長に捉えて処理するために、vertices.Length
を用いています。
int i = 0;
while (i < vertices.Length) {
vertices[i] += normals[i] * Mathf.Sin(Time.time);
i++;
}
vertices.Length
は配列の要素数を取得するものです。変数i
は0から要素数-1まで処理を実行します。配列の指標は0から要素数-1になるので、それに合せています。
この処理をforで書き換えると、以下のようになります。
for(int i = 0; i < vertices.Length; i++) {
vertices[i] += normals[i] * Mathf.Sin(Time.time);
}
一方、冒頭で紹介したGameObject.GetComponents
のリファレンスでは以下のサンプルコードが示されています。
HingeJoint[] hingeJoints;
hingeJoints = GetComponents<HingeJoint>( );
foreach( HingeJoint joint in hingeJoints )
joint.useSpring = false;
このforeach
は配列型等の特定の型に用いられる制御文で、この例では取得したHingeJoint
型のコンポーネント(GameObjectを他のGameObjectに連結するコンポーネント)のそれぞれのuseSpring
にfalseを代入する(バネのように伸び縮みする動作を無効化する)処理をしています。
これを前述のようにfor
文で置き換えると、以下の用になります。
for(int i = 0; i < hingeJoints.Length; i++) {
hingeJoints[i].useSpring = false;
}
配列の要素それぞれのみの参照で閉じた形で処理を行う場合、foreach
の方が簡潔になります。詳しくは以下を参照して下さい。
[配列での foreach の使用 (C# プログラミング ガイド)
https://msdn.microsoft.com/ja-jp/library/2h3zzhdw.aspx]
(https://msdn.microsoft.com/ja-jp/library/2h3zzhdw.aspx)
#配列の特徴とまとめ
- ここで紹介した配列は1次元配列で、Unityのリファレンスに登場するものはほぼこれですが、この他に多次元化した配列もC#では使えます。
- 参考:多次元配列 (C# プログラミング ガイド)
- https://msdn.microsoft.com/ja-jp/library/2yd9wwz4.aspx
- 親子関係のようにしたジャグ配列を用いると、配列の要素が配列になり、各要素数がバラバラにできます。
- 参考:ジャグ配列 (C# プログラミング ガイド)
- https://msdn.microsoft.com/ja-jp/library/2s05feca.aspx
- 配列は単純な処理には向いていますが、長さを後から変えることが再定義するしか無いため、柔軟な処理が出来ない場合が多くあります。その場合は
List
型が役立ちます。配列に処理を施すメソッドが多数、用意されており、非常に強力です。配列で間に合う場合はそのままで、複雑な処理をしたい、用意されたメソッドを用いたい場合はList
型にすると便利です。他にも配列処理が出来る型がありますが、現状だとほぼList
型で間に合います。 - List(T) クラス (System.Collections.Generic)
- https://msdn.microsoft.com/ja-jp/library/6sh2ey19(v=vs.110).aspx
この記事は以下でシリーズしていますので、適宜、参照してください。
[UnityでのC#の基礎]
(http://qiita.com/JunShimura/items/f87c599b3738b804f605#unity%E3%81%A7%E3%81%AEc%E3%81%AE%E5%9F%BA%E7%A4%8E)