コールチンで通信完了まで待機
概要
- 必要なデータが受け取れてない状態でゲーム画面に移行してしまうとゲームが正常に動作しない。
- DBとの接続時、必要なデータが揃ってステートを遷移したい。
流れ
- ステートを管理するGameManagerを生成する
- DBとの通信が完了次第次のステートに移動する。
コード
コールチン内でコールチンを呼ぶ。
- コールチンの親が子コールチンの総括をしていると考えています。
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; } }
各々のコールチン
- isTitleClickがfalseになるまで次のステートに遷移することを食い止めます
TITLE
IEnumerator StartTitle() { titleObj.GetComponent<Text>().text = "TITLE"; while(isTitleClick) { yield return null; } isTitleClick = true; }
LOAD
- mysqlの通信が完了するまで次のステートに遷移することを食い止めます
IEnumerator StartHTTP() { mysql = GetComponent<CheckMySQL>(); mysql.StartHTTP(); while(!mysql.GetIsHTTPCompoleted()) { titleObj.GetComponent<Text>().text = "LOAD"; yield return null; } }
PLAY
- 無限ループになってしまっていますが、一定間隔でモンスターを生成しています。
- ゲームの大きな機能(例えば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ファイルでエネミーのパラメーターを変更してみる
こう来ると次は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の場合、デシリアライズが出来ない仕様だったので下記のサイトを参考に開発しました。
csvファイルをmysqlに移行
Unityからcsvファイルを読み込んでEnemyのステータスを管理しようと思っていたのですが、せっかくなのでMYSQLに移行してみる zvn-x.hatenablog.com
概要
- 全国ランキングを作ったとき、csvファイルじゃだめだよね.
- ユーザー情報なども管理したい.
- モンスターのHPを間違えて0にしてしまった.
こんな時に対応できるようにcsvファイルでの管理をDB(mysql)の管理へ移行します.
流れ
- 予めtableを作成しておくことは必須
- tableができ次第下記のクエリを実行
- データを更新を行う際は一度初期化して再度挿入し直すのが安定?
クエリ
LOAD DATA INFILE "/tmp/test.csv" INTO TABLE monsterData FIELDS TERMINATED BY "," LINES TERMINATED BY "\n" IGNORE 1 LINES;
LOAD DATA INFILE ""
ファイルのインポート
INTO TABLE monsterData
LOADしたデータをmonsterDataテーブルに挿入する。
FIELDS TERMINATED BY ","
区切り文字を指定して分け分け
LINES TERMINATED BY "\n"
改行コードで行を終了
IGNORE 1 LINES;
一行目はフィールド値なので無視するよ
CSVファイルでエネミーのパラメーターを変更してみる
Enemyのステータスはスプレッドシートにまとめたい。
- モンスターを大量に作っていると、どのモンスターがどのくらいのステータスだったかとかわからなくなってしまう.
- チーム開発ではゲームバランスを整える人とプログラムを書く人が別々のこともありそうなのでデータをエクセルで管理できるようにしたい.
データ
キャラクターの名前とHP,SPEEDのみが格納されています。
コード
利用するクラス
ReadCSV.cs
csvファイルを読み込み、Dictionaryに値を格納していきます。また、そのデータを返す関数を一つ用意
Monster.cs
モンスターの挙動が代わることをチェックするクラス。
1. monsterの移動スピードの変更 1. HP,NAME,SPEEDをテクスチャとして表示
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; } }
コードの流れ
- MonsterManagerが読み取りたいcsvファイルを指定
- CSVファイルを読み込んでDicに格納
- MonsterManagerが取得したいMonsterDateを指定
- MonsterDateを元にMonsterを生成。
この記事は下記のサイトを参考にしています.
コールチンでゲームステートを管理してみる
ステートを管理にコールチンが使えた
ミニゲームを作りたいと考えたときに、 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視点)
用意するもの
- Player(中心点にしたいObject)
- CenterRotation(回転を補助するObject)
- MainCamera(カメラ)
やること
- PlayerとCenterRotationのポジションを同期(この時子要素に入れない)
- 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)のスクリプトをアタッチ! コレで終わり!
ツリー
一番簡単なレイザーサンプル
各引数についてはドキュメントを読めばわかる。 DrawRay()とRaycast()の引数は違うので気をつけて
hitした情報を取得してみる
if (Physics.Raycast (transform.position, fwd,out hit)) { print (hit.distance); }