2014年12月19日金曜日

Collision

オブジェクト間の当たり判定とその際の処理の管理

旧1
// 各オブジェクトで処理
foreach (Transform child in rootObject.transform){
    Collider collider = child.GetComponent<Collider> ();
    if (collider.gameObject.tag == "Enemy"){
        HitCollider (collider);
    }
}

全てのオブジェクトをrootObjectの子として管理。
全てのオブジェクトは毎フレーム全オブジェクトを相手をチェックする。その際Tagを判定し、関係あるTagならコリジョンチェック。毎フレーム全オブジェクトが全オブジェクトをチェックするのでオブジェクト数が増えると大変なことになりそう。10発の弾丸があったら10^2=100回のチェックが毎フレーム起こる。


旧2
// ObjectManagerが処理
// 以下の空オブジェクトを子に持つ
// 各オブジェクトはタイプに応じて各空オブジェクトを親に持つ
public GameObject player;
public GameObject enemy;
public GameObject playerbullet;
public GameObject enemybullet;
public GameObject item;
public GameObject trigger;
public GameObject map;

//    ...

foreach (Transform mchild in player.transform){
    Collider mcollider = mchild.GetComponent<Collider> ();
    foreach (Transform echild in enemy.transform){
        Collider ecollider = echild.GetComponent<Collider> ();
        HitCollider (mcollider, ecollider);
    }
}

ObjectManagerが各オブジェクトの親オブジェクトを管理。旧1のrootObjectが複数になった形。チェック対象のオブジェクト群のみをチェック。
無関係なオブジェクトはそもそもチェックしないので処理削減。弾丸は敵としか判定が起きないので、弾丸10発と敵が2体なら10*2=20回のチェック。旧1では(10+2)^2=144回のチェック。


最新版

GetComponent ()は重いらしい。
毎フレームGetComponentを呼び出すのはまずそうなので、
1. オブジェクト生成時(Collider生成時)にGetComponent
2. 得られたColliderポインタをObjectManagerがListで保持
3. 旧2の処理をListを辿ることで実現

オブジェクト消滅時にListにnullポインタがごみとして残るへの対処は?

案1 デストラクタを利用
→Unityでは非推奨。
→C#はガベージコレクションがあるためデストラクタの動作タイミングが不定なため?

案2 Destroy時に一緒にリストから削除
→Destroyする側に任せるのは所在が散開してミスの元になりそう

案3 List辿ってnullポインタがあったらその場でListから消せば良くないか
→採用。
→ただし、foreach文中では消せないため、削除用のループを回す必要あり

ガベージコレクションのせいでオブジェクト消去のタイミングが分からない問題は未解決。
Destroy ()したタイミングでList内のポインタはnullになる?

0 件のコメント:

コメントを投稿