前回のUnity Gems記事に続いて、Unityメモリ管理「Static変数」について翻訳を紹介する:
-------
http://unitygems.com/memorymanagement/October 21, 2012
Static変数
多くの初心者は次の簡単な間違いをしている:
public static int health; void Start(){ health=100; }
別のスクリプトでは次のことを見つけるかもしれない。
void OnCollisionEnter(Collision other){ if (other.gameObject.tag == “Enemy”){ EnemyScript.health-=10; if(EnemyScript.health <=0)Destroy(other); } }
ゲームを一つの敵で初めて殺すことに成功する。しかし次に敵を追加してみて、なぜ同時に殺されるのだろうと悩むことになる。
理由は簡単で、enemyクラス(staticでない)のインスタンスがたくさんあるがhealthクラスが全てのインスタンスが1つしかないためだ。ひとつ殺すことで全部殺されてしまう!
実際、クラスで宣言されたStatic変数はオブジェクトに属しておらず、クラス自身に属する。
クラス名でなく、インスタンス名を使ってアクセスするのもこの理由のためだ。enemyのhealthについて機能しなかったのは、各enemyが各々のhealth変数を持つ必要があるためだ。
実際、クラスで宣言されたStatic変数はオブジェクトに属しておらず、クラス自身に属する。
クラス名でなく、インスタンス名を使ってアクセスするのもこの理由のためだ。enemyのhealthについて機能しなかったのは、各enemyが各々のhealth変数を持つ必要があるためだ。
Static変数はStaticクラスと同じように、それを定義しているクラスが始めてアクセスされたときにインスタンス化される。つまり、ゲームでそのクラスのインスタンスがないにも関わらず、もしアクセスしようとすれば、そのクラスは存在することがある。
例えばenemyのカウンタ(counter)を作るとしてゲームでのenemyの数をトラッキングしていく必要があるとする。
static var counter; public void CreateEnemy(){ GameObject obj=Instantiate(enemyPrefab, new Vector3(0,0,0).Quaternion.identity); if(obj)counter++; } public void DestroyEnemy(){ Destroy(gameObject); counter--; }
このスクリプトは全ての敵にアタッチする各々別のスクリプトであっても全てが同じカウンタ変数を共有する。 この関数をゲームで使用することで、enemyのカウントをトラッキングすることが出来る。インスタンスがオブジェクト作成に失敗した場合を考慮して(例えばヒープのフラグメンテーションによって)参照の偏すが使用されていることをに留意する必要がある。失敗した場合Instantiateはhealthへの参照を返す。もしこのチェックをせずにカウントを増やしてしまうと、何らかの理由でインスタンス化に失敗した場合、カウンタが誤った値になる。もしカウンタをレベルの終わりに使用して新しいレベルロードすると:
if(counter<=0)Application.LoadLevel(nextLevel);このチェックがなければ、失敗した場合、全ての敵を殺した後カウントが1となってゲームにバグが生じることになる。
ところでプレイヤーについてStatic変数のhealthを使用することは出来るのだろうか。答えとしては、プレイヤーにStatic変数を使用することが出来る。実際にStatic変数にアクセスするのはインスタンスメンバをアクセスするよりも効率的だ。
インスタンスメンバをコールするとき、コンパイラは小さな関数をコールしてオブジェクトの存在チェックを行う必要がある。存在しないデータを修正できるべきではないので、これは当然といえる。
-------
Unityメモリ管理の基礎を積み重ねていこうぜ!
-------
Unityメモリ管理の基礎を積み重ねていこうぜ!
0 件のコメント:
コメントを投稿