My portfolio

Menu▼

  • Top
  • About
  • Portfolio
  • Diary
  • Privacy policy
  • [Unity]Instantiateによるオブジェクトの生成とID番号の付与

    概要

    Unityの勉強としてラストウォーの模写を行っている。

     そのゲームを構成する要素の1つにプレイヤーの人数を増減させる機能がある。 今回はInstantiateでオブジェクトを生成、Destroyで削除することでこれを実装した。

    その際オブジェクトにID番号を付与して区別する必要が生じたので、そのための機能を実装した。

    仕様

     プレイヤーの人数を変化させるパネルや、敵に触れるとプレイヤーの人数が接触した相手に応じて増減する。この時のプレイヤーの人数の増減の仕方は次のようにした。

    オブジェクトの生成-Instantiateの書き方-

     プレイヤーオブジェクトの生成はUnityに備わっているメソッドであるInstantiateを用いた。
    必要なパラメータは、生成したいオブジェクトのひな形、生成する位置、生成したオブジェクトの角度であり、これらを下のように引数として与える。
    なお、戻り値は、GameObject 型である。

    Instantiate(Object, new Vector3( -1.0f, 0.0f, 0.0f), Quaternion.identity);

     今回はプレイヤー自身のコピーを作成したいのでオブジェクトのひな形として”this.gameObject”とした。

    オブジェクトの生成コード if (targetNo > PlayerCnt)//targetNo・・・パネルに接触後のプレイヤーの人数 { for (int i = 0; i < targetNo - PlayerCnt; i++) { float rndX = Random.Range(-3, 3); float rndZ = Random.Range(-4, -2); Vector3 pos = transform.position + new Vector3(rndX, 0, rndZ); Instantiate(this.gameObject, pos, Quaternion.identity);//オブジェクトの生成 } }

    Static変数とid付与

    プレイヤーの生成

     static変数はゲームの起動時にメモリ領域が確保され、その後ゲーム終了まで保持される。 また変数の値は同種のゲームオブジェクト間で共有される。

     今回はこれを利用しStartメソッド内でプレイヤーにID番号を付与した。プレイヤーに付与されたID番号を変数として用意し、これより1だけ大きい番号を新しく生成したプレイヤーに付与する。これによりプレイヤーに重複しない番号(=ID)を付与する。

    ID付与コード void Start() { playerIdNo = lastIdNo+1;//static変数 プレイヤーに付与されたID番号 PlayerCnt++;//static変数 プレイヤーの人数 lastIdNo++;//static変数 最後に付与したID番号 }

    プレイヤーの削除

     プレイヤーの人数を減少させるパネルに触れた際のプレイヤーの削除はUpdateメソッド内で行った。なお、敵に触れたときは別の方法で行っている、方法は後述する。

     プレイヤーの人数をStatic変数で保持しておき、各プレイヤーは(自身のID番号>プレイヤーの人数)となった場合に自オブジェクトを削除するようにした。 これにより、ID番号の高いプレイヤーから順番にオブジェクトを削除できる

    プレイヤー削除用コード //不要なプレイヤーを消す if(PlayerCnt<playerIdNo) { Destroy(gameObject); }

    ID再割り当て

    プレイヤーが敵に接触した際、そのプレイヤーを削除し、プレイヤーの人数を1つ減らすようにした。

     それと同時に最終付与IDがそのプレイヤーに割り当てられたIDから1を引いた値より大きい場合、最終付与IDを更新している。(下) これにより、敵に接触したプレイヤーのうち最もID番号の小さいものから1引いた値を最終付与IDにすることができる。

    最終付与ID更新コード //ここに敵に衝突した場合の処理 if (other.gameObject.tag == "Enermy") { if (playerIdNo == 1) { } else {//敵に衝突したプレイヤーのうち最もId番号が若い物をlastIdNoとする if ((playerIdNo-1) < lastIdNo) { lastIdNo = playerIdNo-1; } Destroy(this.gameObject); } }

     最終付与IDとプレイヤーの人数が異なる場合に、プレイヤーのIDを最終付与ID+1に変更することで敵との接触で空きができたIDを埋めるようにID番号を再割り当て可能になる。 なお、IDの再割り当ては、Updateメソッド内で行った。

    ID再割り当てコード //必要ならId再割り当て if(PlayerCnt!=lastIdNo) { if(playerIdNo>lastIdNo) { playerIdNo = lastIdNo + 1; lastIdNo++; } }

    実行結果

     下の動画のように、パネルや敵に接触した際のプレイヤーの人数の増減は適切に処理ができている。

     一方、プレイヤーの出現位置はランダムで決定しているためプレイヤー同士が重なり見た目上は増減が生じていないように見える部分を改善する必要がある。この部分に関しては実際にプレイし仕様を確認する必要がある。

    ダウンロード

    パッケージ(プレイヤースクリプト)
    プレイヤースクリプト(今回のテーマと関係ない部分もあります) using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { static int PlayerCnt=0;//プレイヤーの数 static int lastIdNo = 0; int playerIdNo;//プレイヤー生成用通し番号 public GameObject MyshotPref; GameObject Gate; const float SPEED=3f; int loop; Rigidbody rb; uint button; enum E_INPUT { Left=0x1, Right=0x2, Shot=0x4 } // Start is called before the first frame update void Start() { playerIdNo = lastIdNo+1; PlayerCnt++; lastIdNo++; loop = 0; rb = GetComponent<Rigidbody>(); Gate=transform.Find("Gate").gameObject; } // Update is called once per frame void Update() { float speed=0; button = input(); if((button & (uint)E_INPUT.Left)!=0) { speed=-SPEED; }else if ((button & (uint)E_INPUT.Right) != 0) { speed=SPEED; } //必要ならId再割り当て if(PlayerCnt!=lastIdNo) { if(playerIdNo>lastIdNo) { playerIdNo = lastIdNo + 1; lastIdNo++; } } //不要なプレイヤーを消す if(PlayerCnt<playerIdNo) { Destroy(gameObject); } rb.velocity=new Vector3(speed,0,0); Debug.Log("ID=" + playerIdNo); } private void FixedUpdate() { loop++; int frec = 10; if(PlayerCnt>20) { frec = 20; } if(loop%frec==0 && (button & (uint)E_INPUT.Shot) != 0) { GameObject shot=Instantiate(MyshotPref,Gate.transform.position,Quaternion.identity); shot.GetComponent<Rigidbody>().velocity = new Vector3(0,0,20); } } uint input() { uint result=0; if (Input.GetKey(KeyCode.LeftArrow)) { result |= (uint)E_INPUT.Left; } else if (Input.GetKey(KeyCode.RightArrow)) { result |= (uint)E_INPUT.Right; } if (Input.GetKey(KeyCode.Z)){ result |= (uint)E_INPUT.Shot; } return result; } private void OnTriggerEnter(Collider other) { if (other.gameObject.tag == "PowerChanger" && playerIdNo==1) { int targetNo = other.GetComponent<PowerPanel>().NextPower(PlayerCnt); if (targetNo >= 100) { targetNo = 100; } if (targetNo > PlayerCnt) { for (int i = 0; i < targetNo - PlayerCnt; i++) { float rndX = Random.Range(-3, 3); float rndZ = Random.Range(-4, -2); Vector3 pos = transform.position + new Vector3(rndX, 0, rndZ); Instantiate(this.gameObject, pos, Quaternion.identity); } } else { PlayerCnt=targetNo; if (PlayerCnt <= 0) { PlayerCnt = 1; } lastIdNo=PlayerCnt; } } //ここに敵に衝突した場合の処理 if (other.gameObject.tag == "Enermy") { if (playerIdNo == 1) { } else {//敵に衝突したプレイヤーのうち最もId番号が若い物をlastIdNoとする if ((playerIdNo-1) < lastIdNo) { lastIdNo = playerIdNo-1; } Destroy(this.gameObject); } } //---------------------------- } }