Playerと複数生成されるSpawnerの位置を取得

UnityでFlappy Birdを作ってみたが、すぐにPlayer(Flappy Bird)を自動制御したくなったので、まずはPlayerとSpawner(土管)の位置を取得してみた。


Flappy Bird Made with Unity

Spawnerの設定

Spawnerは土管で、1秒ごとにY軸をランダムにずらして生成し、Playerに向かわせている。 Spawnerが生成された際にタグを付けることで、Player側でSpawnerの位置を取得することができる。

 public GameObject wallPrefab;  // Spawnerとして土管のprefabを設定する
    public float interval;  // 1秒ごとに生成する
    private GameObject spawner;  // 生成されたSpawnerを格納する
    public string tag;  // Spawnerにタグを付ける

    // Use this for initialization
    IEnumerator Start () {
        while (true) {
            // 画面外の座標(12, 2)をベースにY軸を0.0~4.0だけランダムにずらしてSpawnerを生成するよう設定
            transform.position = new Vector2(transform.position.x, Random.Range(0.0f, 4.0f));
            // Spawnerを生成
            spawner = Instantiate(wallPrefab, transform.position, transform.rotation);
            // 生成したSpawnerにタグ付け!
            spawner.tag = "Wall";

            yield return new WaitForSeconds(interval);
        }
    }

なお、Spawnerに指定した土管prefabには1秒ごとに5ずつX軸マイナス方法へ向かうように設定してある。

Playerの設定

Playerはフレームごとに状態を観測することができる。 このスクリプトがPlayerのインスタンスになるので、Playerの位置は簡単に取得できるのだが、 Spawnerの位置は、上記のようにタグ付けをすることで、Playerからも取得することができるようになる。

    public float jumpPower;  // Playerは強さ5でジャンプ
    private int num_wall = 2;  // SpawnerはPlayerに最も近い2つだけ位置を取得

    // Update is called once per frame
    void Update () {
        // Initialize state
        // 観測する位置は以下の5つ
        // [player_pos_y, wall1_pos_x, wall1_pos_y, wall2_pos_x, wall2_pos_y]
        List<float> state = new List<float>();  // 位置を格納するリスト

        // Set player position x
        var pos_player = this.transform.position;  // Playerの位置
        state.Add(pos_player.y);  // リストにPlayerのY座標を追加

        // Set wall position x and y
        GameObject[] walls = GameObject.FindGameObjectsWithTag("Wall");  // タグから全Spawnerを取得
        foreach (var wall in walls) {  // 全Spawnerについて生成された順に
            var pos_wall = wall.gameObject.transform.position;  // Spawnerの位置を取得
            // SpawnerがPlayerより前にいて、かつSpawnerの数がリストに2つ未満の場合
            // If a wall is behind the player & the number of wall in state is not max
            if ((pos_player.x <= pos_wall.x + 1.0f) && (state.Count < 1+2*num_wall)) {  
                state.Add(pos_wall.x);  // SpanerのX座標を格納
                state.Add(pos_wall.y);  // SpanerのY座標を格納
            }
        }

        // debug
        // 取得したPlayerとSpanerの位置を出力
        string text = "";
        foreach (var s in state) {
            text = text + s.ToString() + " ";
        }
        print(text);

    }

位置の取得結果

Playerのスクリプトで設定したコンソールへの出力は以下のようになる。 数値の内容は[player_pos_y, wall1_pos_x, wall1_pos_y, wall2_pos_x, wall2_pos_y]。 SpawnerがX座標マイナス方向にずれていくのが観測できる。 PlayerのX座標は変わらないので、Y座標だけ取得している。

f:id:Shoto:20171103161032p:plain

ソースコード

SpawnerとPlayerの全ソースコードを以下に示しておく。

  • Spawner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Spawner : MonoBehaviour {

    public GameObject wallPrefab;
    public float interval;
    private GameObject spawner;
    public string tag;

    // Use this for initialization
    IEnumerator Start () {
        while (true) {
            transform.position = new Vector2(transform.position.x, Random.Range(0.0f, 4.0f));
            spawner = Instantiate(wallPrefab, transform.position, transform.rotation);
            spawner.tag = "Wall";

            yield return new WaitForSeconds(interval);
        }
    }

    // Update is called once per frame
    void Update () {

    }
}
  • Player.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour {

    public float jumpPower;

    private int num_wall = 2;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        // Initialize state
        // [player_pos_y, wall1_pos_x, wall1_pos_y, wall2_pos_x, wall2_pos_y]
        List<float> state = new List<float>();

        // Set player position x
        var pos_player = this.transform.position;
        state.Add(pos_player.y);

        // Set wall position x and y
        GameObject[] walls = GameObject.FindGameObjectsWithTag("Wall");
        foreach (var wall in walls) {
            var pos_wall = wall.gameObject.transform.position;
            // If a wall is behind the player & the number of wall in state is not max
            if ((pos_player.x <= pos_wall.x + 1.0f) && (state.Count < 1+2*num_wall)) {  
                state.Add(pos_wall.x);
                state.Add(pos_wall.y);
            }
        }

        // debug
        string text = "";
        foreach (var s in state) {
            text = text + s.ToString() + " ";
        }
        print(text);

        // Manual operation
        if (Input.GetButtonDown("Jump")) {
            GetComponent<Rigidbody2D>().velocity = new Vector2(0, jumpPower);
        }
    }

    /*
   void OnCollisionEnter2D (Collision2D other) {
       // Application.LoadLevel(Application.loadedLevel);  //old function
        UnityEngine.SceneManagement.SceneManager.LoadScene(UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex);    
   }
   */

    void OnCollisionEnter2D (Collision2D other) {
        Invoke("Restart", 1.0f);     
    }

    void Restart () {
        // Application.LoadLevel(Application.loadedLevel);  //old function
        UnityEngine.SceneManagement.SceneManager.LoadScene(UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex);   
    }

}

参考文献