どうも、みりんです。
今日からUnityではじめるC#に取り組んでいこうと思います。
すでに、Unity5の教科書に取り組み、一通りやり切ったのでこの本はサクサク進めていければと思っております。
進めている中で、大切だと感じだり、未知だったもの、復習もかねて残しておきたいことなどをここに書いているつもりです。
すでに一冊取り組んでいることもあり、記述内容が少しずつ絞られていく可能性があるので、内容が薄くなってしまったら申し訳ないですw
学習内容
- chap1:Unityの基本操作→割愛
- chap2:C#の基本
- chap3:条件分岐と繰り返し処理
◇chap2:C#の基本
スクリプトの上の行→usingディレクティブ。Unityのクラスなどを使うために宣言。
スクリプト名のクラスの定義→後続の{}ブロックがスクリプト名のクラスの内容であることを意味している。
Start&Updateメソッド(関数)→2つの関数の役割については割愛。関数は必ずクラスの中に書く。
四則演算では、複数の演算子を使う場合、通常の四則演算と演算子の優先順位が異なるため注意が必要。
例えば以下の計算。
|
void Start() { Debug.Log("1+8×4は"+1+8*4); } |
実行結果は「1+8×4は132」となる。*は+よりも計算の優先順位が高いため、8×4が計算され32となる。その後+の計算処理が行われるが、+は左の+から優先的に計算を行うため、前の文字列と1との間で文字列の連結が行われ、上記の実行結果となる。これは()を用いて計算の優先度を変えることで、防ぐことが出来る。
この辺りは、実際の数学と同じですね。
以下に演算子と優先順位を表としてまとめたものを載せておきます。
これは本のp34 表2-02と同じものです。本をお持ちの方はそちらを参照してみてください。
優先順位 | カテゴリ | 演算子 |
1 | 基本式 | . () [] x++ x– new typeof checked unchecked |
2 | 単項式 | + – ! ~ ++x –X (T)x |
3 | 乗法式 | * / % |
4 | 加法式 | + – |
5 | シフト | << >> |
6 | 関係式と型検査 | < > <= >= is as |
7 | 等値式 | == != |
8 | AND(論理) | & |
9 | XOR(論理) | ^ |
10 | OR(論理) | | |
11 | AND(条件) | && |
12 | OR(条件) | || |
13 | 条件 | ?: |
14 | 代入 | = *= /= += -= <<= >>=&= ^= |= |
C#の変数にはいくつかの型が存在する。代表的なのはint、float、double、string、boolなど。このように標準で用意されている型は組み込み型と呼ばれる。
型はクラスからつくることもできる。
変数の型と代入しようとしている値の型が異なる場合には代入することが出来ませんが、型変換(キャスト)と呼ばれる機能を使うことで、代入しようとしている値の型を変換して代入することが出来ます。キャストは下記のように記述します。
|
int x =(int)42.195f; int x =(int)(y*15.2); |
この場合、int型なので小数点以下は切り下げられてしまいます。この型変換はどんな型同士でもできるわけではなく、数値同士など関連性があるものだけで可能だそうです。
・クラス:変数や関数をグループ化して扱う「くくり」のようなもの。
Unityであればゲームオブジェクトそれぞれがクラスと関連付けられる。
例えば、プレイヤークラス、エネミークラスなど。こういった考えをオブジェクト指向と呼んでいます。
クラスを使って様々な実態のある物(Unityでいえばゲームオブジェクト)を作ります。例えばプレイヤークラスというものがあったら、実際にプレイヤーが操作する主人公となるキャラクターのことです。こういった、クラスを使って作成した実態(オブジェクト)はインスタンスと呼ばれます。
インスタンスはnew演算子を使って作ることが出来ます。
クラスを作るという事は、新しい型を作ることと同義なので、クラスを作るたびに新しい型が出来ていることになります。
あるクラスの中の関数や変数を利用したい場面があるかと思いますが、その時には.(ドット)演算子を使うことで、それらの関数、変数を呼び出して使うことが出来ます。
・クラスの継承
プレイヤークラス以外にも、NPCクラスなどの似通ったクラスを作る場合、それぞれに同じ機能が必要になる場合がありますが、そのような場合には継承を使います。継承を使うことで、元(親)となるクラスの変数や関数を引き継いだ新しいクラスを作ることが可能になります。共通する機能は親のクラスに記述し、新しく追加したい機能や個別に設定したい機能は子のクラスに記述することで、共通部分は記述せず、新しいクラスを定義することが出来ます。
Unityでは下記の1文が書かれていますが、これが継承です。
|
public class Lesson : MonoBehaviour{} |
MonoBehaviourクラスを継承したLessonというクラスを作るという事を意味しています。Start関数やUpdate関数はMonoBehaviourクラスの機能で、これを継承しているため、新しく作ったスクリプト上で使用することが出来ています。
ただし、継承することのできる親クラスは1つまでなので、複数の親クラスから継承して新しいクラスを作ることはできないので注意です。
・インスタンスと変数の寿命
インスタンスはnewを使って作成し、変数に代入しますが、実際に変数にインスタンスが代入されているわけではありません。イメージとしては作成したインスタンスにアクセスできるチャンネル=変数と考えると良いかもしれません。インスタンスは変数によって参照されている(チャンネルが作られている)状態でないと、一定時間で自動的に消えてしまうので、消したくないインスタンスは常に変数から参照されている状態にしておく必要があります。
・変数のスコープ(寿命)
クラスのメンバー変数と関数内で宣言した変数にはスコープの違いが存在します。
メンバー変数はクラスのインスタンスが消滅するまで存在し続けますが、関数中の変数は所属している関数の処理が終わるまでしか存在し続けられません。
すべての変数がメンバー変数になってしまうと管理が大変になります。変数の寿命が決まっていれば、その変数が生きている間だけ管理すれば良く、異なるブロックであれば、同じ名前の変数を作ることもできるので、気軽に使い捨てることが出来ます。
◇chap3:条件分岐と繰り返し処理
・if文:割愛
・switch文:ifがtrueかfalseの2択なのに対し、switchでは条件を複数に分岐させることが可能。
switch文の変数や式の内容と、caseラベルの値が一致するかを比較し、一致した場合にはcase~break文までを実行する。
どのcaseとも一致しない場合は、default文の後の処理が実行される。
caseラベルには式や変数を使うことが出来ず、数値か文字列のみが使える。
そのため、等しいか否かしかチェックすることができない。
caseラベルを続けて記述すると、二つのうちどちらかのラベルと一致した場合に処理が実行される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
switch(変数や式){ case 値1: 値1の処理 break; case 値2: 値2の処理 break; case 値3: 値3の処理 break; . . . default: どのcaseとも一致しない場合の処理 break; } |
・条件演算子?:
?:を使うことで、演算子だけで条件分岐を作ることが出来る。
変数=条件式?trueの値:falseの値;
これを使うことでifよりも短い文で条件分岐を記述することが出来るが、わかりづらいので、無理に使う必要もないらしい。
・繰り返し文
for、while、do-while→割愛
continue文:繰り返し処理を1回スキップする。
・配列(変数):複数のデータを記録できる変数。普通の変数には値を1つしか代入することが出来ないが、配列には値を代入できる枠が複数あり、それぞれに別々の値を代入できる。イメージは棚やロッカー。
配列内の1つ1つの変数のことを要素、箱一つ一つに付けられている番号のことを添字と呼ぶ。
配列の宣言は以下のように行う。
|
型[] 変数名 = new 型[要素数]; //例えば int[] array = new int[5]; |
これでarrayという要素数5個(箱の数が5個)の配列変数が宣言されていることになる。
配列はArrayという特殊なクラスのインスタンスで、宣言した配列変数はArray型インスタンスを参照している状態になっている。
そのため、下記のように1つのインスタンスを複数の配列変数で参照したり、宣言後の配列変数に別のインスタンスを参照させたりすることも可能。
|
int [] array1 = new int[5]; int [] array2 = array1;//array2というインスタンスもarray1という同じインスタンスを参照している array1 = new int[8];//別のインスタンスを作成して代入している |
配列変数も以下のように初期化させることが出来る。
|
型[] 変数名={a,b,c,d....}; int[] array = {2,1,5,7,3,9}; |
複数の値を代入できるのは最初の宣言時のみで、宣言が済んだ配列変数に後から複数の値を記録することはできず、1つの要素ずつに代入していく必要がある。
要素に値を代入するには、変数名[添字]と書くことで、普通の変数と同じように使うことが出来る。ただし、添字は0からスタートすることに注意すること。
|
int[] array = new int[5]; array[1]=3; array[4]=1; |
・クラス型の配列変数
クラス型の配列変数は次のように宣言する
|
class Person{ public string firstname; public string lastname; public string getfullname (string sep) { return this.firstname + sep + this.lastname; } } Start() { Person[] parr= new Person[5]; parr[0]=new Person(); parr[0].firstname="太郎"; parr[0].lastname="山田"; Debug.Log(parr[0].getfullname("★")); } |
クラス型の配列変数も{}を使うことで初期化することが出来る。
上記のスクリプトで
Person[] parr = new Person[5] → Person[] parr = {new Parson(), new Parson()}
と書き換えると要素数2の初期化された配列変数になる。
ただ、メンバ変数に後から代入するのが面倒なので、初期化時にそこまで済ませておきたい。
・コンストラクタ―
コンストラクタ―:クラスと同じ名前の特殊な関数でインスタンス作成時に初期値を設定する。関数の書き方と同じだが、呼び出す際にはnewを用いる。
|
//コンストラクタ―の宣言 public クラス名(引数の型と名前、引数の型と名前) { 初期化処理 } //コンストラクタ―の呼び出し クラス名 変数名 = new クラス名 (引数,引数); |
上記のプログラム文にコンストラクタ―を追記すると下記の通り。
|
class Person{ public string firstname; public string lastname; public string getfullname (string sep) { return this.firstname + sep + this.lastname; } public Person (string fn, string ln)//コンストラクタ部分 { this.firstname = fn; this.lastname = ln; } } |
ただし、このままだとエラーが出てしまう。これは、クラス型の変数に=new Person()と代入していたが、このnew Person()も実はコンストラクタで、クラスの宣言時にデフォルトで用意されていたコンストラクタである。
これが引数を二つ持つ新しいコンストラクタを定義したことで使えなくなってしまうためである。
コンストラクタは作成する際に必ずクラス名で宣言しなければならないことを考えると、2つ以上のコンストラクタを作れないように見えるかもしれない。
しかし、コンストラクタは戻り値と引数の型が異なれば、同名のコンストラクタを作ることが可能であるので、新たに引数も返り値も持たないコンストラクタを宣言してやれば問題ない。
つまり、上記のスクリプトにpublic Person(){}を追記してやればよい。
これは関数の宣言時にも同じことができる。
|
class Person { public string firstname; public string lastname; public string getfullname (string sep) { return this.firstname + sep + this.lastname; } public Person (string fn, string ln)//コンストラクタ部分 { this.firstname = fn; this.lastname = ln; } public Person(){} } |
コンストラクタを設定したことで、Start関数内の記述を下記のようにすることが出来る。
|
Start() { Person[] parr={new Person("太郎","山田"), new Person("花子","田中")}; Debug.Log(parr[0].getfullname("★")); } |
・多次元配列→割愛
・foreach文:配列変数と組み合わせやすいように改良されたfor文
下記のように使う。
|
foreach(変数 in 配列変数){ 繰り返したい処理 } //以下例 int[] arr ={1,2,3,4,5}; foreach(int v in arr) { Debug.Log{v}; } |
foreachでは配列の要素が順番に変数に入るため、簡単に配列変数の全要素を処理することが出来る。上の場合、1,2,3,4,5とコンソールウィンドウに表示される。
・Array.Sort関数
Arrayクラスには配列変数の操作を助ける便利な関数を持っている。その中でも、Array.Sort関数は昇順に並べ替えることが出来る関数。引数に配列を渡すことで、中の要素を昇順に並べ替え、昇順になった配列を返してくれる。
・List<T>クラス
配列変数の要素数を変えることが出来るクラス。<T>の部分を型パラメータと呼び、Lsit<int>のように記録したい方を指定する。リストを操作するための下記のようなメンバ関数やプロパティが用意されている。
メンバー | 働き |
Addメソッド | 末尾に要素を追加する。 |
Clearメソッド | すべての要素を削除する。
|
Countプロパティ | 現在の要素の数を取得する。 |
Containsメソッド | ある要素がリスト内にあるか調べる。 |
Sortメソッド | リストを並べ帰る(※静的メソッドでないので、変数名.Sort()の形で呼び出す。
|
Insertメソッド | 指定した位置に要素を挿入する。 |
Removeメソッド | 指定した位置の要素を削除する。 |
List<T>の使用例は以下の通り。
|
List<int> list = new List<int> (); list.Add(4); list.Add(32); for(int i = 0; i <list.Count; i++) { Debug.Log(list [i]); } |
Add関数で要素を決定し、Countプロパティで要素数を調べている。
Add(4)の状態であれば、最終的にコンソールビューに4が表示され、Add(32)であれば、コンソールビューには32が表示される。
ということで、とりあえずchap3まで取り組みました。
一部、飛ばした部分もありましたが、C#の基本的なところは知らないことが多いので、とても勉強になりました。特にクラスやインスタンス、コンストラクタはあまり理解できていなかったところだったので、わかりやすく解説してあってよかったです。
プログラミングの基礎知識中心で退屈なところでしたし、未知の部分やクラスなどの考え方など、理解の難しい部分も多かった割にはサクサク進められたと思うので、この調子でこの先も進んでいきたいですね。
ここまで読んでくださり、ありがとうございました。
それでは、この辺で。