Unityとc#の超入門 ～基礎編～


# Unityの画面構成

![Unity_1.PNG](https://qiita-image-store.s3.amazonaws.com/0/262601/8a4f44ff-c95c-ea64-4eb4-2c2d56606bd6.png)

# 視点の操作
**ズームイン・ズームアウト**　マウスホイール
**視点の平行移動**　「操作ツール」の手のひらマーク「画面移動ツール」
**視点の回転**　「Alt」押しながらドラッグ

# スクリプトのポイント
- スクリプトを実行すると、StartやUpdateのブロック内に書かれた処理が実行される。
- Startメソッド　Startメソッドは、スクリプトを実行すると1度だけ実行される。
- Updateメソッド　Updateメソッドは、フレームごとに毎回実行される。

# 関係演算子
**==**　左右が等しい場合に真
**!=**　左右が等しくない場合に真
**>**　左が右より大きい場合に真
**<**　右が左より大きい場合に真
**>=**　左が右以上の場合に真
**<=**　右が左以上の場合に真

# C#の変数の型の一例
**int**　整数型。±200万くらいまで。
**float**　浮動小数点型。float型に小数点の値を代入するときは、必ず値のあとに「f」をつけること。
**double**　倍精度浮動小数点型。
**bool**　ブール型。trueかfalseのどちらか。
**chr**　文字型。1文字。characterの略。
**string**　文字列型。テキスト。

# C#用語、Unity用語
**アクセス修飾子**　他のクラスからメンバにアクセスできるかどうかを表したもの。
**アニメーションクリップ**　パラパラアニメに使うためのスプライトをまとめたファイルのこと。
**アニメーションコントローラー**　アニメーションクリップをまとめたもの。どのタイミングで、どのアニメーションクリップを再生するか設定する。
**インスタンス**　クラスで作られた実体のこと。
**返り値**　メソッドから返してもらう値のこと。
**キャスト**　強制型変換のこと。メソッドの戻り値の方を変換するために使う。
**クラス**　C#で書かれたプログラムの単位のこと。メソッドと変数をまとめたもの。「クラス名」=「スクリプト名」
**構造体**　変数とメソッドをひとまとめにする仕組みのこと。クラスよりも高速に動作するのが特徴。
**コメント**　処理とは無関係なメモ書きのこと。//　に続いて入力する。
**初期化**　変数の宣言と値の代入を一度に行うこと。例）float XX = 10;
**シーン**　画面の一単位のこと。
**数値の後のf**　符号付き32bit浮動小数点数を表す接尾後。0.0fのように記載する。
**スクリプト**　ゲームの中のオブジェクトを動かすための台本のようなもの。
**スプライト**　シーンビューに配置した画像のこと。2Dゲームで使う画像のこと。
**宣言**　どんな種類のデータをいれるのか、何という名前の箱に入れるのかを明記すること。
**代入**　箱に値を入れること。同じ型の変数同士は代入できる。
**引数**　メソッドに渡す値のこと。
**プレファブ**　オブジェクトの設計図のこと。プレファブ（設計図）をジェネレーター（量産機械）に渡すと、インスタンス（製品）を精算する。
**フレーム**　1コマ1コマの絵のこと。1秒間に表示する枚数をFPS(Frame per Second)と言う。映画は24フレーム、ゲームは60フレーム。
**ブロック**　{}で囲われた部分のこと。
**プロジェクト**　ゲーム全体のこと。
**変数**　データをしまっておく箱のようなもの。
**メカニム**　アニメーションをUnityのエディタで作成と実行できる機能
**メソッド**　スクリプトを機能単位で区切った処理のこと。
**メンバ変数**　クラスで使う変数のこと。
**メンバメソッド**　クラスで使うメソッドのこと。

# Unityのメソッド
**Find**　引数の名前のオブジェクトがゲームシーンにあるかを探す。あった場合にそのオブジェクトを返す。
**ToString**　数値を文字列に変換する。

# ノードの役割
**Entry**　プレイと同時にアニメーションを開始したいときにつなげる。
**Any State**　特定のアニメーションに遷移したいときにつなげる。
**Exit**　アニメーションを終了したいときにつなげる。

# 遷移条件のパラメータ
**Has Exit Time**　アニメーションが終了したときに別のアニメーションに遷移するか否か。
**Exit Time**　アニメーションの終了時間を正規化時間（0.0～1.0）の間で設定。
**Transition Duration**　次のアニメーションの遷移時間を正規化時間（（0.0～1.0）の間で設定。
**Transition Offset**　次のアニメーションを再生し始める時間を正規化時間（0.0～1.0）の間で設定。

# for文
```c#
using System.Collections; //定型文みたいなもの
using System.Collections.Generic; //定型文みたいなもの
using UnityEngine; //定型文みたいなもの

public class Test : MonoBehaviour { //定型文みたいなもの

	// Use this for initialization
	void Start () { // startメソッド。後述のUpdateメソッドが呼び出される前に1回だけ呼び出されるメソッド
        for(int i = 0; i < 5; i++)
        {
            Debug.Log(i);
        }
    }
	
	// Update is called once per frame
	void Update () {
		
	}
}
```

# 1～10の合計値を出す
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

	// Use this for initialization
	void Start () {
        int sum = 0;
        for (int i = 1; i <= 10; i++)
        {
            sum = sum + i;
        }
        Debug.Log(sum);
    }
	
	// Update is called once per frame
	void Update () {
	}
}
```

# 配列

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

	// Use this for initialization
	void Start () {
        // 左辺で配列を宣言。右辺でint型の箱を5つ作る。
        int[] array = new int[5];

        array[0] = 2;
        array[1] = 3;
        array[2] = 5;
        array[3] = 8;
        array[4] = 15;

        for(int i = 0; i < 5; i++)
        {
            Debug.Log(array[i]);
        }
    }
	
	// Update is called once per frame
	void Update () {	
	}
}
```
# 配列から条件に合致する値だけを抽出する

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

	// Use this for initialization
	void Start () {
        int[] points = { 10, 20, 30, 40, 50 };

        for(int i = 0; i < points.Length; i++)
        {
            if(points[i] > 20)
            {
                Debug.Log(points[i]);
            }
        }
    }
	
	// Update is called once per frame
	void Update () {
		
	}
}

// 結果:
// 30
// 40
// 50
```

# 平均値を求める
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

	// Use this for initialization
	void Start () {
        int[] points = { 10, 20, 30 };
        int sum = 0;
        for(int i = 0; i < points.Length; i++)
        {
            sum = sum + points[i];
        }
        int average = sum / points.Length;
        Debug.Log(average);
	}
}

// 結果:
// 20
```

# 平均値を求めて、小数点であらわす
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

	// Use this for initialization
	void Start () {
        int[] points = { 1, 2, 3, 4 };

        int sum = 0;
        for(int i = 0;i < points.Length; i++)
        {
            sum = sum + points[i];
        }

        float avarage = 1.0f * sum / points.Length;
        Debug.Log(avarage);
	}
}

// 結果:
// 2.5
```

# 引数も返り値もないメソッド
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

	void Hello()
    {
        Debug.Log("Hello");
    }

    void Start()
    {
        Hello();   
    }
}
// 結果:
// Hello
```

# 引数があるメソッド
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

	void HelloName(string name)
    {
        Debug.Log("Hello " + name);
    }

    private void Start()
    {
        HelloName("Ken");
    }
}
// 結果:
// Hello Ken
```

# 引数と返り値があるメソッド
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

	int Add(int a, int b)
    {
        int c = a + b;
        return c;
    }

    void Start()
    {
        int answer;
        answer = Add(1, 2); // answer = c となる
        Debug.Log(answer);
    }
}
// 結果:
// 3
```

# アクセス修飾子
他のクラスからメンバにアクセスできるかどうかを表している。アクセス修飾子を省略するとplivateだとみなされる。
**public**　他のクラスから呼び出せる
**plivate**　他のクラスから呼び出せない

# thisキーワード
自分自身のインスタンスを表すキーワードのこと。メンバ変数と同じ名前のローカル変数を宣言した場合に、thisを書かないとローカル変数が優先され、thisを書くとメンバ変数が優先される。

# クラスの作成
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player {

    // クラスの基本形
    // class クラス名{
    //      メンバ変数の宣言;
    //      メンバメソッドの実装;
    // }

    private int hp = 100; 
    private int power = 50;

    public void Attack()
    {
        Debug.Log(this.power + "のダメージを与えた"); // 「this.power」は「Attack.power」表す。thisをつけるとローカル変数よりメンバ変数が優先される
    }
    public void Damage(int damage)
    {
        this.hp = this.hp - damage;
        Debug.Log(damage + "のダメージを受けた");
    }  
}

public class Test : MonoBehaviour
{
    private void Start()
    {
        Player myPlayer = new Player(); // 「new クラス名()」で、インスタンスを作成。Player型のyPlayer変数の中にインスタンスを格納
        myPlayer.Attack(); // 「変数名.メンバメソッド名」で、Attackメソッドを呼び出し
        myPlayer.Damage(30); // 「変数名.メンバメソッド名」で、Damageメソッドを呼び出し。30を引数で渡す
    }
}
}
// 結果:
// 50のダメージを与えた
// 30のダメージを受けた
```

# Vectorクラス
空間上のどこにオブジェクトを配置するか、どの方向にオブジェクトを移動させるかなどを決めるためのクラス。float型のx（横）、y（縦）、z（奥行）の値を扱う。3DはVector3（x、y、z）クラス、2DはVector2クラス（x、y）を使用する。

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        Vector2 playerPosition = new Vector2(3.0f, 4.0f); //左辺でVector2型のplayerPosition変数を宣言。右辺でVector2クラスのインスタンスを作って、playerPosition変数に代入
        playerPosition.x = playerPosition.x + 8.0f;
        playerPosition.y = playerPosition.y + 5.0f;
        Debug.Log(playerPosition);
    }
}

// 結果:
// (11.0, 9.0)
// (11.0, 9.0)
```

# Vectorの差分と直線距離を求める
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        Vector2 startPosition = new Vector2(1.0f, 1.0f);
        Vector2 endPosition = new Vector2(4.0f, 5.0f);
        Vector2 difference = endPosition - startPosition;
        Debug.Log(difference);

        float directDistance = difference.magnitude;
        Debug.Log(directDistance);
    }
}
// 結果:
// (3.0, 4.0)
// 5
```

# 2Dで絵を回転させる

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RouletteController : MonoBehaviour {

    float rotSpeed = 0; // 回転速度

    void Start()
    {
    }

    private void Update()
    {
        // マウスが押すことで回転速度を設定する
        if (Input.GetMouseButtonDown(0)) //マウスのボタン押下検知。引数0は左クリック、1は右クリック、2は中ボタンクリックを表す
        {
            this.rotSpeed = 10; // 左クリックすると、rotSpeedに10を代入する。フレームごとに現在の角度に10°足す
        }

        //  ルーレットを回転させる
        transform.Rotate(0, 0, this.rotSpeed); //メンバ変数の定義。第1引数はX軸、第2引数はY軸、第3引数はZ軸の回転を表す
    }
}
```

# スワイプした分だけ走るクルマ（初速にスワイプ距離を代入し、徐々に減速する）
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CarController : MonoBehaviour {

    float speed = 0;
    Vector2 startPosition;
    Vector2 endPosition;
    float swipeLength;

    void Start()
    {
    }

    void Update()
    {
        // スワイプの長さを求める
        if (Input.GetMouseButtonDown(0))
        {
            this.startPosition = Input.mousePosition; // マウスをクリックした座標をstartPosition変数に格納
        } else if(Input.GetMouseButtonUp(0)) { // マウスのボタンが離されたら
            this.endPosition = Input.mousePosition; // マウスを離した座標をendPosition変数に格納
            this.swipeLength = endPosition.x - this.startPosition.x; // X軸の距離を求める

            //スワイプの長さを初速に設定する
            this.speed = swipeLength / 500.0f;
        }

        transform.Translate(this.speed, 0, 0); // 移動
        this.speed = this.speed * 0.98f; // 減速
    }
}
```

# クルマと旗の距離を表示し、クルマの効果音を鳴らす
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CarController : MonoBehaviour {

    float speed = 0;
    Vector2 startPosition;
    Vector2 endPosition;
    float swipeLength;

    void Start()
    {
    }

    void Update()
    {
        // スワイプの長さを求める
        if (Input.GetMouseButtonDown(0))
        {
            this.startPosition = Input.mousePosition; // マウスをクリックした座標をstartPosition変数に格納
        } else if(Input.GetMouseButtonUp(0)) { // マウスのボタンが離されたら
            this.endPosition = Input.mousePosition; // マウスを離した座標をendPosition変数に格納
            this.swipeLength = endPosition.x - this.startPosition.x; // X軸の距離を求める

            //スワイプの長さを初速に設定する
            this.speed = swipeLength / 500.0f;

            // 効果音を再生
            GetComponent<AudioSource>().Play(); // マウスを話したときに効果音が再生する
        }

        transform.Translate(this.speed, 0, 0); // 移動
        this.speed = this.speed * 0.98f; // 減速
    }
}
```

# 矢印キーを押すとキャラクターが移動する
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour {

    void Start()
    { 
    }

    void Update()
    {
        // 左矢印をクリックしたときの挙動
        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            transform.Translate(-3, 0, 0); // 左に3動かす
        }

        // 右矢印をクリックしたときの挙動
        if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            transform.Translate(3, 0, 0); // 右に3動かす
        }
    }
}
```

# モノが落下してきて、キャラクターに当たると消える（当たり判定）
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ArrowController : MonoBehaviour {

    GameObject player;

    void Start()
    {
        this.player = GameObject.Find("player"); // 同シーン内でplayerという名前のオブジェクトがないか探す。あった場合、変数playerに代入する
    }

    void Update()
    {
        // フレームごとに等速で落下
        transform.Translate(0, -0.1f, 0);

        // 画面外に出たらオブジェクトを廃棄
        if(transform.position.y < -5.0f)
        {
            Destroy(gameObject);
        }

        // 当たり判定
        Vector2 p1 = transform.position; // 矢自身の中心座標を変数p1に代入
        Vector2 p2 = this.player.transform.position; // プレイヤの中心座標を変数p2に代入
        Vector2 dir = p1 - p2; // p2からp1へのベクトルを求め、変数dirに代入
        float d = dir.magnitude; // 縦と横のベクトルの対角線の長さを求める
        float r1 = 0.5f; // 矢印の半径
        float r2 = 1.0f; // プレイヤの半径

        if(d < r1 + r2)
        {
            // 衝突した場合は矢を消す
            Destroy(gameObject);
        }

    }
}
```

# 1秒ごとに矢を生成するジェネレータースクリプト
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ArrowGenerator : MonoBehaviour {
    public GameObject arrowPrefab;
    float span = 1.0f;
    float delta = 0;

    void Update()
    {
        // 1秒ごとに矢を生成
        this.delta = this.delta + Time.deltaTime; // Time.deltaTimeは、前フレートと現フレームの時間差を取得するスクリプト。unityで最初から用意されている
        if(this.delta > this.span) // 変数deltaが1秒以上になったら
        {
            this.delta = 0;
            GameObject go = Instantiate(arrowPrefab) as GameObject; // instantiateメソッドに引数arrowPrefabを渡すと、戻り値としてPrefabのインスタンスを返す。強制型変換であるキャストを使い、戻り値をGameObject型に変換
            int px = Random.Range(-6, 7);
            go.transform.position = new Vector3(px, 7, 0);
        }
    }
}
```

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