Unityに関連する記事です

static (スタティック) キーワード


 プログラムには、静的(せいてき)と非静的(ひせいてき)という状態があり、基本的には常に非静的の状態で作成されます。
非静的は、動的とも呼ばれ、これは Dynamic(ダイナミック)という言葉を使うことがあります。

 いつも書いているクラスや変数は、非静的(動的)の状態です。

 もう1つの、静的な状態は、明示的に static というキーワードになっている単語を使うことで、作成することができます。
明示的というのは、プログラム内に処理を書く、ということを意味する言葉です。
そのため、static キーワードをプログラム内で使うと静的な状態を作ることが出来ます。 
(逆に言うと、static キーワードをプログラム内で使わない限りは、静的な状態は作れない、とも言い換えることが出来ます。)


静的クラス


 static キーワードは、クラス、変数、メソッドのいずれかの前に書くことが出来ます。

 下記は、静的クラス(スタティック・クラス)を作った例です。

public static class StaticClass { // 静的クラス

    public static int staticValue = 10; // 静的変数

    public static void StaticMethod() { // 静的メソッド
        Console.WriteLine("これは静的メソッドです。");
    }
}

 静的クラスを作成した場合、メンバ(変数やメソッド)はすべて static にしなければなりません。
そのため、静的クラス内で宣言した変数やメソッドの前に static キーワードを忘れるとエラーが出ます。
 
 静的クラスはインスタンス化することが出来ません。
代わりに、プログラムが実行されると自動でインスタンスが作成されます。
Unity であればゲーム実行ボタンを押した後に作成されます。
そして、プログラム実行中はインスタンスは常に1つで新たにインスタンスを作成することはできません。

 静的クラスにはこういった特徴があります。

 では続けて、静的な変数について説明します。


静的変数


 静的な変数は、静的クラス、あるいは普段使っている非静的クラスのどちらでも作ることが出来ます。

 下記は、非静的クラスに宣言した場合の例です。

public class DynamicClass {  // 非静的クラス
    public static int staticValue = 20;  // 静的変数
}

 この例のように、静的ではないクラスは new キーワードを使うことで、インスタンスして使うことが出来るようになります。
Unity の場合であれば、設計図用に C# スクリプトのファイルを作成し、その中でクラスを書いて、アタッチすることで利用できるようになります。

 このとき、インスタンスする数に制限はありません。
いくつでも new できますし、Unity であれば、スクリプトのファイルは複数の異なるゲームオブジェクトにもアタッチできます。

 静的ではないクラスに書いた通常の変数(静的ではない変数)は、それぞれのインスタンスにつき、それぞれが別の情報として管理されます。
例えば、

public class Enemy {  // 非静的クラス
    public int life = 20;  // 非静的変数
}

 このようなクラスを作って、4つのゲームオブジェクトにアタッチしている場合、
それぞれのゲームオブジェクトにアタッチされている Enemy は異なるインスタンスになるため、
life 変数も、それぞれが異なる値を管理します。Enemy 1 の life は20でも、Enemy 2 の life は10 のように表現が出来ます。

 プログラムの仕様の1つとして、クラスはたくさん作られる前提で処理が動くようになっています。
そのため、クラス内にある変数やメソッドにアクセスするには、そのクラスのインスタンスにアクセスをしないと使えませんね。
つまり、同名のクラスがたくさん存在する可能性があるので、Unity であれば、
「どのゲームオブジェクトにアタッチされているクラス・コンポーネント」という風に特定をしてあげないと、
プログラムは命令を出すことが出来ません。

 そのため、各クラス内の変数やメソッドを使う場合には、下記のようにクラスを特定する作業が必要になります。

Enemy enemy = GetComponent<Enemy>();
enemy.life = 5;

 あるいは、SerializeField属性 などを使って、事前にインスペクターから、どのゲームオブジェクトにアタッチされているクラスかを指定しておきます。

[SerializeField] Enemy enemy;

enemy.life = 5;

 このように、非静的クラス(通常のクラス)は、同名のクラスがたくさん存在する前提でプログラムが動いているので、
プログラムに対して、「どの Enemy クラスであるか」まで特定してあげることで、複数ある同名のクラスから1つを選択してアクセスが出来ます。



 今回の静的変数は、異なるインスタンス間であっても、共通の1つの情報として扱われるという特徴を持ちます。
 先程の Enemy クラスのlife 変数を静的な変数にしてみましょう。

public class Enemy {  // 非静的クラス
    public static int life = 20;  // ← 静的変数に変更
}

 このクラスを同じように4つのゲームオブジェクトにアタッチしたとき、
それぞれが異なるインスタンスの Enemy クラスとして生成されますが、static である life 変数だけは、すべて共通化されて、
1つの情報として管理されるように変わります。つまり、Enemy 1 の life が 15 なら、他の3つの Enemy の life も 15 になってしまう、ということです。

 これはプログラム的な説明に置き換えると、静的変数とは、クラスのインスタンスに依存しない(個別の情報にならない)変数であり、
クラス全体(今回なら Enemy クラス全体)で共有された1つの情報になり、インスタンスを作成せずにアクセスできる変数です。

 よって、クラス自体は複数あっても、その中にある変数は1つの固有情報となりますので、
「どのゲームオブジェクトにアタッチされているクラス」という風に特定しなくても使うことが出来ます
 「クラス名.静的変数名」と書けば、GetComponent や SerializeField などでクラスを特定しなくても使えます。

Enemy.life = 10;

 このように、static の変数は、扱われ方(共通管理される)と、扱い方(命令の書き方)が、通常の変数とは異なります



 また、静的変数は public であっても、インスペクターには表示されないという特徴も持ちます。
デバッグがしにくいため、Debug.Log メソッドを併用することで、現在の値を確認するようにします。



 下記のようなテストクラスを2つ作成していただき、通常の変数と、静的な変数の違いを確認してみてください。


Enemy.cs(複数のゲームオブジェクトにアタッチする)
public class Enemy : MonoBehaviour {  // 非静的クラス
    public static int life = 10;  // ← 静的変数

    void Update() {
        if(life <= 0) {
            Destroy(gameObject);
        }
    }
}




StaticValueTest.cs (Enemy 以外のゲームオブジェクトにアタッチ(Create Emptyしたものでも大丈夫です))
public class StaticValueTest : MonoBehaviour{

    [SerializeField] private int testValue;

    void Start () {
        Enemy.life = testValue;
        Debug.Log("静的変数の値 Enemy の life :" + Enemy.life);
    }
}

 インスペクターで、testValue の値を変えてみましょう。
複数の Enemy の値が共通で変化します。

 また、testValue を0 にしてみると、すべての Enemy のアタッチされているゲームオブジェクトが破壊されますので
静的変数が共通で管理されていることがゲーム画面内でも分かります。

 これはゲーム制作においてはデメリットになるケースが多いため、こういった、敵ごとに同名の別の値を管理する際には適していません。
代わりに、シングルトンクラスを作る際には、便利な機能になります。


テスト方法例


 作成したスクリプトを利用したテスト方法の実例です。

 まず、2Dでも3Dでもよいので、Enemy クラスをアタッチするためのゲームオブジェクトを作成し、Enemy クラスをアタッチします。
削除されることを確認したいので、Create Empty 以外で作成すると良いでしょう。

 次に、このオブジェクトを Ctrl + D(Command + D)で複製します。4〜5こ位にします。

インスペクター画像




 これらは重なった状態で複製されるため、それぞれが見えるように位置をずらす必要があります。
1つずつ移動させてもよいですが、インスペクターの Position では関数が用意されており、それを利用することで位置を移動できます。

 移動させたい軸に L(min, max) と書きます。例えば、ゲームオブジェクトが5つあり、L(0, 4) と書くと、1メートル間隔で離れて配置されます。
ただし、少しずらした方が見えやすい場合には、L(0,5) のように最大値を大きくすることで間隔を空けることが出来ます。

インスペクター画像



<テスト動画 (数のオブジェクトを等間隔で並べる>
動画ファイルへのリンク


 数字を入れるたびに再配置されるので、よい位置になるまで調整するとよいでしょう。

 また # とだけ入力しても等間隔に配置出来ます。こちらは index number を元にして配置しています。


インスペクター画像



 こういった便利な機能などは解説されている動画やサイトがありますので、覚えておくと効率化の手助けになります。


参考動画(YouTube)
Unity Japan
配置を超加速する11のテクニック




 Enemy の静的変数を確認するための StaticValueTest クラスを、新しく作ったゲームオブジェクトにアタッチします。
こちらは Create Empty で作成しても問題ありません。


インスペクター画像



<テスト動画◆\電変数が共通管理されている確認テスト>
動画ファイルへのリンク


 StaticValue 変数を 0 に設定すると、Enemy の Life 変数が 0 になり、
この情報が全 Enemy で共通して利用されているため、すべての Enemy ゲームオブジェクトが破壊されます。

 これにより、静的変数の状態を確認することが出来ます。


Console



プロパティの作成


 static のプロパティも作れます。

class MyClass {

    private static int _staticValue = 10; // 静的変数は private に

    // 静的プロパティを使って、private の静的変数を外部に提供
    public static int StaticValue {
        get { return _staticValue; }
        set { _staticValue = value; }
    }
}

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます