[超初心者向け]UnityでのC#の基礎(3)配列

Unityは「ゲームを簡単に作れるようにする」ソフトですが、他のプログラミング経験がないままで利用するとScriptが分からなくてつまずいてしまいます。ここでは、Unityで利用するC#に絞って、Scriptの仕組みを解説します。
Scriptのエディタで出てくる簡単な解説は以下で記していますので、一度読んでからこちらを参考にして下さい。

[[超初心者向け]やっと納得、Unityを初めて触ると出てくるC#の何だあれの答え](http://qiita.com/JunShimura/items/3c2e23bb77cc9085bfda)

ここでは少しずつ、Scriptを解説していきます。

#連続したオブジェクトを定義する配列

同じ型のものを複数で定義して、連続して同じ処理を施したり、値などを加えて順位を出すなど、配列を用いるとまとめて処理が可能になり、Scriptを簡単にできます。

#<i class="fa fa-cubes"></i>配列の基本
リファレンスの中で、複数の連続したデータを扱う場面があります。

> 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`にアタッチされたコンポーネントを取得するものです。
コードのサンプルでは、以下のように書いてあります。

```csharp
HingeJoint[] hingeJoints;
hingeJoints = GetComponents<HingeJoint>();
```

この処理を実行すると、`HingeJoint`型のアタッチされたコンポーネントが、配列`hingeJoints`に格納されます。

##<i class="fa fa-cube"></i>配列の定義

配列は、型と`[]`で定義します。
>型[]　オブジェクト名;


```csharp
int[] i;  //int型の配列
float[] f;  //float型の配列
Vector3[] v; //Vecotor3型の配列
GameObject[]　gameObjects; //GameObject型の配列
```

##<i class="fa fa-cube"></i>初期化と要素数
配列に含まれるオブジェクトを要素と呼び、その数を要素数として定義します。上記の場合は要素数が無いので、それを後から配列が代入されることで数が決まります。**要素数の変更は、決定後にできません**。

### 定義時に初期化

```csharp
int[] i={10,20,30};
```

これで定義される配列は、以下になります。

|参照|i[0]|i[1]|i[2]|
|:---:|:---:|:---:|:---:|
|要素|10|20|30|

参照は以下の形で指標をしていします。

```csharp
int sum =i[0]+i[1]+i[2]; //3要素の合計
```

要素数だけ定義すると要素数だけ確定しますが要素は未定義になります。


### 要素数だけ初期化

定義時に要素数だけ決めておきます、あとから要素の値は変えられます。

```csharp
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`が入ります。

```csharp
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演算子で作成し、代入することが可能です。

```csharp
        int[] a;
        a = new int[] { 8, -2, 4 };
```

|参照|a[0]|a[1]|a[2]|
|:---:|:---:|:---:|:---:|
|要素|8|-2|4|

##<i class="fa fa-cube"></i>配列の処理

配列は連続したデータ型なので、まとめた処理をする場合に便利です。以下は、リファレンスにある`Mesh`コードの抜粋です。

```csharp
    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](https://docs.unity3d.com/ja/current/ScriptReference/Mesh.html)

このScriptは`Update`関数で配列verticesに入っているポリゴンの頂点を1秒間で1°、三角関数の`sin`で動かす物です。`Mesh`コンポーネントを有するGameObjectならなんでも有効ですので試してみて下さい。
頂点を動かしている演算は、以下の部分です。

```csharp
            vertices[i] += normals[i] * Mathf.Sin(Time.time);
```
normalsに入っているのが法線ベクトルで、長さが1になる単位ベクトルになっています。それを三角関数`sin`をかけているので、±1の距離で頂点が動きます。
頂点数がもし5つであれば、以下のコードでも代用できます。

```csharp
            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`を用いています。

```csharp
        int i = 0;
        while (i < vertices.Length) {
            vertices[i] += normals[i] * Mathf.Sin(Time.time);
            i++;
        }
```
`vertices.Length`は配列の要素数を取得するものです。変数`i`は0から要素数-1まで処理を実行します。配列の指標は0から要素数-1になるので、それに合せています。

この処理をforで書き換えると、以下のようになります。

```csharp
        for(int i = 0; i < vertices.Length; i++) {
            vertices[i] += normals[i] * Mathf.Sin(Time.time);
        }
```

一方、冒頭で紹介した`GameObject.GetComponents`のリファレンスでは以下のサンプルコードが示されています。

```csharp
		HingeJoint[] hingeJoints;

		hingeJoints = GetComponents<HingeJoint>( );

		foreach( HingeJoint joint in hingeJoints )
			joint.useSpring = false;
```
引用元：[GameObject.GetComponents
https://docs.unity3d.com/ja/current/ScriptReference/GameObject.GetComponents.html](https://docs.unity3d.com/ja/current/ScriptReference/GameObject.GetComponents.html)

この`foreach`は配列型等の特定の型に用いられる制御文で、この例では取得した`HingeJoint`型のコンポーネント（GameObjectを他のGameObjectに連結するコンポーネント）のそれぞれの`useSpring`にfalseを代入する(バネのように伸び縮みする動作を無効化する)処理をしています。
これを前述のように`for`文で置き換えると、以下の用になります。

```csharp
        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)

#<i class="fa fa-cubes"></i>配列の特徴とまとめ

- ここで紹介した配列は1次元配列で、Unityのリファレンスに登場するものはほぼこれですが、この他に多次元化した配列もC#では使えます。
  - 参考：多次元配列 (C# プログラミング ガイド)
  -  [https://msdn.microsoft.com/ja-jp/library/2yd9wwz4.aspx](https://msdn.microsoft.com/ja-jp/library/2yd9wwz4.aspx)
- 親子関係のようにしたジャグ配列を用いると、配列の要素が配列になり、各要素数がバラバラにできます。
  - 参考：ジャグ配列 (C# プログラミング ガイド)
  -  [https://msdn.microsoft.com/ja-jp/library/2s05feca.aspx](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)