SlideShare ist ein Scribd-Unternehmen logo
1 von 57
Downloaden Sie, um offline zu lesen
Unityで覚えるC♯
  Learn C# in Unity
Learn C# in Unity
 初学者にありがちな混乱
 ・言語の仕様
 ・標準ライブラリの仕様
 ・実行環境の仕様
    この3つをごっちゃにして「何がわからないのかわからない」
    状態になりがち。C#の文法の問題なのか、.Net Framework
    の問題なのか、Unityの問題なのか切り分けて考えよう。

    今回は主にC#の文法の話と、よく使う(知らないとそもそも発
    想に至らない).Net Frameworkの機能の話をします。




                                    2/57
Learn C# in Unity
 オブジェクト指向 再々(xN)入門
 ・その前に、とても眠くなるそもそも論
    そもそもプログラムとは「データの加工」です。つまり「デー
    タ」と「加工」という2つの要素から成り立っています。プロ
    グラムの用語に直すと「変数」と「関数」です。

    オブジェクト指向以前は、データと加工処理が完全に別れてい
    ました。データ、つまり変数を、それを処理する関数に渡して
    加工してもらい、受け取った結果をまた別の関数に渡して、と
    いう流れを延々繰り返します。

    オブジェクト指向はその考え方を1段階抽象化して、関連する
    変数と関数を1まとまりにしたオブジェクトという概念を導入
    し、プログラムは各オブジェクトが協調動作して動くものだ、
    と考えるようになりました。
                               3/57
Learn C# in Unity
 オブジェクト指向 再々(xN)入門
 ・オブジェクト指向以前・以後
    オブジェクト指向という考え方をした場合としなかった場合、
    プログラムの構造がどのようにかわるか、という例。

   ■BEFORE                                        ■AFTER
   int GetFileSize(string fname);                 class File
   bytes ReadFromFile(string fname, int size);    {
   void WriteToFile(string fname, bytes data);         bytes data;
   void CloseFile(string fname);                       void Open(string fname);
                                                       void Close();
   main()                                         }
   {
        string fname = "hoge.txt";                main()
        int size = GetFileSize(fname);            {
        bytes data = ReadFromFile(fname, size);        File f = new File();
        for (int i = 0; i < size; i++)                 f.Open("hoge.txt");
             data[i] += 1;                             for (int i = 0; i < f.data.size; i++)
        WriteToFile(fname, data);                           f.data[i] += 1;
        CloseFile(fname);                              f.Close();
   }                                              }




                                                                                               4/57
Learn C# in Unity
 オブジェクト指向 再々(xN)入門
 ・一般的な意味での用語の定義(≠C#の用語)
    ■オブジェクト
     データや処理が1まとまりになった最小のプログラム片
    ■クラス/構造体
     オブジェクトの設計図
    ■インスタンス
     メモリ上に配置されたクラス/構造体の実体
    ■メンバー変数/メンバーフィールド/メンバープロパティ
     オブジェクトが持つ情報
    ■メンバー関数/メンバーメソッド
     オブジェクトの動作を定義した関数
    ■インターフェース
     オブジェクトがどんなメンバーを持っているか、どう振る舞
     うかの定義。実は一番大事な概念。
                              5/57
Learn C# in Unity
 オブジェクト指向 再々(xN)入門
 ・プログラムの設計=インターフェースの設計
     オブジェクト指向に限らず、プログラムの設計とはインターフェー
    スの設計に他なりません。オブジェクト指向ならそもそも何をオブ
    ジェクトに見立てて、それがどんなメンバーを持っているのか、つま
    りどんなインターフェースにするのかを決めることが最大の関心事で
    あり、一番難しい問題です。
     ライブラリの場合だと、ユーザーのプログラムと、どんなデータを
    どんな関数を介してやりとりするのか決めること=インターフェース
    の設計です。
     ゲームだってユーザーに対してどんな情報を見せるのか、あるいは
    見せないのか、つまりユーザーインターフェースの設計がキモであ
    り、難しい部分です。
     インターフェースが適切になっているか、常に意識しながらプログ
    ラミングしましょう。
                                 6/57
Learn C# in Unity
 オブジェクト指向 再々(xN)入門
 ・Unityの代表的なオブジェクト
    ■Vector3
      X,Y,Zの値を持つベクトル。位置情報などを表す。
    ■Input
      ユーザーからの入力を一元管理している。
    ■GameObject
      ゲーム空間(シーン)の中に存在するものは全てこれ。
    ■Component
      GameObjectにアタッチすることで、GameObjectがどう
      振る舞うか定義できる。
    ■Transform
      Componentの一種で、ゲーム空間中での位置や向きなどを
      管理する。全てのGameObjectに付いている。

                                     7/57
Learn C# in Unity
 オブジェクト指向 再々(xN)入門
 ・継承
    あるオブジェクトの機能を引き継ぎ、より具体的な機能を追加
    した新しいオブジェクトを作る仕組み。

       Component    Transform


                     Camera          BoxCollider


                     Collider       SphereCollider


                    MonoBehaviour      PlayerBehaviour


                                       EnemyBehaviour


                                                         8/57
Learn C# in Unity
 オブジェクト指向 再々(xN)入門
 ・多態(ポリモーフィズム)
    あるオブジェクトが継承先で何をやっているか意識することな
    く、継承元のインターフェースでアクセスできる仕組み。

                                  BoxCollider
                                  bool Raycast(ray)
              Collider
                                  {
              bool Raycast(ray)
                                     return 線と立方体の判定結果;
                                  }


        Ray         Bool          SphereCollider
                                  bool Raycast(ray)
                                  {
                                     return 線と球の判定結果;
     GameObject                   }


                                                        9/57
Learn C# in Unity
 Unityの設計から学ぶオブジェクト指向
 ・継承が全てではない!
    Unityのゲームシステムは、オブジェクト指向を一歩進めたコン
    ポーネント指向という考え方で作られています。
    ■古いオブジェクト指向
                     GameCharacter             PlayerCharacter
     GameObject
                     MeshData mesh;            Controller controller;


                                               EnemyCharacter
                                               AI ai;

    ■コンポーネント指向
                    MeshData                            MeshData
     GameObject                       GameObject
                    Controller                          EnemyAI

                                                                        10/57
Learn C# in Unity
 C#におけるクラス
 ・クラスの定義の仕方
    using UnityEngine; // 使うライブラリの宣言

    // MonoBehaviourを継承したNewBehaviourScriptクラスの宣言
    public class NewBehaviourScript : MonoBehaviour
    {
         // メンバーフィールドの宣言
         public Vector3 velocity;

        // メンバーメソッドの定義
        void Update()
        {
             transform.Translate(velocity * Time.deltaTime);
        }
    }


    メンバーの宣言に、publicを付けるとクラスの外からも見える
    ようになる。privateを付けるか何も付けないと、クラスの外か
    らは見えないようになる。内部で何をやっているかはできるだ
    け見せない方がよい。

                                                               11/57
Learn C# in Unity
 C#におけるクラス
 ・クラスがメンバーに持てるもの
    ■フィールド
     変数。通常あまり生のメンバー変数を公開するものではない
     が、Unityの場合パブリックフィールドにしないとインスペ
     クタに表示されない。
    ■メソッド/コンストラクタ/デストラクタ
     関数。コンストラクタとデストラクタは少し特殊な関数。
    ■プロパティ
     アクセサの簡易表記法
    ■インデクサー
     オブジェクトを配列のように扱えるようにするための機能
    ■イベント
     処理の一部を外部に委譲したり、何かのタイミングを通知す
     るための機能。
                               12/57
Learn C# in Unity
 C#におけるクラス
 ・コンストラクタ
    オブジェクトの初期化処理を行うためのメソッド。ただしUnity
    はMonoBehaviourを継承したクラスがコンストラクタを実装
    することを推奨していません。Awake/Startを使いましょう。
    public class Foo : Bar
    {
         int i;
         // コンストラクタの定義。戻り値のない、クラス名とまったく同じ名前のメソッドにする。引数は取れる。
         public Foo(int i)
         {
              this.i = i;
         }
         // 同じクラスの別のコンストラクタを呼ぶ書き方。
         public Foo() : this(0)
         {
         }
         // 継承元のコンストラクタを明示的に呼び出す書き方。省略すると継承元の引数なしコンストラクタが呼ばれる。
         public Foo(float f) : base(f)
         {
         }
    }

    Foo f = new Foo(1.0f); // 3つめのコンストラクタが呼ばれる

                                                           13/57
Learn C# in Unity
 C#におけるクラス
 ・デストラクタ
    オブジェクトの破棄処理を行うためのメソッド。C#はGCが動
    いていて明示的な破棄はしなくてよいので、通常意識する必要
    はありません。
    public class Foo
    {
         // デストラクタの定義。戻り値も引数もアクセス指定もない、クラス名の最初に~を付けた名前のメソッドにする。
         ~Foo()
         {
         }
    }




    C#で破棄のタイミングを管理したいクラスはIDisposableを継
    承して、Dispose()メソッドを実装し、using文と合わせて使
    います。ただDispose()の実装は慣れてないと難しい…。


                                                           14/57
Learn C# in Unity
 C#におけるクラス
 ・プロパティ:アクセサの簡易表記法
    public class NewBehaviourScript : MonoBehaviour
    {
         // メンバープロパティの定義
         public Vector3 velocity
         {
              get { return rigidbody.velocity; }
              set { rigidbody.velocity = value; }
         }
         // 上記は、以下の様なアクセサの定義を簡単にできるようにしたもの
         Vector3 GetVelocity()
         {
              return rigidbody.velocity;
         }
         void SetVelocity(Vector3 value)
         {
              rigidbody.velocity = value;
         }
         // プロパティへは普通のメンバーフィールドと同じようにアクセスできる
         void Start()
         {
              velocity = Vector3.zero;
         }
    }




                                                      15/57
Learn C# in Unity
 C#におけるクラス
 ・プロパティをもっと便利に使う
    プロパティは実装を省略してもOK
    public class NewBehaviourScript : MonoBehaviour
    {
         public Vector3 velocity { get; set; }

        // 上記は、以下のような暗黙のメンバーフィールドを持ったプロパティが作られていると考えてOK
        Vector3 m_velocity;
        public Vector3 velocity
             get { return m_velocity; }
             set { m_velocity = value; }
        }
    }


    プロパティはget/setごとにアクセス指定を付けることも可能
    public class NewBehaviourScript : MonoBehaviour
    {
         public Vector3 velocity
         {
              get; private set;
         }
    }




                                                          16/57
Learn C# in Unity
 C#におけるクラス
 ・プロパティをもっともっと便利に使う
    読み取りのみ許可するプロパティの場合は、setを省略できる
    public class NewBehaviourScript : MonoBehaviour
    {
         public Vector3 velocity
         {
              get { return rigidbody.velocity; }
         }
    }




                                                      17/57
Learn C# in Unity
 C#におけるクラス
 ・インデクサー
    public class NewBehaviourScript : MonoBehaviour
    {
         int[] data;
         // インデクサーの定義
         public int this[int index]
         {
              get { return data[index]; }
              set { data[index] = value; }
         }
         // インデクサーをメンバーに持つオブジェクトへは、配列のようにアクセスできる
         void Start()
         {
              NewBehaviourScript nbs = new NewBehaviourScript();
              print(nbs[0]);
         }
    }




                                                                   18/57
Learn C# in Unity
 C#におけるクラス
 ・イベント
    重要な機能だけど理解が難しいので後で詳しく説明します。
    public class Foo
    {
         // デリゲート型の定義
         public delegate void OnDamageDelegate(GameObject victim, float amount);
         // 定義した型のイベントを宣言
         public event OnDamageDelegate onDamage;
         // ダメージ処理
         float hp { get; private set; }
         public void DoDamage(float amount) {
              hp -= amount;
              onDamage(gameObject, amount); // onDamageに登録されてるメソッドを呼ぶ
         }
    }
    // 例えばダメージを喰らったタイミングでこのメソッドを呼んで欲しい場合
    void PrintDamage(GameObject victim, float amount)
    {
         print(victim.name + " got damage " + amount);
    }
    // イベントにデリゲートを登録
    Foo f = new Foo();
    f.onDamage = PrintDamage;
    // ダメージ処理を呼ぶと、イベントの機能でPrintDamageメソッドが呼ばれる
    f.DoDamage(10);


                                                                                   19/57
Learn C# in Unity
 C#におけるクラス
 ・クラスメンバーとインスタンスメンバー
    一口にメンバーといっても、クラス自体に属して全てのインス
    タンスから同じ値を参照するクラスメンバーと、各インスタン
    ス毎にローカルな値を持つインスタンスメンバーがあります。
    public class Foo : MonoBehaviour
    {
         // クラスフィールドの定義
         public static int classField = 0;
         // インスタンスフィールドの定義
         public int instanceField = 0;
         // クラスメソッドの定義
         public static void Hoge() { print("Hoge! " + classField); }
         // インスタンスメソッドの定義
         public void Mage() { print("Mage! " + classField); }
    }

    // クラスメンバーにはインスタンスがなくてもアクセスできる
    Foo.classField = 10;
    Foo.Hoge(); // "Hoge! 10"
    Foo foo = new Foo();
    print(foo.instanceField); // 0
    foo.Mage(); // "Mage! 10"

                                                                       20/57
Learn C# in Unity
 C#におけるクラス
 ・クラスメンバーしか持たないクラス
    全てのメンバーがstaticなクラスは、クラス自体もstaticにす
    ることで、インスタンスを作ることを明示的に禁止できます。
    public static class Foo
    {
         // クラスフィールドの定義
         public static int classField = 0;
         // クラスメソッドの定義
         public static void Hoge() { print("Hoge! " + classField); }
         // staticなクラスは静的コンストラクター(クラスコンストラクタ)で初期化する
         static Foo()
         {
              classField = 10;
         }
    }



    ちなみに静的コンストラクターは普通のクラスでも使えます。



                                                                       21/57
Learn C# in Unity
 C#におけるクラス
 ・クラス修飾子
    sealed
      sealed修飾子を付けたクラスは継承できなくなります。

 ・メンバーフィールド修飾子
    const
      実行中に値が変わらない(変わってはいけない)フィールド
      につけることで、値を変えようとするコードを書くとコンパ
      イル時にエラーにしてくれます。

    readonly
       意味的にはconstと同じ。constは値型(後述)にしか付け
       られませんが、readonlyは参照型にも付けられます。
                                   22/57
Learn C# in Unity
 C#におけるクラス
 ・メンバーメソッド修飾子
    virtual
        継承先で実装を書き換えて良いことを宣言します。

    override
      継承元で宣言されているvirtualメソッドを上書きして、独自
      に実装し直すことを宣言します。
      ちなみにoverrideしたメソッドから継承元の本来の処理を
      呼び出すには「base.メソッド名()」と書きます。

    extern
       外部で実装されているメソッドを宣言する時に、DllImport
       属性と組み合わせて使います。Unityではネイティブプラグ
       インのメソッドを呼びたい時に使います。
                                    23/57
Learn C# in Unity
 C#におけるクラス
 ・属性(アトリビュート)
    C#はアトリビュートという機能を使って、クラス自体やそのメ
    ンバーにメタデータを付けることができます。Unityでは自分で
    作ったクラスにSerializable属性を付けることでインスペクタ
    に表示できるようにしたり、エディタの拡張で多用します。
    [ExecuteInEditMode()] // この属性を付けると、エディタ上で非実行時もStartとかUpdateが呼ばれる
    public class NewBehaviourScript : MonoBehaviour
    {
         [System.Serializable()] // この属性を付けないと、Foo型のフィールドがインスペクタに表示されない
         public class Foo
         {
              public int hoge;
         }
         public Foo f;
    }




                                                                      24/57
Learn C# in Unity
 C#における構造体
 ・構造体の定義の仕方
    public struct Point
    {
         // メンバーフィールドの宣言
         public int x, y;

        // メンバーメソッドの定義
        public Point(int x, int y)
        {
             this.x = x;
             this.y = y;
        }
    }



    基本的にはクラスの定義と同じだが、構造体はクラスのような
    実装の継承はできない。インターフェース(後述)を継承して、
    自分で実装を書くことはできる。
    またクラスは参照型だが、構造体は値型であるという違いがあ
    る(後述)。

                                     25/57
Learn C# in Unity
 C#におけるインターフェース
 ・インターフェースの定義の仕方
    interface ICollidable
    {
         // メンバーメソッドの宣言(定義はできない)
         bool IsCollide(GameObject other);
    }

    public class NewBehaviourScript : MonoBehaviour, ICollidable
    {
         // インターフェースの実装
         public bool IsCollide(GameObject other)
         {
              if (gameObject.collider == null || other.collider == null)
                   return false;
              return IsCollide(gameObject.collider, other.collider);
         }
    }



    インターフェースはそれを継承したオブジェクトがどんなメン
    バーメソッド、プロパティ、インデクサー、イベントを持つか
    明言するためのもの。メンバーフィールドは宣言できず、実装
    もできないため、単体では機能しない。
                                                                           26/57
Learn C# in Unity
 クラス or 構造体
 ・参照型と値型
    クラスは参照型、構造体は値型です。この2つの違いは、メ
    ソッドの引数や戻り値としてオブジェクトが渡される時の挙動
    に影響します。
    例えばオブジェクトFooからBarへ変数が渡される場合…
     ■参照型                 ■値型
                                    複製
      Transform           Vector3        Vector3




        Foo         Bar    Foo            Bar



                                                   27/57
Learn C# in Unity
 クラス or 構造体
 ・値型の参照渡し
    refキーワードやoutキーワードを使って、構造体のような値型
    の参照を渡す方法もあります。
    public class Foo
    {
         Vector3 myVector;

        public AddVectorTo(ref Vector3 target)
        {
             target += myVector;
        }
    }

    public class Bar
    {
         Foo foo = new Foo();
         Vector3 myVector;
         public Bar()
         {
              foo(ref myVector);
         }
    }




                                                 28/57
Learn C# in Unity
 クラス or 構造体
 ・Null許容型
    値型の変数でも、まだ初期化されていないことを明示したい場
    合があります。そういう時はNull許容型を使います。
    public class Foo
    {
         Vector3? myVector; // 変数の型の後ろに「?」を付けるとNull許容型になる

        public Vector3 GetVector()
        {
             if (myVector == null)
                  myVector = Vector3.up;
             return myVector.Value;
        }
    }




    ただこれはデータベースとのやりとりを簡単にするために用意
    されたものなので、Unityで使うことはあまりない。使わざるを
    えないような状況になったらおそらく設計が悪い。

                                                            29/57
Learn C# in Unity
 クラス or 構造体
 ・参照型
    メリット
     オブジェクトのサイズに関わらず、受け渡しのコストが一定
     受け渡した先で値を変更すると、受け渡した元の値も変わる
    デメリット
     GCで処理する際のコストが高い
 ・値型
    メリット
     GCで処理する際のコストが低い
     受け渡し先で値を変更しても、受け渡し元は影響を受けない
    デメリット
     オブジェクトのサイズに比例して受け渡しのコストが増える
     ボックス化によるパフォーマンスの悪化がわかりづらい
                              30/57
Learn C# in Unity
 クラス or 構造体
 ・ボックス化・ボックス化解除
    値型をobject型に変換することをボックス化、object型を元の
    値型へキャストし直すことをボックス化解除といい、どちらも
    とてもコストが高い操作なので極力避けるようにします(ボッ
    クス化されるとインスタンスのサイズも増えます)。
       object o = 1;   // ボックス化
       int i = (int)o; // ボックス化解除

       // ArrayListは全ての要素をobject型に変換して格納するコレクションクラス
       ArrayList list = new ArrayList();
       list.Add("hoge");   // だから文字列も数値も同じArrayListに格納できるけど…
       list.Add(100);      // ←ここでボックス化が発生!気づきにくい!




    後述するジェネリックという機能を使えば不要なボックス化を
    減らせるので、積極的に使いましょう。


                                                               31/57
Learn C# in Unity
 クラス or 構造体
 ・どちらを選ぶべきか
    基本はクラスを使い、以下の条件を全て満たす場合のみ構造体
    にします(とMicrosoftのドキュメントに書いてある…)。

    1.整数や浮動小数点数のような論理的に単一な値を表す
    2.インスタンスのサイズが16バイト未満である
    3.継承により振る舞いを変更する必要がない
    4.頻繁にボックス化する必要がない

    例えば「二次元座標を表すPointオブジェクト」のようなもの
    は構造体に向いています。



                                 32/57
Learn C# in Unity
 C#の便利な機能
 ・Enum:一連の定数を1つにまとめた型
    public class Foo
    {
         // 関連のある定数群をこう書くよりも…
         const int DamageTypeSlash = 1;
         const int DamageTypeBlunt = 2;
         const int DamageTypeExplosion = 3;

        // enumにしたほうが見通しが良い
        enum DamageType
        {
             Slash = 1, // 値を明言することもできる。明言しないと前の値+1になる。基底は0。
             Blunt,     // 直前の値が1なのでこいつは2。
             Explosion,
        }

        DamageType damageType; // DamageType型のどれか1つの値を取るメンバーフィールド、という意味

        // Enum型の各値には、「型名.名前」という形式でアクセスする。
        public Foo() { damageType = DamageType.Blunt; }

        // 整数へのキャストは保証されているが、あまり感心できる使い方ではない…
        int GetDamageTypeID() { return (int)damageType; }
    }



                                                                          33/57
Learn C# in Unity
 C#の便利な機能
 ・namespace:名前空間
    namespace MyClasses //関連するオブジェクトを1つの名前空間に収めることで検索性を上げたり名前の衝突を防ぐ
    {
         public class Foo { }
         public class Bar { }
    }
    // 名前空間の中の要素にはこのように書いてアクセス
    MyClasses.Foo f;


    // 別のファイルでも同じ名前空間を宣言することができる
    namespace MyClasses
    {
         public class Hoge { }
    }


    // ファイルの先頭でusingディレクティブを使うと、アクセス時の名前空間を省略できる
    using MyClasses;

    Foo f;



    ファイルの先頭でusing UnityEngine;とかやってるのはコレ

                                                                34/57
Learn C# in Unity
 C#の便利な機能
 ・キャスト、型情報の利用
    キャスト(型の明示的な変換)はCの書き方と似ています。
    またis演算子、as演算子という型チェックの簡単な書き方があ
    ります。
       // 普通のキャストは「(目的の型)」で行う
       Collider c = (Collider)gameObject.AddComponent("BoxCollider");

       // is演算子でインスタンスの型が指定したものかどうかチェックできる
       if (c is BoxCollider)
            boxCollider = c as BoxCollider; // インスタンスを指定した型にキャスト、できなかったらnull

       // 型情報を取り出して自分で判定することも
       if (c.GetType() == typeof(BoxCollider))
            print("OK");

       // ジェネリックを使えばそもそもキャストはいらなかったり
       c = gameObject.AddComponent<BoxCollider>();




                                                                         35/57
Learn C# in Unity
 C#の便利な機能
 ・var
    型が明確なローカル変数は、型名をvarで代用することが可能
    public class Foo
    {
         void Hoge()
         {
              // これは
              Transform t = transform;
              // こう書いてもいい
              var t = transform;
              // その1文ではvarが実際何の型になるのかわからない書き方はNG
              var i;
              i = 0;
         }

        public var i = 0; // これもNG。varが使えるのはローカル変数のみ。
    }




                                                        36/57
Learn C# in Unity
 C#の便利な機能
 ・パーシャルクラス・パーシャルメソッド
    1つのクラスの定義を複数のファイルに分けて書くことが可能
    public partial class Foo          public partial class Foo
    {                                 {
         void Hoge()                       void Mage()
         {                                 {
         }                                 }
    }                                 }


    // もちろんクラスFooはHoge、Mage両方のメソッドをメンバに持っている
    Foo f = new Foo();
    f.Hoge();
    f.Mage();



    パーシャルクラスのメソッドにpartial修飾子を付けると、実装
    を別のファイルで定義しても、定義しなくても(!)いい。
    public partial class Foo
    {
         partial void Hoge();
    }


                                                                 37/57
Learn C# in Unity
 C#の便利な機能
 ・拡張メソッド
    staticメソッドをあたかもインスタンスメソッドのように呼べ
    るようにする機能です。クラスにメソッドを追加しているよう
    に見えるけど、継承ではないので既存のメソッドの振る舞いを
    変更したりはできないし、多用すると混乱の元。
    // 本来は以下のようにしか書けないが
    Instantiate(prefabObject);

    // 拡張メソッドの機能を使うと
    static class GameObjectExtension
    {
         // staticメソッドの第一引数の前にthisを付けると拡張メソッドになる
         public static Object Instantiate(this GameObject prefab)
         {
              return Instantiate(prefab);
         }
    }

    // あたかもGameObjectクラスがInstantiate()というインスタンスメソッドを持っているかのように書ける
    prefabObject.Instantiate();



                                                                    38/57
Learn C# in Unity
 C#の制御構文
 ・if文、for文、while・do~while文
    他言語と比べて別段取り立てるような差異はありません。
    contiue、break、gotoなども使えます。
 ・switch文
    caseに文字列が使えたり、基本的にはbreakを省略できなかっ
    たり、他言語と比べて少し特殊です。
       switch (hoge)
       {
       case 0: // case文の間に処理が挟まらない場合だけフォールスルーできる
       case 1: // caseを繋げて書いてあるので、hogeの値が0か1の場合、以下のDoSomething()が呼ばれる
            DoSomething();
            break; // これは省略できない(Cなどでは省略すると処理が下に繋がる)
       case 2:
            DoSomething2();
            goto case 0; // 何か処理をした後どうしても他のcaseに進みたい場合はgotoを使う
       default: // 上記のどのcaseにも当てはまらなかった場合、という書き方
            DoNothing();
            break;
       }


                                                                        39/57
Learn C# in Unity
 C#の制御構文
 ・foreach文
    配列やコレクションなどの全ての要素に対して繰り返し処理を
    行います。
       foreach (AudioSource a in GetComponents<AudioSource>())
       {
            a.Stop();
       }


    後述するLinqと組み合わせるとfor文がほとんど要らなくなる。
       // アタッチされているAoudioSouceのうち、再生中の物に対してだけStop()を呼び出す、という例
       foreach (var a in from a in GetComponents<AudioSource>() where a.isPlaying select a)
       {
            a.Stop();
       }


    ループ文の中でif文を使って分岐させると、ループ処理自体が長
    くなってしまうので、可能ならLinqであらかじめリストを整形
    してからforeach文で処理すると見通しが良くなります。

                                                                                         40/57
Learn C# in Unity
 C#の制御構文
 ・try~catch~finally文
    C#での例外処理を制御する構文だけど、Unityが例外をほとん
    ど意識しなくて良い設計になっているのであまり使いません。
    StreamReader sr = null;
    try
    {
         sr = File.OpenText(path);
         string s = "";
         while ((s = sr.ReadLine()) != null)
              print(s);
    }
    catch (FileNotFoundException e)
    {
         print("File Not Found!");
    }
    finally
    {
         sr.Dispose();
    }




                                               41/57
Learn C# in Unity
 C#の制御構文
 ・using文
    名前空間の省略や型の別名定義にもusingというキーワードを
    使うので混乱しやすいけど、メソッド内に出てくるusing文は
    Dispose()の呼び出しを保証するもの。UnityEngineには
    IDisposableを実装したクラスがないのであまり使わない…。
    ■using版                                         ■非using版
    using (StreamReader sr = File.OpenText(path))   StreamReader sr = null;
    {                                               try
         string s = "";                             {
         while ((s = sr.ReadLine()) != null)             sr = File.OpenText(path);
              print(s);                                  string s = "";
    }                                                    while ((s = sr.ReadLine()) != null)
                                                              print(s);
                                                    }
                                                    finally
                                                    {
                                                         sr.Dispose();
                                                    }




                                                                                        42/57
Learn C# in Unity
 ジェネリック
 ・ジェネリックとは
    不要なキャストを減らし、コンパイル時に型チェックができ、
    コードが最適化されパフォーマンスが良くなる、大変素晴らし
    い機能です。大変素晴らしいです。
       BoxCollider c;

       // 非ジェネリック版(長い。しなくてもいいキャストは見苦しい…)
       c = (BoxCollider)gameObject.AddComponent(typeof(BoxCollider));
       c = gameObject.AddComponent(typeof(BoxCollider)) as BoxCollider;

       // ジェネリック版
       c = gameObject.AddComponent<BoxCollider>();



    しかしUnityはジェネリック版のメソッドをあまり用意していな
    い…ぐぬぬ…。



                                                                          43/57
Learn C# in Unity
 ジェネリック
 ・自分でジェネリック対応する
       // 例えばこんなメソッドをジェネリック版にする場合
       Object FindObjectOf(Type type)
       {
            return FindObjectOfType(type);
       }

       // 型パラメータの名前をTとしてあるのは慣習(スタンダードなルールがある)
       T FindObjectOf<T>() where T: Component // 型パラメータに制限を課すことができる(任意)
       {
            return (T)FindObjectOfType(typeof(T));
       }

       // 上記ジェネリックメソッドの呼び出し方
       var renderer = FindObjectOf<Renderer>(); // 型が自明なのでvarが使えるしキャストもない!

       // 型パラメーターに制限をかけてあるので以下はコンパイル時エラー。素晴らしい!
       int i = FindObjectOf<int>(); // intはComponentを継承していない




                                                                             44/57
Learn C# in Unity
 ジェネリック
 ・非ジェネリックコンテナは使うな
    ボックス化のところで説明したように、ArrayListなどの非ジェ
    ネリックコンテナは、知らないうちにパフォーマンスが悪化し
    たり、本来必要ないキャストが増えたりしてよろしくありませ
    ん(キャストが増えるとバグが増える)。
    明確な理由がない場合は、System.Collections.Generic名前
    空間にある、ジェネリック版のコンテナを使いましょう。
    using System.Collections.Generic;

    List<int> list;
    list.Add(100); // ボックス化無し!
    list.Add("hoge"); // コンパイル時エラー!
    int i = list[0]; // もちろんボックス化解除も無し!




                                          45/57
Learn C# in Unity
 デリゲート
 ・メソッドを参照できる型
    メソッドの参照を保存しておいて後から呼び出したり、複数の
    メソッドを1つの変数に入れておいてまとめて呼び出せるよう
    にする機能です。
    // デリゲート型の定義
    delegate void SomeDelegate(float f);
    // 定義した型の変数を宣言
    SomeDelegate someDelegate;

    // 例えばこんなメソッドを先ほどの変数へ代入することができる
    void Hoge(float value) { } // 型さえあってれば引数の名前は同じじゃなくてもいい
    someDelegate = Hoge;

    // インスタンスメソッドも代入できる
    public class Foo
    {
         public void Bar(float amount) { }
    }
    Foo f = new Foo();
    someDelegate += f.Bar; // 「+=」で追加代入できる

    // デリゲート変数に格納されているメソッドを呼ぶ(Hogeとf.Barが順番に呼ばれる)
    someDelegate(1.0f);

                                                             46/57
Learn C# in Unity
 デリゲート
 ・元々用意されているデリゲート
    引数も取らず戻り値もないデリゲートとか、引数をひとつ取り
    bool値を返すデリゲートなどは頻出するので、System以下に
    あらかじめ用意されています(自分で定義しなくてOK)。
    System.Func<TResult> // TResult Func()

    System.Predicate<T> // bool Predicate(T value)

    System.Action<T> // void Action(T value)

    System.Action<T1, T2> // void Action(T1 p1, T2 p2)




                                                         47/57
Learn C# in Unity
 イベント
 ・デリゲートを外から実行できなくする
    例えばダメージを喰らったタイミングをデリゲートを使って他
    のオブジェクトに通知したい場合、デリゲートむき出しだと外
    から実行できてしまいます。これは困る。
    public class Foo
    {
         // デリゲート型の定義
         public delegate void OnDamageDelegate(GameObject victim, float amount);
         // 定義したデリゲート型の変数を宣言(privateにしちゃうと登録すらできなくなっちゃうので意味なし)
         public OnDamageDelegate onDamage;
         // ダメージ処理
         float hp { get; private set; }
         public void DoDamage(float amount) {
              hp -= amount;
              onDamage(gameObject, amount);
         }
    }
    Foo f = new Foo();
    f.onDamage(1.0f); // 実際にはダメージを喰らってないのにonDamageを直接呼べてしまう


    そういう時はイベントという機能を使いましょう

                                                                                   48/57
Learn C# in Unity
 イベント
 ・イベントは外からは追加と削除だけできる
    デリゲートむき出しではなくイベントにすると、追加と削除は
    クラス外からでもできるけど、実行はクラス内でしかできない
    ようになります。これで変なタイミングで呼ばれなくなる。
    public class Foo
    {
         // デリゲート型の定義
         public delegate void OnDamageDelegate(GameObject victim, float amount);
         // デリゲート型の変数に「event」を付けるだけ
         public event OnDamageDelegate onDamage;
         // ダメージ処理
         float hp { get; private set; }
         public void DoDamage(float amount) {
              hp -= amount;
              onDamage(gameObject, amount);
         }
    }
    Foo f = new Foo();
    f.onDamage(1.0f); // コンパイルエラー!
    f.onDamage += PrintDamage; // 追加は問題なく行える




                                                                                   49/57
Learn C# in Unity
 ラムダ式
 ・名前の無いメソッド
    イベントに登録するメソッドをいちいち全部メンバーメソッド
    として定義していくと、クラスが無駄に巨大化しがちです。
    そこでラムダ式という、名前がない、何かに代入した状態でな
    いと呼び出せないメソッドを定義できる機能を使います。
    public class Foo
    {
         // デリゲート型の定義
         public delegate void OnDamageDelegate(GameObject victim, float amount);
         // デリゲート型の変数に「event」を付けるだけ
         public event OnDamageDelegate onDamage;
         /* 略 */
    }
    Foo f = new Foo();
    // イベントにラムダ式を代入
    f.onDamage = (victim, amount) => print(victim.name + " got damage " + amount);
    // これは以下と同じ
    void PrintDamage(GameObject victim, float amount)
    {
         print(victim.name + " got damage " + amount);
    }
    f.onDamage += PrintDamage;

                                                                                     50/57
Learn C# in Unity
 ラムダ式
 ・コンテナの走査などにも使える
    Listクラスなどは条件判定用デリゲート(リストの要素1つを
    引数に取り、bool値を返すメソッド)を引数に取るFindメソッ
    ドなどをメンバーに持っています。こいつにラムダ式を渡すこ
    とも可能。
    // 例えばGameObjectのリストがあったとして、
    List<GameObject> gameObjects = new List<GameObject>(src);

    // 名前に「Enemy」を含むオブジェクトを探す
    GameObject go = gameObjects.Find(o => o.name.Contains("Enemy")); // returnは省略可能。いい。

    // gameObjectsリストのうち、Y座標が0未満のオブジェクトを全て削除
    gameObjects.RemoveAll(o => o.transform.x < 0); // returnは省略可能。いい。




                                                                                     51/57
Learn C# in Unity
 LINQ
 ・データベース向けに導入された機能だけど
    要するに大量のデータの中から必要な物だけ抽出したり、複数
    のリストをマージしたり、データの塊を整形するための機能で
    す。うまく使うとコードが非常にすっきりする。
    // 例えばこんなループは
    var renderers = GetComponentsInChildren<Renderer>();
    foreach (var r in renderers)
    {
         if (r != null && r.material != null)
              r.material.mainColor = Color.red;
    }

    // LINQだとこう書ける
    var materials = from r in GetComponentsInChildren<Renderer>()
                    where r != null && r.material != null
                    select r.material;
    foreach (Material m in materials)
         m.mainColor = Color.red;



    ループの中で分岐するより先にリストを整形してしまった方が
    間違いが起こりにくい。
                                                                    52/57
Learn C# in Unity
 LINQ
 ・匿名クラスと組み合わせるとさらに強力に
    注目したいメンバーだけ抽出した匿名クラスを作って返せば、
    余計なメンバーにアクセスしてバグることもなくなる。
    var materialSets = from Renderer r in FindObjectsOfType(typeof(Renderer))
                        where r.material != null && r.sharedMaterial != null
                        select new { r.material, r.sharedMaterial };
    foreach (var m in materialSets)
    {
         m.material.mainTexture = texture;
         m.sharedMaterial.mainTexture = texture;
    }




    ただし軽い処理ではないので使いどころに注意する必要がある




                                                                                53/57
Learn C# in Unity
 コルーチン
 ・C#のイテレーター構文を流用している
    C#のyield returnの本来の目的は、イテレータを気軽に実装す
    るためのものです。途中まで処理して一旦メソッドを抜けて、
    次またそこ(メソッドの途中)から再開できる、という特性が
    マルチタスク処理に向いていたので、Unityではコルーチンに流
    用されたようです。コルーチンはC#の機能ではありません。
    // 本来の使い方
    IEnumerator Count10()
    {
         for (int i = 10; i >= 0; --i)
              yield return i;
    }

    foreach (var i in Count1to10())
    {
         print(i); // 10, 9, 8, 7...
    }




                                         54/57
Learn C# in Unity
 コルーチン
 ・コンパイル時に暗黙のクラスが作られている
    yield文が含まれたメソッドは、実はコンパイル時に暗黙の列挙
    用クラスに変換されています。
    IEnumerator CountUp()     class CountUpEnumerator : IEnumerator
    {                         {
         print(1);                 int state = 0;
         yield return null;        bool MoveNext()
         print(2);                 {
         yield return null;             switch (state++)
         print(3);                      {
    }                                   case 0:
                                             print(1);
                                             return null;
                                        case 1:
                                             print(2);
                                             return null;
                                        case 2:
                                             print(3);
                                        }
                                   }
                              }
                              IEnumerator CountUp()
                              {
                                   return new CountUpEnumerator();
                              }

                                                                      55/57
Learn C# in Unity
 コルーチン
 ・コルーチンはMoveNextを毎フレーム呼んでるだけ
    おそらくGameObjectが今実行中のコルーチン(先ほどの列挙
    用クラスのインスタンス)のリストを持っていて、毎フレーム
    それらのMoveNext()メソッドを呼んでいるだけ。似たような
    処理を自分でも書ける。コルーチンごとに停止再開などを管理
    したい場合は、こっちのほうが柔軟性が高い。
    public class Foo : MonoBehaviour
    {
         List<IEnumerator> coroutines = new List<IEnumerator>();
         void Start()
         {
              coroutines.Add(MyCoroutine1());
              coroutines.Add(MyCoroutine2());
         }
         void Update()
         {
              coroutines.RemoveAll(c => !c.MoveNext());
         }
    }




                                                                   56/57
Learn C# in Unity
 おしまい!




           ご清聴ありがとうございました




                            57/57

Weitere ähnliche Inhalte

Was ist angesagt?

Doozy UI 使おうぜ! #unity_lt
Doozy UI 使おうぜ! #unity_ltDoozy UI 使おうぜ! #unity_lt
Doozy UI 使おうぜ! #unity_lttorisoup
 
大規模ゲーム開発における build 高速化と安定化
大規模ゲーム開発における build 高速化と安定化大規模ゲーム開発における build 高速化と安定化
大規模ゲーム開発における build 高速化と安定化DeNA
 
Unityでパフォーマンスの良いUIを作る為のTips
Unityでパフォーマンスの良いUIを作る為のTipsUnityでパフォーマンスの良いUIを作る為のTips
Unityでパフォーマンスの良いUIを作る為のTipsUnity Technologies Japan K.K.
 
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術Unity Technologies Japan K.K.
 
【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説
【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説
【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説Unity Technologies Japan K.K.
 
C#とILとネイティブと
C#とILとネイティブとC#とILとネイティブと
C#とILとネイティブと信之 岩永
 
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例sairoutine
 
Unityでオニオンアーキテクチャ
UnityでオニオンアーキテクチャUnityでオニオンアーキテクチャ
Unityでオニオンアーキテクチャtorisoup
 
【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-
【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-
【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-Unity Technologies Japan K.K.
 
Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介torisoup
 
誰もAddressableについて語らないなら、自分が語るしかない…ッッッッ
誰もAddressableについて語らないなら、自分が語るしかない…ッッッッ誰もAddressableについて語らないなら、自分が語るしかない…ッッッッ
誰もAddressableについて語らないなら、自分が語るしかない…ッッッッTatsuhiko Yamamura
 
Azure PlayFab トレーニング資料
Azure PlayFab トレーニング資料Azure PlayFab トレーニング資料
Azure PlayFab トレーニング資料Daisuke Masubuchi
 
ワタシはSingletonがキライだ
ワタシはSingletonがキライだワタシはSingletonがキライだ
ワタシはSingletonがキライだTetsuya Kaneuchi
 
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現Yoshifumi Kawai
 
【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!
【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!
【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!Unity Technologies Japan K.K.
 
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しようUnityTechnologiesJapan002
 
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方Yoshifumi Kawai
 

Was ist angesagt? (20)

Doozy UI 使おうぜ! #unity_lt
Doozy UI 使おうぜ! #unity_ltDoozy UI 使おうぜ! #unity_lt
Doozy UI 使おうぜ! #unity_lt
 
UIElements+UI BuilderでEditor拡張を作ろう
UIElements+UI BuilderでEditor拡張を作ろうUIElements+UI BuilderでEditor拡張を作ろう
UIElements+UI BuilderでEditor拡張を作ろう
 
大規模ゲーム開発における build 高速化と安定化
大規模ゲーム開発における build 高速化と安定化大規模ゲーム開発における build 高速化と安定化
大規模ゲーム開発における build 高速化と安定化
 
Unityでパフォーマンスの良いUIを作る為のTips
Unityでパフォーマンスの良いUIを作る為のTipsUnityでパフォーマンスの良いUIを作る為のTips
Unityでパフォーマンスの良いUIを作る為のTips
 
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
 
【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説
【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説
【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説
 
C#とILとネイティブと
C#とILとネイティブとC#とILとネイティブと
C#とILとネイティブと
 
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
 
Unityでオニオンアーキテクチャ
UnityでオニオンアーキテクチャUnityでオニオンアーキテクチャ
Unityでオニオンアーキテクチャ
 
日本一詳しい人が教えるUE4
日本一詳しい人が教えるUE4日本一詳しい人が教えるUE4
日本一詳しい人が教えるUE4
 
【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-
【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-
【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-
 
Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介
 
誰もAddressableについて語らないなら、自分が語るしかない…ッッッッ
誰もAddressableについて語らないなら、自分が語るしかない…ッッッッ誰もAddressableについて語らないなら、自分が語るしかない…ッッッッ
誰もAddressableについて語らないなら、自分が語るしかない…ッッッッ
 
Azure PlayFab トレーニング資料
Azure PlayFab トレーニング資料Azure PlayFab トレーニング資料
Azure PlayFab トレーニング資料
 
猫でも分かる UE4の新しいサンプル「Action RPG」について
猫でも分かる UE4の新しいサンプル「Action RPG」について猫でも分かる UE4の新しいサンプル「Action RPG」について
猫でも分かる UE4の新しいサンプル「Action RPG」について
 
ワタシはSingletonがキライだ
ワタシはSingletonがキライだワタシはSingletonがキライだ
ワタシはSingletonがキライだ
 
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
 
【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!
【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!
【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!
 
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
【Unite Tokyo 2019】Unity Test Runnerを活用して内部品質を向上しよう
 
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方
Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方
 

Ähnlich wie Unityで覚えるC#

What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...Yoshifumi Kawai
 
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例Yoshifumi Kawai
 
第2回デザインパターン資料
第2回デザインパターン資料第2回デザインパターン資料
第2回デザインパターン資料gaaupp
 
cocos2d-xとネイティブ間の連携
cocos2d-xとネイティブ間の連携cocos2d-xとネイティブ間の連携
cocos2d-xとネイティブ間の連携Tomoaki Shimizu
 
pi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピングpi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピングkunihikokaneko1
 
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~Fujio Kojima
 
C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~Fujio Kojima
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 
TypeScript と Visual Studio Code
TypeScript と Visual Studio CodeTypeScript と Visual Studio Code
TypeScript と Visual Studio CodeAkira Inoue
 
メディア・アートII 第3回 openFrameworks基礎 OOoF : オブジェクト指向 oF
メディア・アートII 第3回 openFrameworks基礎 OOoF : オブジェクト指向 oFメディア・アートII 第3回 openFrameworks基礎 OOoF : オブジェクト指向 oF
メディア・アートII 第3回 openFrameworks基礎 OOoF : オブジェクト指向 oFAtsushi Tadokoro
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~Akira Inoue
 
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用de:code 2017
 
GroovyなAndroidテスト #atest_hack
GroovyなAndroidテスト #atest_hackGroovyなAndroidテスト #atest_hack
GroovyなAndroidテスト #atest_hackTakahiro Yoshimura
 
2018/06/23 Sony"s deep learning software and the latest information
2018/06/23 Sony"s deep learning software and the latest information2018/06/23 Sony"s deep learning software and the latest information
2018/06/23 Sony"s deep learning software and the latest informationSony Network Communications Inc.
 
Entity Framework 5.0 deep dive
Entity Framework 5.0 deep diveEntity Framework 5.0 deep dive
Entity Framework 5.0 deep diveAtsushi Fukui
 

Ähnlich wie Unityで覚えるC# (20)

Boost Fusion Library
Boost Fusion LibraryBoost Fusion Library
Boost Fusion Library
 
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
What, Why, How Create OSS Libraries - 過去に制作した30のライブラリから見るC#コーディングテクニックと個人OSSの...
 
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
 
第2回デザインパターン資料
第2回デザインパターン資料第2回デザインパターン資料
第2回デザインパターン資料
 
cocos2d-xとネイティブ間の連携
cocos2d-xとネイティブ間の連携cocos2d-xとネイティブ間の連携
cocos2d-xとネイティブ間の連携
 
pi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピングpi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピング
 
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
C#の新機能勉強会 ~ C#7、8の新機能を活用して速く安全なプログラムを書こう~
 
C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~C#勉強会 ~ C#9の新機能 ~
C#勉強会 ~ C#9の新機能 ~
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 
TypeScript と Visual Studio Code
TypeScript と Visual Studio CodeTypeScript と Visual Studio Code
TypeScript と Visual Studio Code
 
メディア・アートII 第3回 openFrameworks基礎 OOoF : オブジェクト指向 oF
メディア・アートII 第3回 openFrameworks基礎 OOoF : オブジェクト指向 oFメディア・アートII 第3回 openFrameworks基礎 OOoF : オブジェクト指向 oF
メディア・アートII 第3回 openFrameworks基礎 OOoF : オブジェクト指向 oF
 
Boost tour 1_40_0
Boost tour 1_40_0Boost tour 1_40_0
Boost tour 1_40_0
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用
 
Mvc conf session_4_ono
Mvc conf session_4_onoMvc conf session_4_ono
Mvc conf session_4_ono
 
GroovyなAndroidテスト #atest_hack
GroovyなAndroidテスト #atest_hackGroovyなAndroidテスト #atest_hack
GroovyなAndroidテスト #atest_hack
 
20110607
2011060720110607
20110607
 
2018/06/23 Sony"s deep learning software and the latest information
2018/06/23 Sony"s deep learning software and the latest information2018/06/23 Sony"s deep learning software and the latest information
2018/06/23 Sony"s deep learning software and the latest information
 
Entity Framework 5.0 deep dive
Entity Framework 5.0 deep diveEntity Framework 5.0 deep dive
Entity Framework 5.0 deep dive
 

Kürzlich hochgeladen

論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Danieldanielhu54
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 

Kürzlich hochgeladen (10)

論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Daniel
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 

Unityで覚えるC#

  • 2. Learn C# in Unity 初学者にありがちな混乱 ・言語の仕様 ・標準ライブラリの仕様 ・実行環境の仕様 この3つをごっちゃにして「何がわからないのかわからない」 状態になりがち。C#の文法の問題なのか、.Net Framework の問題なのか、Unityの問題なのか切り分けて考えよう。 今回は主にC#の文法の話と、よく使う(知らないとそもそも発 想に至らない).Net Frameworkの機能の話をします。 2/57
  • 3. Learn C# in Unity オブジェクト指向 再々(xN)入門 ・その前に、とても眠くなるそもそも論 そもそもプログラムとは「データの加工」です。つまり「デー タ」と「加工」という2つの要素から成り立っています。プロ グラムの用語に直すと「変数」と「関数」です。 オブジェクト指向以前は、データと加工処理が完全に別れてい ました。データ、つまり変数を、それを処理する関数に渡して 加工してもらい、受け取った結果をまた別の関数に渡して、と いう流れを延々繰り返します。 オブジェクト指向はその考え方を1段階抽象化して、関連する 変数と関数を1まとまりにしたオブジェクトという概念を導入 し、プログラムは各オブジェクトが協調動作して動くものだ、 と考えるようになりました。 3/57
  • 4. Learn C# in Unity オブジェクト指向 再々(xN)入門 ・オブジェクト指向以前・以後 オブジェクト指向という考え方をした場合としなかった場合、 プログラムの構造がどのようにかわるか、という例。 ■BEFORE ■AFTER int GetFileSize(string fname); class File bytes ReadFromFile(string fname, int size); { void WriteToFile(string fname, bytes data); bytes data; void CloseFile(string fname); void Open(string fname); void Close(); main() } { string fname = "hoge.txt"; main() int size = GetFileSize(fname); { bytes data = ReadFromFile(fname, size); File f = new File(); for (int i = 0; i < size; i++) f.Open("hoge.txt"); data[i] += 1; for (int i = 0; i < f.data.size; i++) WriteToFile(fname, data); f.data[i] += 1; CloseFile(fname); f.Close(); } } 4/57
  • 5. Learn C# in Unity オブジェクト指向 再々(xN)入門 ・一般的な意味での用語の定義(≠C#の用語) ■オブジェクト データや処理が1まとまりになった最小のプログラム片 ■クラス/構造体 オブジェクトの設計図 ■インスタンス メモリ上に配置されたクラス/構造体の実体 ■メンバー変数/メンバーフィールド/メンバープロパティ オブジェクトが持つ情報 ■メンバー関数/メンバーメソッド オブジェクトの動作を定義した関数 ■インターフェース オブジェクトがどんなメンバーを持っているか、どう振る舞 うかの定義。実は一番大事な概念。 5/57
  • 6. Learn C# in Unity オブジェクト指向 再々(xN)入門 ・プログラムの設計=インターフェースの設計  オブジェクト指向に限らず、プログラムの設計とはインターフェー スの設計に他なりません。オブジェクト指向ならそもそも何をオブ ジェクトに見立てて、それがどんなメンバーを持っているのか、つま りどんなインターフェースにするのかを決めることが最大の関心事で あり、一番難しい問題です。  ライブラリの場合だと、ユーザーのプログラムと、どんなデータを どんな関数を介してやりとりするのか決めること=インターフェース の設計です。  ゲームだってユーザーに対してどんな情報を見せるのか、あるいは 見せないのか、つまりユーザーインターフェースの設計がキモであ り、難しい部分です。  インターフェースが適切になっているか、常に意識しながらプログ ラミングしましょう。 6/57
  • 7. Learn C# in Unity オブジェクト指向 再々(xN)入門 ・Unityの代表的なオブジェクト ■Vector3 X,Y,Zの値を持つベクトル。位置情報などを表す。 ■Input ユーザーからの入力を一元管理している。 ■GameObject ゲーム空間(シーン)の中に存在するものは全てこれ。 ■Component GameObjectにアタッチすることで、GameObjectがどう 振る舞うか定義できる。 ■Transform Componentの一種で、ゲーム空間中での位置や向きなどを 管理する。全てのGameObjectに付いている。 7/57
  • 8. Learn C# in Unity オブジェクト指向 再々(xN)入門 ・継承 あるオブジェクトの機能を引き継ぎ、より具体的な機能を追加 した新しいオブジェクトを作る仕組み。 Component Transform Camera BoxCollider Collider SphereCollider MonoBehaviour PlayerBehaviour EnemyBehaviour 8/57
  • 9. Learn C# in Unity オブジェクト指向 再々(xN)入門 ・多態(ポリモーフィズム) あるオブジェクトが継承先で何をやっているか意識することな く、継承元のインターフェースでアクセスできる仕組み。 BoxCollider bool Raycast(ray) Collider { bool Raycast(ray) return 線と立方体の判定結果; } Ray Bool SphereCollider bool Raycast(ray) { return 線と球の判定結果; GameObject } 9/57
  • 10. Learn C# in Unity Unityの設計から学ぶオブジェクト指向 ・継承が全てではない! Unityのゲームシステムは、オブジェクト指向を一歩進めたコン ポーネント指向という考え方で作られています。 ■古いオブジェクト指向 GameCharacter PlayerCharacter GameObject MeshData mesh; Controller controller; EnemyCharacter AI ai; ■コンポーネント指向 MeshData MeshData GameObject GameObject Controller EnemyAI 10/57
  • 11. Learn C# in Unity C#におけるクラス ・クラスの定義の仕方 using UnityEngine; // 使うライブラリの宣言 // MonoBehaviourを継承したNewBehaviourScriptクラスの宣言 public class NewBehaviourScript : MonoBehaviour { // メンバーフィールドの宣言 public Vector3 velocity; // メンバーメソッドの定義 void Update() { transform.Translate(velocity * Time.deltaTime); } } メンバーの宣言に、publicを付けるとクラスの外からも見える ようになる。privateを付けるか何も付けないと、クラスの外か らは見えないようになる。内部で何をやっているかはできるだ け見せない方がよい。 11/57
  • 12. Learn C# in Unity C#におけるクラス ・クラスがメンバーに持てるもの ■フィールド 変数。通常あまり生のメンバー変数を公開するものではない が、Unityの場合パブリックフィールドにしないとインスペ クタに表示されない。 ■メソッド/コンストラクタ/デストラクタ 関数。コンストラクタとデストラクタは少し特殊な関数。 ■プロパティ アクセサの簡易表記法 ■インデクサー オブジェクトを配列のように扱えるようにするための機能 ■イベント 処理の一部を外部に委譲したり、何かのタイミングを通知す るための機能。 12/57
  • 13. Learn C# in Unity C#におけるクラス ・コンストラクタ オブジェクトの初期化処理を行うためのメソッド。ただしUnity はMonoBehaviourを継承したクラスがコンストラクタを実装 することを推奨していません。Awake/Startを使いましょう。 public class Foo : Bar { int i; // コンストラクタの定義。戻り値のない、クラス名とまったく同じ名前のメソッドにする。引数は取れる。 public Foo(int i) { this.i = i; } // 同じクラスの別のコンストラクタを呼ぶ書き方。 public Foo() : this(0) { } // 継承元のコンストラクタを明示的に呼び出す書き方。省略すると継承元の引数なしコンストラクタが呼ばれる。 public Foo(float f) : base(f) { } } Foo f = new Foo(1.0f); // 3つめのコンストラクタが呼ばれる 13/57
  • 14. Learn C# in Unity C#におけるクラス ・デストラクタ オブジェクトの破棄処理を行うためのメソッド。C#はGCが動 いていて明示的な破棄はしなくてよいので、通常意識する必要 はありません。 public class Foo { // デストラクタの定義。戻り値も引数もアクセス指定もない、クラス名の最初に~を付けた名前のメソッドにする。 ~Foo() { } } C#で破棄のタイミングを管理したいクラスはIDisposableを継 承して、Dispose()メソッドを実装し、using文と合わせて使 います。ただDispose()の実装は慣れてないと難しい…。 14/57
  • 15. Learn C# in Unity C#におけるクラス ・プロパティ:アクセサの簡易表記法 public class NewBehaviourScript : MonoBehaviour { // メンバープロパティの定義 public Vector3 velocity { get { return rigidbody.velocity; } set { rigidbody.velocity = value; } } // 上記は、以下の様なアクセサの定義を簡単にできるようにしたもの Vector3 GetVelocity() { return rigidbody.velocity; } void SetVelocity(Vector3 value) { rigidbody.velocity = value; } // プロパティへは普通のメンバーフィールドと同じようにアクセスできる void Start() { velocity = Vector3.zero; } } 15/57
  • 16. Learn C# in Unity C#におけるクラス ・プロパティをもっと便利に使う プロパティは実装を省略してもOK public class NewBehaviourScript : MonoBehaviour { public Vector3 velocity { get; set; } // 上記は、以下のような暗黙のメンバーフィールドを持ったプロパティが作られていると考えてOK Vector3 m_velocity; public Vector3 velocity get { return m_velocity; } set { m_velocity = value; } } } プロパティはget/setごとにアクセス指定を付けることも可能 public class NewBehaviourScript : MonoBehaviour { public Vector3 velocity { get; private set; } } 16/57
  • 17. Learn C# in Unity C#におけるクラス ・プロパティをもっともっと便利に使う 読み取りのみ許可するプロパティの場合は、setを省略できる public class NewBehaviourScript : MonoBehaviour { public Vector3 velocity { get { return rigidbody.velocity; } } } 17/57
  • 18. Learn C# in Unity C#におけるクラス ・インデクサー public class NewBehaviourScript : MonoBehaviour { int[] data; // インデクサーの定義 public int this[int index] { get { return data[index]; } set { data[index] = value; } } // インデクサーをメンバーに持つオブジェクトへは、配列のようにアクセスできる void Start() { NewBehaviourScript nbs = new NewBehaviourScript(); print(nbs[0]); } } 18/57
  • 19. Learn C# in Unity C#におけるクラス ・イベント 重要な機能だけど理解が難しいので後で詳しく説明します。 public class Foo { // デリゲート型の定義 public delegate void OnDamageDelegate(GameObject victim, float amount); // 定義した型のイベントを宣言 public event OnDamageDelegate onDamage; // ダメージ処理 float hp { get; private set; } public void DoDamage(float amount) { hp -= amount; onDamage(gameObject, amount); // onDamageに登録されてるメソッドを呼ぶ } } // 例えばダメージを喰らったタイミングでこのメソッドを呼んで欲しい場合 void PrintDamage(GameObject victim, float amount) { print(victim.name + " got damage " + amount); } // イベントにデリゲートを登録 Foo f = new Foo(); f.onDamage = PrintDamage; // ダメージ処理を呼ぶと、イベントの機能でPrintDamageメソッドが呼ばれる f.DoDamage(10); 19/57
  • 20. Learn C# in Unity C#におけるクラス ・クラスメンバーとインスタンスメンバー 一口にメンバーといっても、クラス自体に属して全てのインス タンスから同じ値を参照するクラスメンバーと、各インスタン ス毎にローカルな値を持つインスタンスメンバーがあります。 public class Foo : MonoBehaviour { // クラスフィールドの定義 public static int classField = 0; // インスタンスフィールドの定義 public int instanceField = 0; // クラスメソッドの定義 public static void Hoge() { print("Hoge! " + classField); } // インスタンスメソッドの定義 public void Mage() { print("Mage! " + classField); } } // クラスメンバーにはインスタンスがなくてもアクセスできる Foo.classField = 10; Foo.Hoge(); // "Hoge! 10" Foo foo = new Foo(); print(foo.instanceField); // 0 foo.Mage(); // "Mage! 10" 20/57
  • 21. Learn C# in Unity C#におけるクラス ・クラスメンバーしか持たないクラス 全てのメンバーがstaticなクラスは、クラス自体もstaticにす ることで、インスタンスを作ることを明示的に禁止できます。 public static class Foo { // クラスフィールドの定義 public static int classField = 0; // クラスメソッドの定義 public static void Hoge() { print("Hoge! " + classField); } // staticなクラスは静的コンストラクター(クラスコンストラクタ)で初期化する static Foo() { classField = 10; } } ちなみに静的コンストラクターは普通のクラスでも使えます。 21/57
  • 22. Learn C# in Unity C#におけるクラス ・クラス修飾子 sealed sealed修飾子を付けたクラスは継承できなくなります。 ・メンバーフィールド修飾子 const 実行中に値が変わらない(変わってはいけない)フィールド につけることで、値を変えようとするコードを書くとコンパ イル時にエラーにしてくれます。 readonly 意味的にはconstと同じ。constは値型(後述)にしか付け られませんが、readonlyは参照型にも付けられます。 22/57
  • 23. Learn C# in Unity C#におけるクラス ・メンバーメソッド修飾子 virtual 継承先で実装を書き換えて良いことを宣言します。 override 継承元で宣言されているvirtualメソッドを上書きして、独自 に実装し直すことを宣言します。 ちなみにoverrideしたメソッドから継承元の本来の処理を 呼び出すには「base.メソッド名()」と書きます。 extern 外部で実装されているメソッドを宣言する時に、DllImport 属性と組み合わせて使います。Unityではネイティブプラグ インのメソッドを呼びたい時に使います。 23/57
  • 24. Learn C# in Unity C#におけるクラス ・属性(アトリビュート) C#はアトリビュートという機能を使って、クラス自体やそのメ ンバーにメタデータを付けることができます。Unityでは自分で 作ったクラスにSerializable属性を付けることでインスペクタ に表示できるようにしたり、エディタの拡張で多用します。 [ExecuteInEditMode()] // この属性を付けると、エディタ上で非実行時もStartとかUpdateが呼ばれる public class NewBehaviourScript : MonoBehaviour { [System.Serializable()] // この属性を付けないと、Foo型のフィールドがインスペクタに表示されない public class Foo { public int hoge; } public Foo f; } 24/57
  • 25. Learn C# in Unity C#における構造体 ・構造体の定義の仕方 public struct Point { // メンバーフィールドの宣言 public int x, y; // メンバーメソッドの定義 public Point(int x, int y) { this.x = x; this.y = y; } } 基本的にはクラスの定義と同じだが、構造体はクラスのような 実装の継承はできない。インターフェース(後述)を継承して、 自分で実装を書くことはできる。 またクラスは参照型だが、構造体は値型であるという違いがあ る(後述)。 25/57
  • 26. Learn C# in Unity C#におけるインターフェース ・インターフェースの定義の仕方 interface ICollidable { // メンバーメソッドの宣言(定義はできない) bool IsCollide(GameObject other); } public class NewBehaviourScript : MonoBehaviour, ICollidable { // インターフェースの実装 public bool IsCollide(GameObject other) { if (gameObject.collider == null || other.collider == null) return false; return IsCollide(gameObject.collider, other.collider); } } インターフェースはそれを継承したオブジェクトがどんなメン バーメソッド、プロパティ、インデクサー、イベントを持つか 明言するためのもの。メンバーフィールドは宣言できず、実装 もできないため、単体では機能しない。 26/57
  • 27. Learn C# in Unity クラス or 構造体 ・参照型と値型 クラスは参照型、構造体は値型です。この2つの違いは、メ ソッドの引数や戻り値としてオブジェクトが渡される時の挙動 に影響します。 例えばオブジェクトFooからBarへ変数が渡される場合… ■参照型 ■値型 複製 Transform Vector3 Vector3 Foo Bar Foo Bar 27/57
  • 28. Learn C# in Unity クラス or 構造体 ・値型の参照渡し refキーワードやoutキーワードを使って、構造体のような値型 の参照を渡す方法もあります。 public class Foo { Vector3 myVector; public AddVectorTo(ref Vector3 target) { target += myVector; } } public class Bar { Foo foo = new Foo(); Vector3 myVector; public Bar() { foo(ref myVector); } } 28/57
  • 29. Learn C# in Unity クラス or 構造体 ・Null許容型 値型の変数でも、まだ初期化されていないことを明示したい場 合があります。そういう時はNull許容型を使います。 public class Foo { Vector3? myVector; // 変数の型の後ろに「?」を付けるとNull許容型になる public Vector3 GetVector() { if (myVector == null) myVector = Vector3.up; return myVector.Value; } } ただこれはデータベースとのやりとりを簡単にするために用意 されたものなので、Unityで使うことはあまりない。使わざるを えないような状況になったらおそらく設計が悪い。 29/57
  • 30. Learn C# in Unity クラス or 構造体 ・参照型 メリット オブジェクトのサイズに関わらず、受け渡しのコストが一定 受け渡した先で値を変更すると、受け渡した元の値も変わる デメリット GCで処理する際のコストが高い ・値型 メリット GCで処理する際のコストが低い 受け渡し先で値を変更しても、受け渡し元は影響を受けない デメリット オブジェクトのサイズに比例して受け渡しのコストが増える ボックス化によるパフォーマンスの悪化がわかりづらい 30/57
  • 31. Learn C# in Unity クラス or 構造体 ・ボックス化・ボックス化解除 値型をobject型に変換することをボックス化、object型を元の 値型へキャストし直すことをボックス化解除といい、どちらも とてもコストが高い操作なので極力避けるようにします(ボッ クス化されるとインスタンスのサイズも増えます)。 object o = 1; // ボックス化 int i = (int)o; // ボックス化解除 // ArrayListは全ての要素をobject型に変換して格納するコレクションクラス ArrayList list = new ArrayList(); list.Add("hoge"); // だから文字列も数値も同じArrayListに格納できるけど… list.Add(100); // ←ここでボックス化が発生!気づきにくい! 後述するジェネリックという機能を使えば不要なボックス化を 減らせるので、積極的に使いましょう。 31/57
  • 32. Learn C# in Unity クラス or 構造体 ・どちらを選ぶべきか 基本はクラスを使い、以下の条件を全て満たす場合のみ構造体 にします(とMicrosoftのドキュメントに書いてある…)。 1.整数や浮動小数点数のような論理的に単一な値を表す 2.インスタンスのサイズが16バイト未満である 3.継承により振る舞いを変更する必要がない 4.頻繁にボックス化する必要がない 例えば「二次元座標を表すPointオブジェクト」のようなもの は構造体に向いています。 32/57
  • 33. Learn C# in Unity C#の便利な機能 ・Enum:一連の定数を1つにまとめた型 public class Foo { // 関連のある定数群をこう書くよりも… const int DamageTypeSlash = 1; const int DamageTypeBlunt = 2; const int DamageTypeExplosion = 3; // enumにしたほうが見通しが良い enum DamageType { Slash = 1, // 値を明言することもできる。明言しないと前の値+1になる。基底は0。 Blunt, // 直前の値が1なのでこいつは2。 Explosion, } DamageType damageType; // DamageType型のどれか1つの値を取るメンバーフィールド、という意味 // Enum型の各値には、「型名.名前」という形式でアクセスする。 public Foo() { damageType = DamageType.Blunt; } // 整数へのキャストは保証されているが、あまり感心できる使い方ではない… int GetDamageTypeID() { return (int)damageType; } } 33/57
  • 34. Learn C# in Unity C#の便利な機能 ・namespace:名前空間 namespace MyClasses //関連するオブジェクトを1つの名前空間に収めることで検索性を上げたり名前の衝突を防ぐ { public class Foo { } public class Bar { } } // 名前空間の中の要素にはこのように書いてアクセス MyClasses.Foo f; // 別のファイルでも同じ名前空間を宣言することができる namespace MyClasses { public class Hoge { } } // ファイルの先頭でusingディレクティブを使うと、アクセス時の名前空間を省略できる using MyClasses; Foo f; ファイルの先頭でusing UnityEngine;とかやってるのはコレ 34/57
  • 35. Learn C# in Unity C#の便利な機能 ・キャスト、型情報の利用 キャスト(型の明示的な変換)はCの書き方と似ています。 またis演算子、as演算子という型チェックの簡単な書き方があ ります。 // 普通のキャストは「(目的の型)」で行う Collider c = (Collider)gameObject.AddComponent("BoxCollider"); // is演算子でインスタンスの型が指定したものかどうかチェックできる if (c is BoxCollider) boxCollider = c as BoxCollider; // インスタンスを指定した型にキャスト、できなかったらnull // 型情報を取り出して自分で判定することも if (c.GetType() == typeof(BoxCollider)) print("OK"); // ジェネリックを使えばそもそもキャストはいらなかったり c = gameObject.AddComponent<BoxCollider>(); 35/57
  • 36. Learn C# in Unity C#の便利な機能 ・var 型が明確なローカル変数は、型名をvarで代用することが可能 public class Foo { void Hoge() { // これは Transform t = transform; // こう書いてもいい var t = transform; // その1文ではvarが実際何の型になるのかわからない書き方はNG var i; i = 0; } public var i = 0; // これもNG。varが使えるのはローカル変数のみ。 } 36/57
  • 37. Learn C# in Unity C#の便利な機能 ・パーシャルクラス・パーシャルメソッド 1つのクラスの定義を複数のファイルに分けて書くことが可能 public partial class Foo public partial class Foo { { void Hoge() void Mage() { { } } } } // もちろんクラスFooはHoge、Mage両方のメソッドをメンバに持っている Foo f = new Foo(); f.Hoge(); f.Mage(); パーシャルクラスのメソッドにpartial修飾子を付けると、実装 を別のファイルで定義しても、定義しなくても(!)いい。 public partial class Foo { partial void Hoge(); } 37/57
  • 38. Learn C# in Unity C#の便利な機能 ・拡張メソッド staticメソッドをあたかもインスタンスメソッドのように呼べ るようにする機能です。クラスにメソッドを追加しているよう に見えるけど、継承ではないので既存のメソッドの振る舞いを 変更したりはできないし、多用すると混乱の元。 // 本来は以下のようにしか書けないが Instantiate(prefabObject); // 拡張メソッドの機能を使うと static class GameObjectExtension { // staticメソッドの第一引数の前にthisを付けると拡張メソッドになる public static Object Instantiate(this GameObject prefab) { return Instantiate(prefab); } } // あたかもGameObjectクラスがInstantiate()というインスタンスメソッドを持っているかのように書ける prefabObject.Instantiate(); 38/57
  • 39. Learn C# in Unity C#の制御構文 ・if文、for文、while・do~while文 他言語と比べて別段取り立てるような差異はありません。 contiue、break、gotoなども使えます。 ・switch文 caseに文字列が使えたり、基本的にはbreakを省略できなかっ たり、他言語と比べて少し特殊です。 switch (hoge) { case 0: // case文の間に処理が挟まらない場合だけフォールスルーできる case 1: // caseを繋げて書いてあるので、hogeの値が0か1の場合、以下のDoSomething()が呼ばれる DoSomething(); break; // これは省略できない(Cなどでは省略すると処理が下に繋がる) case 2: DoSomething2(); goto case 0; // 何か処理をした後どうしても他のcaseに進みたい場合はgotoを使う default: // 上記のどのcaseにも当てはまらなかった場合、という書き方 DoNothing(); break; } 39/57
  • 40. Learn C# in Unity C#の制御構文 ・foreach文 配列やコレクションなどの全ての要素に対して繰り返し処理を 行います。 foreach (AudioSource a in GetComponents<AudioSource>()) { a.Stop(); } 後述するLinqと組み合わせるとfor文がほとんど要らなくなる。 // アタッチされているAoudioSouceのうち、再生中の物に対してだけStop()を呼び出す、という例 foreach (var a in from a in GetComponents<AudioSource>() where a.isPlaying select a) { a.Stop(); } ループ文の中でif文を使って分岐させると、ループ処理自体が長 くなってしまうので、可能ならLinqであらかじめリストを整形 してからforeach文で処理すると見通しが良くなります。 40/57
  • 41. Learn C# in Unity C#の制御構文 ・try~catch~finally文 C#での例外処理を制御する構文だけど、Unityが例外をほとん ど意識しなくて良い設計になっているのであまり使いません。 StreamReader sr = null; try { sr = File.OpenText(path); string s = ""; while ((s = sr.ReadLine()) != null) print(s); } catch (FileNotFoundException e) { print("File Not Found!"); } finally { sr.Dispose(); } 41/57
  • 42. Learn C# in Unity C#の制御構文 ・using文 名前空間の省略や型の別名定義にもusingというキーワードを 使うので混乱しやすいけど、メソッド内に出てくるusing文は Dispose()の呼び出しを保証するもの。UnityEngineには IDisposableを実装したクラスがないのであまり使わない…。 ■using版 ■非using版 using (StreamReader sr = File.OpenText(path)) StreamReader sr = null; { try string s = ""; { while ((s = sr.ReadLine()) != null) sr = File.OpenText(path); print(s); string s = ""; } while ((s = sr.ReadLine()) != null) print(s); } finally { sr.Dispose(); } 42/57
  • 43. Learn C# in Unity ジェネリック ・ジェネリックとは 不要なキャストを減らし、コンパイル時に型チェックができ、 コードが最適化されパフォーマンスが良くなる、大変素晴らし い機能です。大変素晴らしいです。 BoxCollider c; // 非ジェネリック版(長い。しなくてもいいキャストは見苦しい…) c = (BoxCollider)gameObject.AddComponent(typeof(BoxCollider)); c = gameObject.AddComponent(typeof(BoxCollider)) as BoxCollider; // ジェネリック版 c = gameObject.AddComponent<BoxCollider>(); しかしUnityはジェネリック版のメソッドをあまり用意していな い…ぐぬぬ…。 43/57
  • 44. Learn C# in Unity ジェネリック ・自分でジェネリック対応する // 例えばこんなメソッドをジェネリック版にする場合 Object FindObjectOf(Type type) { return FindObjectOfType(type); } // 型パラメータの名前をTとしてあるのは慣習(スタンダードなルールがある) T FindObjectOf<T>() where T: Component // 型パラメータに制限を課すことができる(任意) { return (T)FindObjectOfType(typeof(T)); } // 上記ジェネリックメソッドの呼び出し方 var renderer = FindObjectOf<Renderer>(); // 型が自明なのでvarが使えるしキャストもない! // 型パラメーターに制限をかけてあるので以下はコンパイル時エラー。素晴らしい! int i = FindObjectOf<int>(); // intはComponentを継承していない 44/57
  • 45. Learn C# in Unity ジェネリック ・非ジェネリックコンテナは使うな ボックス化のところで説明したように、ArrayListなどの非ジェ ネリックコンテナは、知らないうちにパフォーマンスが悪化し たり、本来必要ないキャストが増えたりしてよろしくありませ ん(キャストが増えるとバグが増える)。 明確な理由がない場合は、System.Collections.Generic名前 空間にある、ジェネリック版のコンテナを使いましょう。 using System.Collections.Generic; List<int> list; list.Add(100); // ボックス化無し! list.Add("hoge"); // コンパイル時エラー! int i = list[0]; // もちろんボックス化解除も無し! 45/57
  • 46. Learn C# in Unity デリゲート ・メソッドを参照できる型 メソッドの参照を保存しておいて後から呼び出したり、複数の メソッドを1つの変数に入れておいてまとめて呼び出せるよう にする機能です。 // デリゲート型の定義 delegate void SomeDelegate(float f); // 定義した型の変数を宣言 SomeDelegate someDelegate; // 例えばこんなメソッドを先ほどの変数へ代入することができる void Hoge(float value) { } // 型さえあってれば引数の名前は同じじゃなくてもいい someDelegate = Hoge; // インスタンスメソッドも代入できる public class Foo { public void Bar(float amount) { } } Foo f = new Foo(); someDelegate += f.Bar; // 「+=」で追加代入できる // デリゲート変数に格納されているメソッドを呼ぶ(Hogeとf.Barが順番に呼ばれる) someDelegate(1.0f); 46/57
  • 47. Learn C# in Unity デリゲート ・元々用意されているデリゲート 引数も取らず戻り値もないデリゲートとか、引数をひとつ取り bool値を返すデリゲートなどは頻出するので、System以下に あらかじめ用意されています(自分で定義しなくてOK)。 System.Func<TResult> // TResult Func() System.Predicate<T> // bool Predicate(T value) System.Action<T> // void Action(T value) System.Action<T1, T2> // void Action(T1 p1, T2 p2) 47/57
  • 48. Learn C# in Unity イベント ・デリゲートを外から実行できなくする 例えばダメージを喰らったタイミングをデリゲートを使って他 のオブジェクトに通知したい場合、デリゲートむき出しだと外 から実行できてしまいます。これは困る。 public class Foo { // デリゲート型の定義 public delegate void OnDamageDelegate(GameObject victim, float amount); // 定義したデリゲート型の変数を宣言(privateにしちゃうと登録すらできなくなっちゃうので意味なし) public OnDamageDelegate onDamage; // ダメージ処理 float hp { get; private set; } public void DoDamage(float amount) { hp -= amount; onDamage(gameObject, amount); } } Foo f = new Foo(); f.onDamage(1.0f); // 実際にはダメージを喰らってないのにonDamageを直接呼べてしまう そういう時はイベントという機能を使いましょう 48/57
  • 49. Learn C# in Unity イベント ・イベントは外からは追加と削除だけできる デリゲートむき出しではなくイベントにすると、追加と削除は クラス外からでもできるけど、実行はクラス内でしかできない ようになります。これで変なタイミングで呼ばれなくなる。 public class Foo { // デリゲート型の定義 public delegate void OnDamageDelegate(GameObject victim, float amount); // デリゲート型の変数に「event」を付けるだけ public event OnDamageDelegate onDamage; // ダメージ処理 float hp { get; private set; } public void DoDamage(float amount) { hp -= amount; onDamage(gameObject, amount); } } Foo f = new Foo(); f.onDamage(1.0f); // コンパイルエラー! f.onDamage += PrintDamage; // 追加は問題なく行える 49/57
  • 50. Learn C# in Unity ラムダ式 ・名前の無いメソッド イベントに登録するメソッドをいちいち全部メンバーメソッド として定義していくと、クラスが無駄に巨大化しがちです。 そこでラムダ式という、名前がない、何かに代入した状態でな いと呼び出せないメソッドを定義できる機能を使います。 public class Foo { // デリゲート型の定義 public delegate void OnDamageDelegate(GameObject victim, float amount); // デリゲート型の変数に「event」を付けるだけ public event OnDamageDelegate onDamage; /* 略 */ } Foo f = new Foo(); // イベントにラムダ式を代入 f.onDamage = (victim, amount) => print(victim.name + " got damage " + amount); // これは以下と同じ void PrintDamage(GameObject victim, float amount) { print(victim.name + " got damage " + amount); } f.onDamage += PrintDamage; 50/57
  • 51. Learn C# in Unity ラムダ式 ・コンテナの走査などにも使える Listクラスなどは条件判定用デリゲート(リストの要素1つを 引数に取り、bool値を返すメソッド)を引数に取るFindメソッ ドなどをメンバーに持っています。こいつにラムダ式を渡すこ とも可能。 // 例えばGameObjectのリストがあったとして、 List<GameObject> gameObjects = new List<GameObject>(src); // 名前に「Enemy」を含むオブジェクトを探す GameObject go = gameObjects.Find(o => o.name.Contains("Enemy")); // returnは省略可能。いい。 // gameObjectsリストのうち、Y座標が0未満のオブジェクトを全て削除 gameObjects.RemoveAll(o => o.transform.x < 0); // returnは省略可能。いい。 51/57
  • 52. Learn C# in Unity LINQ ・データベース向けに導入された機能だけど 要するに大量のデータの中から必要な物だけ抽出したり、複数 のリストをマージしたり、データの塊を整形するための機能で す。うまく使うとコードが非常にすっきりする。 // 例えばこんなループは var renderers = GetComponentsInChildren<Renderer>(); foreach (var r in renderers) { if (r != null && r.material != null) r.material.mainColor = Color.red; } // LINQだとこう書ける var materials = from r in GetComponentsInChildren<Renderer>() where r != null && r.material != null select r.material; foreach (Material m in materials) m.mainColor = Color.red; ループの中で分岐するより先にリストを整形してしまった方が 間違いが起こりにくい。 52/57
  • 53. Learn C# in Unity LINQ ・匿名クラスと組み合わせるとさらに強力に 注目したいメンバーだけ抽出した匿名クラスを作って返せば、 余計なメンバーにアクセスしてバグることもなくなる。 var materialSets = from Renderer r in FindObjectsOfType(typeof(Renderer)) where r.material != null && r.sharedMaterial != null select new { r.material, r.sharedMaterial }; foreach (var m in materialSets) { m.material.mainTexture = texture; m.sharedMaterial.mainTexture = texture; } ただし軽い処理ではないので使いどころに注意する必要がある 53/57
  • 54. Learn C# in Unity コルーチン ・C#のイテレーター構文を流用している C#のyield returnの本来の目的は、イテレータを気軽に実装す るためのものです。途中まで処理して一旦メソッドを抜けて、 次またそこ(メソッドの途中)から再開できる、という特性が マルチタスク処理に向いていたので、Unityではコルーチンに流 用されたようです。コルーチンはC#の機能ではありません。 // 本来の使い方 IEnumerator Count10() { for (int i = 10; i >= 0; --i) yield return i; } foreach (var i in Count1to10()) { print(i); // 10, 9, 8, 7... } 54/57
  • 55. Learn C# in Unity コルーチン ・コンパイル時に暗黙のクラスが作られている yield文が含まれたメソッドは、実はコンパイル時に暗黙の列挙 用クラスに変換されています。 IEnumerator CountUp() class CountUpEnumerator : IEnumerator { { print(1); int state = 0; yield return null; bool MoveNext() print(2); { yield return null; switch (state++) print(3); { } case 0: print(1); return null; case 1: print(2); return null; case 2: print(3); } } } IEnumerator CountUp() { return new CountUpEnumerator(); } 55/57
  • 56. Learn C# in Unity コルーチン ・コルーチンはMoveNextを毎フレーム呼んでるだけ おそらくGameObjectが今実行中のコルーチン(先ほどの列挙 用クラスのインスタンス)のリストを持っていて、毎フレーム それらのMoveNext()メソッドを呼んでいるだけ。似たような 処理を自分でも書ける。コルーチンごとに停止再開などを管理 したい場合は、こっちのほうが柔軟性が高い。 public class Foo : MonoBehaviour { List<IEnumerator> coroutines = new List<IEnumerator>(); void Start() { coroutines.Add(MyCoroutine1()); coroutines.Add(MyCoroutine2()); } void Update() { coroutines.RemoveAll(c => !c.MoveNext()); } } 56/57
  • 57. Learn C# in Unity おしまい! ご清聴ありがとうございました 57/57