[備忘録]Unity で始める C# その２

**条件分岐と繰り返しを学ぶ回。**

```:if文構文
if(条件式){
　　　　　　　trueのときの処理
}
```

【復習】
intは整数型　floatは実数型　boolは真偽値　stringは文字列　
float x = 42.195f; float型はfをつけなければならない。
double x = 42.195;　でも同じことが表現できる。

---
```
if (){
 if () {
   } 
}
```
という風に組み合わせると、true値になったときに別の条件チェックが行われるということ。

```
if (){
}
else if() {
}
```
というふうに組み合わせると、条件がfalseのときに条件をチェックするという書き方になる。

【演算子で条件を組み合わせる】
条件式**&&**条件式　→　条件式が**どちらもtrue**のときtrueを返す。
条件式**||**条件式　→　条件式の**どちらかがtrue**のときtrueを返す。

---
**switch文を使った分岐**
switch文はtrue、falseの２択だけではない、**複数に分岐できる構文**。
switch文の変数とcaseラベルの値が一致するかで実行される。実行はbreak文まで。
どのラベルにも一致しない場合はdefault文のあとの処理が行われる。

```:switch文を使ったFileメニュー
//架空のFileメニューが有り、項目選択時に変数が変数menuに入り、switch文で処理が実行される。（これはテキストのみ）
	void Start () {
		string menu = "print"; //stringは文字列型

		switch(menu){
		case "save":     //caseラベルは:(コロン)で書く
			Debug.Log ("保存します");
			break;
		case"open":　　　//caseラベルは:(コロン)で書く
			Debug.Log ("開きます");
			break;
		case"print":　　//caseラベルは:(コロン)で書く
			Debug.Log("印刷します");
			break;
		default:　　//default文も:(コロン)で書く
			Debug.Log("一致する機能がありません");
			break;
		}

	}
```
caseラベルは変数や式を使うことはできず、数値か文字列だけ。つまり大小ではなく、==か!=かだけ判断できる。

---
**while文**

```:while文構文
while (条件式) {
   繰り返す処理
}
```
```:while文例
// Use this for initialization
	void Start () {
		int x = 0;
		while (x < 8) {  //x<8の限り処理が続く
			x = Random.Range (0, 10);
			Debug.Log (x);
		}
		Debug.Log ("終了");
	}
```

**do-while文**
こちらはブロックが先、条件式が後になる。

```:do-while文構文
do {
 　　繰り返す処理
} while (条件式);
```
**while文との違いは、ブロック内の処理が必ず１回は実行されること。**

**for文**
回数の決まった繰り返しに便利。

```:for文構文
for (初期化; 条件式; 反復) {
    繰り返す処理
}
```
for文では回数を数えるための変数（カウンター変数）を用意する。
初期化の部分で変数を宣言し、条件式の部分で回数をチェック、反復の部分で変数を増やす。

```
for (int i =0; i <10; i++) {
   　繰り返す処理
}
```
iをカウンター変数として用意、i<10になるまでやることを設定、iの増やし方を設定。

```:使用例
void Start () {
		for (int i = 0; i < 10; i++) {
			Debug.Log (i);
		}
		Debug.Log ("終了");
	}
```

---
**for文で使うbreak文とcontinue文**
**break文は処理を中止し、ブロックの外へ移動する**。例えば、繰り返しの中で処理するべきデータがなくなったときに使う。switch文でもbreak文は出てきたが、どちらもブロックの外へ移動することが目的。

```:for文のbreak文
for ( int i = 0; i < 1000; i++){
    if (終了条件のチェック) break;
    繰り返したい処理
}
```

```:break文を使った例　０から２００までを表示する。
for (int i = 0; i <1000; i++){
			if(i >= 200) break;
			Debug.Log(i);
	}
```
**continue文は繰り返し処理を１回スキップする**。
例えば、複数のデータチェックで、負の数だけスキップして正の数だけ処理するという挙動にしたい場合につかう。

```:for文のcontinue文
for (int i = 0; i < 1000; i++){
    if (スキップ条件のチェック）continue;
　　繰り返したい処理
}
```

```:continue文を使った例　奇数のみ　1000までの数字を表示する。
for (int i = 0; i <1000; i++){
			if(i%2==0) continue;
			Debug.Log(i);
}
```

---
**foreach文**
配列変数と組み合わせやすいように改良されたfor文のこと。

```:foreach文の構文
foreach (変数　in 配列変数）{
　　　繰り返したい処理
}
```
**配列変数**
複数のデータを記録できる変数のこと。
クラスのメンバー変数を追加して複数データを記録するのとは異なる仕組み。
メンバー変数はそれぞれが違う変数だが、配列変数は同じ型の変数が複数並んだような感じ。
それぞれに番号がついており、**番号を添字**（そえじ）、**配列変数内の１つ１つの変数を要素**という。

配列変数を宣言するには、**型の後に[]をつける**。
**さらに、new演算子をつかって作成したインスタンスを代入する必要がある**。

```:配列変数の宣言
型[] 変数名 = new　型[要素数];
```

```:配列変数の使用例
int[] arr = new int[5];
```
変数arrにインスタンスを代入、メソッドはint型（整数型）を使用。
**配列はArray（アレイ）という特殊なクラスのインスタンス。つまり配列変数はArray型インスタンスを参照している**

【復習】
クラスのインスタンスはnew演算子を使って作成し、変数に代入する。


```:（例）
(略){
Person p = new Person();　　///クラスPersonのインスタンス作成　pに代入
(中略）
}
class Person{         ///クラスPersonを作成
     string name;
}
```
Personクラスのインスタンスを作成し、ｐという変数に代入している。
**しかし変数にインスタンスが入ってるわけではなく、メモリ上の何処かにあるインスタンスを変数から「参照」している状態である。**
組み込み型を代入したときは値がコピーされるが、インスタンスを代入したときは同じものを参照しているということ。

**つまり**
１つのインスタンスを複数の配列変数で参照したり、宣言後の配列変数に別のインスタンスを参照させたりすることもできる。
（例）
```
int[] arr = new int[5];　
int[] arr2 = arr;  //同じインスタンスを代入している。
arr = new int[8];  //別のインスタンスを作成して代入している。

**配列変数の初期化**
複数の値を**{}で囲んで**まとめて書く。要素数は値の数でわかるので省略される。new　型[]すらも省略される。

```:配列変数の初期化
型[] 変数名　= {値１,値２,値３,値４};
```

```:配列変数の初期化例
int[] arr = {-1, 53, 22, 43, 2};
```
**なお、一度宣言された配列変数に後から数値を記録することはできない。**

```:配列変数を使ってみる
// Use this for initialization
	void Start () {
		int[] arr = { -1, 22, 31, 65, 4 };
	
	Debug.Log(arr[2]);
	}
```

```:配列変数に代入してみる
void Start () {
		int[] arr = { -1, 22, 31, 65, 4 };
		arr [2] = 42; ///添字2に42を代入。値は更新される。
	Debug.Log(arr[2]);
	}
```
```:for文と組み合わせてみた
void Start () {
		int[] arr = { -1, 53, 21, 16, 4 }; //int型配列変数arrを用意、５つの値で初期化
		for (int i = 0; i < 5; i++){　　　//for文で繰り返し処理
			arr [i] = arr [i] * 2;　　
			Debug.Log (arr [i]);
		
	}

}
```
---
**int型、float型、string型はわかったけど、クラスを配列変数にする場合は？**
ちょっと不思議な書き方になる。

```:クラス型の配列変数を作る
// Use this for initialization
	//クラス型の配列変数を作る
	void Start () {
		Person[] parr = new Person[5]; //5つの要素を格納できる配列変数parrを宣言

		parr [0] = new Person ();　/*１つ目の要素にインスタンスを代入してメンバー変数（クラスが持つ変数のこと）や
		                             メソッドを利用している。new演算子が２つもあるのは、１つ目は格納できる何も入っていない
		                             配列変数のインスタンスをつくるためのもので、２つ目が要素に入れるインスタンスだということ*/

		parr [0].firstname = "太郎";　　//配列変数parrの要素に入れたPersonインスタンスのメソッドを呼び出している。クラス名.メソッドの順。
		parr [0].lastname = "山田";
		Debug.Log (parr [0].GetFullName ("★"));

	}
```

**クラス型の配列変数でも初期化できる**
その場合は**{}の中に要素に入れたいインスタンスを作成する。**

```:クラス型の配列変数の初期化
Person[] parr = {new Person () , new Person ()};

parr [0].firstname = "太郎";
parr [0].lastname = "山田";
Debug.Log (parr [0].GetFullName("★"));
```
**なおparr[0]とparr[1]は同じnew Person()が指定されていますが、参照型では別のオブジェクトになります。**
Personクラスのインスタンスを２種類new演算子で作って、それぞれparr[0]とparr[1]になってる。
**※参考書でなぜ先頭しか使っていないのかはわかりません。配列の使用例としては不適切に思えます。**


---
**毎回メンバー変数に代入するの面倒じゃね？ってことで...**
**クラスにコンストラクターを追加する**
これによりインスタンスを作るときに初期値を設定することができる。
これを利用して、配列変数の初期化時にメンバー変数を設定できる。
**コンストラクターとは**クラスと同じ名前の特殊なメソッド。書き方はメソッドと同じだが、呼び出すときはnew演算子を使う。

```:コンストラクターの定義
public クラス名　(引数の型と名前, 引数の型と名前){
    初期化処理
}
// コンストラクターの呼び出し
クラス名　変数名 = new クラス名 (引数,引数); 
```
```:コンストラクター使ってみた
class Person{
	public string firstname;
	public string lastname;

	public string GetFullName(string separator) {
		//戻り値の型はstring(文字列型）　引数付きのメソッドを定義する場合、(引数の型　引数名)を書く。複数の引数ならカンマ(,)で区切る。→(string fn , string ln)
		return this.lastname + separator + this.firstname;
}
	
        public Person (string fn, string ln){ //stringは文字列型。
		    this.firstname = fn;　　// thisはインスタンス自身を表す特殊な変数。
		    this.lastname = ln;
	}
public Person (){} ///上で２つの引数を取るコンストラクターを定義したので、デフォで用意されていた引数なしのコンストラクター（new Person()）が使えなくなったので、**「The type `Person' does not contain a constructor that takes `0' arguments（Person型は引数を０個取るコンストラクターを持っていない）」**というエラーが出るので、引数をとらず何もしないコンストラクターも追加しておく。
```
このように**戻り値と引数が違えば、同名のコンストラクターをつくることが可能**。

---
**多次元配列**
いままでのは１次元配列（横の並びのみ）だったが、２次元配列（横+縦)などのような多次元配列もある。
２次元配列の場合、[]の間を,（カンマ）で区切って２つの添字を書く。

```
int[,] arr2d = {
     {1,1,1,1,1,1},
     {1,0,0,0,0,0},
     {1,0,0,0,0,1},
     {1,1,1,1,1,1}
};
arr2d [1,0] = 5;
```
どうやら、添字は最初の数字が縦（縦のどの配列か）、次の数字が横（配列の何番目か、最初は0）を表すようだ。

---
**foreach文（フォーイーチ文）**
配列変数と組み合わせしやすいように改造されたfor文のこと。
カッコ内に「変数名 in 配列変数名」とかくと配列変数の要素が順番に変数に入るので、for文よりシンプルに書ける。**ただし、カウンター変数がないので、「奇数のときはスキップ」などのような処理をすることはできない。**汎用性はfor文のほうが高い。

```
int[] arr = {-1, 52, 22, 31, 4}
foreach (int v in arr){
    Debug.Log (v);
}
```

---
**Array.Sortメソッドで要素を並び替えてラクをしよう**

```usingSystem;とArray.Sortを追加
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class Lesson5 : MonoBehaviour {

	// Use this for initialization
	void Start () {
		int[] arr = { -4, 33, 21, 53, 4 };
		Array.Sort (arr);
		for (int i = 0; i < 5; i++){
			arr [i] *= 2;
			Debug.Log (arr [i]);
	}
}
```

---
**要素数をいじれるList<T>クラス**
要素数を変えられるクラスで、Unityでも使えるのがList<T>クラス。
<T>の部分は型パラメータといい、List<int>のように記録したい型を指定する。

Addメソッド（以下略）→末尾に要素を追加
Clear→すべての要素を削除
Count→現在の要素数を取得
Contains→ある要素がリスト内にあるか調べる
Sort→リストを並び替える（静的メソッドではないので、変数名.Sort()の形で呼び出す）
Insert→指定した位置に要素を挿入
Remove→指定した位置の要素を削除

```:使用例 
using System.Collections.Generic;

public class Lesson5 : MonoBehaviour {

	// Use this for initialization
	void Start () {
		List<int> list = new List<int> ();
		list.Add (48);
		list.Add (985);
		for (int i = 0; i < list.Count; i++){
			Debug.Log (list [i]);
}
	}
```
---

**名前空間**

```using System;
```
先程の例で使用したもの。このusingディレクティブは名前空間（ネームスペース）を取り込む指定。冒頭で書いておけば、「System.」の**入力を省略できる**。
例えばこれまで使ってきたMonoBehaviourクラスも、名前空間を含めた正式名称は「UnityEngine.MonoBehaviour」である。

```:パターンA（そのまま）
public class Lesson5 : UnityEngine.MonoBehaviour {
（省略）
```

```:パターンB（今後省略できる)
using UnityEngine;
(中略)
public class Lesson5 : MonoBehaviour {
(省略)
```

---
**静的メソッド**
変数名.メソッド名　
Debug.Log / Random.Range / Array.Sort();など。

クラス名.メソッド名
通常の。

前者が**静的メソッド**。インスタンスを作らずに呼び出せる。
定義の仕方はstatic（スタティック）修飾子をつけるだけ。
ただし静的メソッドにするとクラス内で特別な扱いになるので、同じクラスでもインスタンスのメンバー変数にアクセスできないなどの制限がある。

```:静的メソッドに定義する
public static void Sort (Array array){
    Sortメソッドの定義
}
```