Star☆Unityメモ

Unityのちょっとしたことをメモって後で見返せれたらいいなサイト

コールチンで通信完了まで待機

f:id:zvn_X:20170109232813g:plain

概要

  1. 必要なデータが受け取れてない状態でゲーム画面に移行してしまうとゲームが正常に動作しない。
  2. DBとの接続時、必要なデータが揃ってステートを遷移したい。

流れ

  1. ステートを管理するGameManagerを生成する
  2. DBとの通信が完了次第次のステートに移動する。

コード

コールチン内でコールチンを呼ぶ。

  1. コールチンの親が子コールチンの総括をしていると考えています。
        void Awake () {
        StartCoroutine("GameState");
    }


    IEnumerator GameState(){
        while (true) {
            //TITLE
            yield return StartCoroutine("StartTitle");
            //LOAD
            yield return StartCoroutine("StartHTTP");
            //ゲームMAIN
            yield return StartCoroutine("StartPlay");

            yield return null;
        }
    }

各々のコールチン

  1. isTitleClickがfalseになるまで次のステートに遷移することを食い止めます

TITLE

   IEnumerator StartTitle() {
                titleObj.GetComponent<Text>().text = "TITLE";      
                while(isTitleClick) { 
            yield return null;
        }
        isTitleClick = true;
    }

LOAD

  1. mysqlの通信が完了するまで次のステートに遷移することを食い止めます
   IEnumerator StartHTTP() {
        mysql = GetComponent<CheckMySQL>();
        mysql.StartHTTP();
        while(!mysql.GetIsHTTPCompoleted()) {
            titleObj.GetComponent<Text>().text = "LOAD";
            yield return null;
        }
    }

PLAY

  1. 無限ループになってしまっていますが、一定間隔でモンスターを生成しています。
  2. ゲームの大きな機能(例えばEnemyManagerをActiveにするなどを入れると良いかもしれません.
   IEnumerator StartPlay(){
        titleObj.GetComponent<Text>().text = "PLAY";
        while(true){
            timeElapsed += Time.deltaTime;
            if (timeElapsed >= timeOut) {
                monsterBase.CreateEnemy(mysql);
                timeElapsed = 0.0f;
            }
            yield return null;
        }
    }

MYSQLとUNITY間のやり取り

概要

以前作ったCSVファイルでエネミーのパラメーターを変更してみる

zvn-x.hatenablog.com

次にCSVファイルをMYSQLにぶち込む

zvn-x.hatenablog.com

こう来ると次はUNITYとMYSQLを接続してみたい. 以前作った「CSVファイルでエネミーのパラメーターを変更してみる」のCSV読み込み部分をDBに変えるだけだ。

コード

ReadMonsterData.cs

const string LOCALDOMAIN = "";
    string m_url = "http://" + LOCALDOMAIN + "/unity/monsterData_get.php";
    Dictionary<string, Dictionary<string, string>> monsterSummarizeData = new Dictionary<string, Dictionary<string, string>>();

    void Awake(){
        StartCoroutine(GetUser());
    }

    IEnumerator GetUser() {
        WWW result = new WWW(m_url);
        yield return result;


        if (result.error == null) {
            Debug.Log(result.text);

            List<MonsterStates> datas = JsonHelper.ListFromJson<MonsterStates>(result.text);
            foreach(var data in datas){
                Dictionary<string, string> monsterStates = new Dictionary<string, string>();
                monsterStates.Add("NAME", data.NAME);
                monsterStates.Add("HP", data.HP);
                monsterStates.Add("SPEED", data.SPEED);
                monsterSummarizeData.Add(data.NAME,monsterStates);
            }
            var monsterParam = monsterSummarizeData["ELEPHANT"];
            Debug.Log(monsterParam["HP"]);
            Debug.Log(monsterParam["NAME"]);
        }
    }

    public Dictionary<string, string> GetMonsterDate(string name) {
        var MonsterDic = monsterSummarizeData[name];
        return MonsterDic;
    }
}

MonsterBase.cs

   public GameObject[] enemy;
    ReadCSV csv;
    ReadMonsterData mysql;
    float timeOut;
    float timeElapsed;


    void Awake() {
        timeOut = 5.0f;
        mysql = GetComponent<ReadMonsterData>();
    }


    void Update() {
        timeElapsed += Time.deltaTime;

        if (timeElapsed >= timeOut) {
            Debug.Log("huga");
            GameObject monster = Instantiate(enemy[0], new Vector3(0.0f, 0.0f, 0.0f), new Quaternion(0.0f, 0.0f, 0.0f, 0.0f)) as GameObject;
            monster.GetComponent<Monster>().SetStates(mysql.GetMonsterDate("ELEPHANT"));

            monster = Instantiate(enemy[1], new Vector3(0.0f, 0.0f, 0.0f), new Quaternion(0.0f, 0.0f, 0.0f, 0.0f)) as GameObject;
            monster.GetComponent<Monster>().SetStates(mysql.GetMonsterDate("RABBIT"));

            timeElapsed = 0.0f;
        }
    }

参照サイト

jsonUtilityではJsonのルートがArrayの場合、デシリアライズが出来ない仕様だったので下記のサイトを参考に開発しました。

blog.cluster.mu

csvファイルをmysqlに移行

Unityからcsvファイルを読み込んでEnemyのステータスを管理しようと思っていたのですが、せっかくなのでMYSQLに移行してみる zvn-x.hatenablog.com

概要

  1. 全国ランキングを作ったとき、csvファイルじゃだめだよね.
  2. ユーザー情報なども管理したい.
  3. モンスターのHPを間違えて0にしてしまった.

こんな時に対応できるようにcsvファイルでの管理をDB(mysql)の管理へ移行します.

流れ

  1. 予めtableを作成しておくことは必須
  2. tableができ次第下記のクエリを実行
  3. データを更新を行う際は一度初期化して再度挿入し直すのが安定?

クエリ

LOAD DATA INFILE "/tmp/test.csv"
INTO TABLE monsterData
FIELDS TERMINATED BY ","
LINES TERMINATED BY "\n" 
IGNORE 1 LINES;
  1. LOAD DATA INFILE ""

    ファイルのインポート

  2. INTO TABLE monsterData

    LOADしたデータをmonsterDataテーブルに挿入する。

  3. FIELDS TERMINATED BY ","

    区切り文字を指定して分け分け

  4. LINES TERMINATED BY "\n"

    改行コードで行を終了

  5. IGNORE 1 LINES;

    一行目はフィールド値なので無視するよ

CSVファイルでエネミーのパラメーターを変更してみる

f:id:zvn_X:20170109031112p:plain

Enemyのステータスはスプレッドシートにまとめたい。

  1. モンスターを大量に作っていると、どのモンスターがどのくらいのステータスだったかとかわからなくなってしまう.
  2. チーム開発ではゲームバランスを整える人とプログラムを書く人が別々のこともありそうなのでデータをエクセルで管理できるようにしたい.

データ

f:id:zvn_X:20170108232547p:plain

キャラクターの名前とHP,SPEEDのみが格納されています。

コード

利用するクラス

  1. ReadCSV.cs

    csvファイルを読み込み、Dictionaryに値を格納していきます。また、そのデータを返す関数を一つ用意

  2. Monster.cs

    モンスターの挙動が代わることをチェックするクラス。

     1. monsterの移動スピードの変更
     1. HP,NAME,SPEEDをテクスチャとして表示
    
  3. MonsterManager

    Monsterを管理するクラス.

    1. モンスターの生成やcsvから生成
    1. monsterのパラメーターをmonsterにセットします
    

ReadCSV.cs

   Dictionary<string, Dictionary<string, string>> NameDic = new Dictionary<string, Dictionary<string, string>>();


    public ReadCSV(string test) {
        int csvNumberLines = 0;
        TextAsset csvFile = Resources.Load("CSV/"+test) as TextAsset;
        StringReader reader = new StringReader(csvFile.text);
        List<string[]> lisString = new List<string[]>();
        while (reader.Peek() > -1) {
            string line = reader.ReadLine();
            lisString.Add(line.Split(','));

            SetDictionary(csvNumberLines,lisString);
            csvNumberLines++;
        }

    }


    void SetDictionary(int csvNumberLines,List<string[]> lisString) {
        Dictionary<string, string> dic = new Dictionary<string, string>();
        var NAME = lisString[csvNumberLines][0];
        var HP = lisString[csvNumberLines][1];
        var SPEED = lisString[csvNumberLines][2];
        dic.Add(lisString[0][0], NAME);
        dic.Add(lisString[0][1], HP);
        dic.Add(lisString[0][2], SPEED);
        NameDic.Add(NAME, dic); 
    }


    //csvをDictionaryに変換したMonsterDataを返します
    public Dictionary<string,string> GetMonsterData(string monsterName) {
        var MonsterDic = NameDic[monsterName];
        return MonsterDic;
    }

Monster.cs

   float maxSpeed = 0.0f;
    float speed = 0.0f;

    void Update () {
        transform.Translate(new Vector3(speed/10, 0.0f, 0.0f));
    }

    public void SetStates(Dictionary<string,string> states){
        Debug.Log(states["HP"]);
        Debug.Log(states["SPEED"]);
        speed = float.Parse(states["SPEED"]);
        this.GetComponent<TextMesh>().text = states["NAME"]+"\nSPEED:"+states["SPEED"]+"\nHP:"+states["HP"];
    }

MonsterManager

public GameObject[] enemy;
    ReadCSV csv;
    float timeOut;
    float timeElapsed;


    void Awake() {
        timeOut = 5.0f;
        csv = new ReadCSV("test");
    }


    void Update() {
        timeElapsed += Time.deltaTime;

        if (timeElapsed >= timeOut) {
            Debug.Log("huga");
            GameObject monster = Instantiate(enemy[0], new Vector3(0.0f, 0.0f, 0.0f), new Quaternion(0.0f, 0.0f, 0.0f, 0.0f)) as GameObject;
            monster.GetComponent<Monster>().SetStates(csv.GetMonsterData("ELEPHANT"));

            monster = Instantiate(enemy[1], new Vector3(0.0f, 0.0f, 0.0f), new Quaternion(0.0f, 0.0f, 0.0f, 0.0f)) as GameObject;
            monster.GetComponent<Monster>().SetStates(csv.GetMonsterData("RABBIT"));

            timeElapsed = 0.0f;
        }
    }

コードの流れ

  1. MonsterManagerが読み取りたいcsvファイルを指定
  2. CSVファイルを読み込んでDicに格納
  3. MonsterManagerが取得したいMonsterDateを指定
  4. MonsterDateを元にMonsterを生成。

この記事は下記のサイトを参考にしています.

qiita.com

コールチンでゲームステートを管理してみる

ステートを管理にコールチンが使えた

ミニゲームを作りたいと考えたときに、 Title→main→GameOver→Title みたいなステート遷移を行いたいときに意外とコールチンが使えた. この方法は下記のTanksの中でも利用されている(っと思う) unity3d.com

コード

void Start() {
    playerManger = playerManager.GetComponent<PlayerManager>();
    StartCoroutine("GameStateChange");
}


//Gameのマスター管理
IEnumerator GameStateChange() {
    yield return StartCoroutine(RoundStart());
    yield return StartCoroutine(RoundPlay());
    yield return StartCoroutine(RoundEnd());
    yield return StartCoroutine(GameStateChange());
}


IEnumerator RoundStart() {
    // テキストの変更
    playerManger.CreatePlayer();
    // 2秒後にStart
    yield return new WaitForSeconds(2.0f);
}


IEnumerator RoundPlay() {
    while (!OnPlayer()) {
        Debug.Log("プレイヤーが存在しています");
        yield return null;
    }
}


IEnumerator RoundEnd() {
        Debug.Log("ゲームオーバー時に行いたい処理、2病後にRoundStart開始");
    yield return new WaitForSeconds(2.0f);
}

一点を中心に回転(TPS視点)

用意するもの

  1. Player(中心点にしたいObject)
  2. CenterRotation(回転を補助するObject)
  3. MainCamera(カメラ)

やること

  1. PlayerとCenterRotationのポジションを同期(この時子要素に入れない)
  2. RotationObjの子要素にCameraをセット.

 実践

(1)PlayerとCenterRotationのポジションを同期するするスクリプトを書いてあげる

   public GameObject player;
    private Vector3 offset;
    // Use this for initialization
    void Start () {
        offset = transform.position - player.transform.position;
    }
    
    // Update is called once per frame
    void Update () {
        transform.position = player.transform.position + offset;
    }

(2)CenterRotationを回転させるスクリプト

void Update () {
    if (Input.GetKey(KeyCode.Q)) {
        this.transform.Rotate(new Vector3(0, 1, 0), 90 * Time.deltaTime);
    }
    if (Input.GetKey(KeyCode.E)) {
        this.transform.Rotate(new Vector3(0, 1, 0), -90 * Time.deltaTime);
    }
}

(3)RotationObjに(1)と(2)のスクリプトをアタッチ! コレで終わり!

ツリー

f:id:zvn_X:20170101140314p:plain

一番簡単なレイザーサンプル

C#

各引数についてはドキュメントを読めばわかる。 DrawRay()とRaycast()の引数は違うので気をつけて

hitした情報を取得してみる

if (Physics.Raycast (transform.position, fwd,out hit)) {
    print (hit.distance);
}