前提
Unityでノベルゲームを制作しています。テキストファイルから文字を読み込み、本文かコマンドかを判別するプログラムを作成しました。
本文を表示する場合はクリック待ち、コマンド実行の場合は入力なしで自動で実行されるようにしたいのですが、
関数を実行するとエディターがフリーズしてしまいます。
エラー原因と思われる関数を記述してます。
追記1:フリーズは解決しました。次はテキスト行数参照用の変数iが変な値を表示してしまいます。
動きとしては最初にChangeBackGroundを呼び出して壁紙を表示、そのあとInstantCharactersでキャラを呼び出し、本文が表示されるのですが、ゲーム再生してクリックするとiが3から1400など突飛もない値になってしまいます。
実現したいこと
OnClickToNextString関数で最初のif文でマウス入力待ちをすればフリーズしなくなるのですが、コマンドは自動で実行されるようにしたいです
発生している問題・エラーメッセージ
該当のソースコード
C#
1 2 3 IEnumerator OnClickToNextString() 4 { 5 6 if(/*Input.GetMouseButtonDown(0) &&*/ isMove && isNext) { 7 //isNext = false; 8 tmp = scenarioList[i]; 9 if(tmp[0] == '#') { //コマンドだったら 10 tmp = tmp.Remove(0,1); 11 commandText = tmp.Split(' '); 12 if(commandText[0] == "SetChara") { 13 this.currentPos = int.Parse(commandText[2]); 14 15 bool isNumber = float.TryParse(commandText[3],out this.waitTimeTimes); 16 if(isNumber == false) 17 this.waitTimeTimes = 1f; 18 19 StartCoroutine("InstantCharacters"); 20 } else if(commandText[0] == "RefChara") { 21 this.currentPos = int.Parse(commandText[2]); 22 23 bool isNumber = float.TryParse(commandText[3],out this.waitTimeTimes); 24 if(isNumber == false) 25 this.waitTimeTimes = 1f; 26 27 StartCoroutine("ChangeCharacters"); 28 } else if(commandText[0] == "SetBack") { 29 bool isNumber = float.TryParse(commandText[2],out this.waitTimeTimes); 30 if(isNumber == false) 31 this.waitTimeTimes = 1f; 32 33 StartCoroutine("ChangeBackGround"); 34 } else if(commandText[0] == "RemChara") { 35 DestroyCharacters(int.Parse(commandText[1])); 36 } else if(commandText[0] == "MovChara") { 37 this.currentPos = int.Parse(commandText[1]); 38 this.toMovePos = int.Parse(commandText[2]); 39 40 bool isNumber = float.TryParse(commandText[3],out this.waitTimeTimes); 41 if(isNumber == false) 42 this.waitTimeTimes = 1f; 43 44 StartCoroutine("MoveCharacters"); 45 } else if(commandText[0] == "RunAway") { 46 this.currentPos = int.Parse(commandText[2]); 47 48 bool isNumber = float.TryParse(commandText[3],out this.waitTimeTimes); 49 if(isNumber == false) 50 this.waitTimeTimes = 1f; 51 52 StartCoroutine("RunAwayCharacters"); 53 } else if(commandText[0] == "OutScreen") { 54 bool isNumber = float.TryParse(commandText[3],out this.waitTimeTimes); 55 if(isNumber == false) 56 this.waitTimeTimes = 1f; 57 58 StartCoroutine("ScreenBlackOut"); 59 } 60 //this.i++; 61 //コマンド用 62 } else { //コメントでもコマンドでもなければ 63 yield return new WaitUntil(() => Input.GetMouseButtonDown(0)); 64 StartCoroutine("MainStringDisplay"); 65 66 //this.i++; 67 } 68 isNext = true; 69 yield return null; 70 i++; 71 } 72 } 73 74 IEnumerator ChangeBackGround() 75 { 76 isNext = false; 77 yield return new WaitForSeconds(waitTime * waitTimeTimes); 78 if(isMove) { 79 isMove = false; 80 string backPath = this.backGroundPath + this.commandText[1]; 81 Image image = backGroundObject.GetComponent<Image>(); 82 image.sprite = Resources.Load<Sprite>(backPath); 83 Debug.Log(backPath); 84 85 yield return null; 86 isMove = true; 87 } 88 } 89 90 IEnumerator InstantCharacters() 91 { 92 isNext = false; 93 yield return new WaitForSeconds(waitTime * waitTimeTimes); 94 if(isMove) { 95 isMove = false; 96 97 string charPath = this.charactersPath + this.commandText[1]; 98 string charPrefabPath = prefabPath + "Character1"; 99 100 GameObject prefab = (GameObject)Resources.Load(charPrefabPath); 101 this.characters[currentPos] = Instantiate(prefab,new Vector3(charImagePositionX[currentPos],charImagePositionY,0f) 102 ,Quaternion.identity); 103 this.characters[currentPos].gameObject.name = "Character" + currentPos.ToString(); 104 105 this.characters[currentPos].transform.SetParent(this.canvas.transform,false); 106 107 this.characters[currentPos].GetComponent<Image>().sprite = Resources.Load<Sprite>(charPath); 108 109 SortOrderCharImage(this.characters[currentPos]); 110 111 yield return null; 112 isMove = true; 113 } 114 115 } 116
- RunAwayCharactersの中で「R」でも「L」でもない場合は中断なしでの無限ループ(=フリーズ)になります。
そのため「R」「L」のどちらが必須になりますが、そうなっていますか?
- Update()の中に「StartCoroutine("OnClickToNextString");」があります。
そのため、コルーチンが全て終わる前に次のOnClickToNextStringが実行されてしまいます。
これは意図的なものですか?
fiveHundredさん、質問ありがとうございます。
1つ目に関してはコマンドを確認し、すべてにR,Lがついてることを確認しました。
2つ目はUpdateでコルーチンを呼び出し、各コルーチン(RunAwayCharacters、ChangeCharactersなど)内でbool型のisMoveとisNextをfalseにして、コルーチンが終了したらそれぞれtrueにする、という処理をして条件分岐の際にコマンド処理に入らないようにしたかったので、意図的にUpdate内でOnClickToNextStringを呼び出しています。
エディターがフリーズしてしまう、という問題に関してはRunAwayCharactersのwhile文の後にyield return nullを記述したら解決したのですが、次はテキストの行数を参照するための変数 i が予期しない値になってしまうという問題が発生してしまいました。
質問を編集してソースを全部載せました。
かなり長いので、可能であれば見てほしいです。よろしくお願いします。
画像でソース全文載せました。
Updateでコルーチンを呼び出すのはあまり推奨されたやり方ではないのでしょうか?
Startから呼び出して再起呼び出しをしたほうがよいのでしょうか。
isNext = true;
yield return null;
i++;
この箇所ですが、順序が間違っているような気がします。
これだと「isNext = true;」でロック解除、「yield return null;」で一度待機してから「i++;」としているので、「i++;」が反映されないまま次の処理に移っているようながします。
なので、
i++;
isNext = true;
yield return null;
が正しいのではないかと。
あと、Update()が非推奨かどうかは分かりませんが、そもそもコルーチン内で
while (/*条件*/)
{
/*処理*/
yield return null;
}
とループさせればUpdate()での呼び出しは不要です。
また、「StartCoroutine("コルーチン名");」は待ち合わせを行いませんが、「yield return コルーチン名();」とすれば行えます。
なので、コルーチンで同一させるのもありかなとは思います。
あと、質問とは全く関係ないですが、メンバー変数に「i」と名前をつけるのはよくないです。
「「i」って何の意味だ?」となります。
また、私の感覚では「「i」は大昔にforループで使う変数」というイメージですので、それとも大きくかけ離れます。
意味が分かりやすい変数名にしましょう。
fiveHundredさん
ありがとうございます!常に呼び出す方法についてUpdateから呼び出す以外に、コルーチン内でループさせるという考えがなかったです。Updateからの呼び出しを消してOnClickToNextString内でループさせることで行数参照用の変数が変な値を示すバグが解決しました。
yield return コルーチン名()のやり方についてもとても助かりました。前回の処理から指定フレーム数待つという処理を行いたかったのが実現できなかったのですが、これのおかげで解決できました。
変数iについてのアドバイスもありがとうございます。わかりやすい名前を付けるよう心がけてみます
本当にありがとうございました。
(質問欄で完結してしまったのでベストアンサーつけれなくて申し訳ありません)
お手数おかけしますが、解決した内容を回答欄に記載して、それをベストアンサーにしてください。
(いわゆる自己解決というやつです)
fiveHundredさん、問題解決法の提示から自己解決の方法まで教えていただきありがとうございました。
また機会があればよろしくお願いします

回答1件
あなたの回答
tips
プレビュー