質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

328閲覧

Unity コルーチンを実行するとフリーズしてしまう

Sakurami

総合スコア2

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2023/02/22 13:11

編集2023/02/23 13:13

前提

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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fiveHundred

2023/02/22 13:52

- RunAwayCharactersの中で「R」でも「L」でもない場合は中断なしでの無限ループ(=フリーズ)になります。 そのため「R」「L」のどちらが必須になりますが、そうなっていますか? - Update()の中に「StartCoroutine("OnClickToNextString");」があります。 そのため、コルーチンが全て終わる前に次のOnClickToNextStringが実行されてしまいます。 これは意図的なものですか?
Sakurami

2023/02/22 15:20

fiveHundredさん、質問ありがとうございます。 1つ目に関してはコマンドを確認し、すべてにR,Lがついてることを確認しました。 2つ目はUpdateでコルーチンを呼び出し、各コルーチン(RunAwayCharacters、ChangeCharactersなど)内でbool型のisMoveとisNextをfalseにして、コルーチンが終了したらそれぞれtrueにする、という処理をして条件分岐の際にコマンド処理に入らないようにしたかったので、意図的にUpdate内でOnClickToNextStringを呼び出しています。 エディターがフリーズしてしまう、という問題に関してはRunAwayCharactersのwhile文の後にyield return nullを記述したら解決したのですが、次はテキストの行数を参照するための変数 i が予期しない値になってしまうという問題が発生してしまいました。 質問を編集してソースを全部載せました。 かなり長いので、可能であれば見てほしいです。よろしくお願いします。
Sakurami

2023/02/22 15:38

画像でソース全文載せました。 Updateでコルーチンを呼び出すのはあまり推奨されたやり方ではないのでしょうか? Startから呼び出して再起呼び出しをしたほうがよいのでしょうか。
fiveHundred

2023/02/23 02:16

isNext = true; yield return null; i++; この箇所ですが、順序が間違っているような気がします。 これだと「isNext = true;」でロック解除、「yield return null;」で一度待機してから「i++;」としているので、「i++;」が反映されないまま次の処理に移っているようながします。 なので、 i++; isNext = true; yield return null; が正しいのではないかと。
fiveHundred

2023/02/23 02:29

あと、Update()が非推奨かどうかは分かりませんが、そもそもコルーチン内で while (/*条件*/) { /*処理*/ yield return null; } とループさせればUpdate()での呼び出しは不要です。 また、「StartCoroutine("コルーチン名");」は待ち合わせを行いませんが、「yield return コルーチン名();」とすれば行えます。 なので、コルーチンで同一させるのもありかなとは思います。 あと、質問とは全く関係ないですが、メンバー変数に「i」と名前をつけるのはよくないです。 「「i」って何の意味だ?」となります。 また、私の感覚では「「i」は大昔にforループで使う変数」というイメージですので、それとも大きくかけ離れます。 意味が分かりやすい変数名にしましょう。
Sakurami

2023/02/23 02:52

fiveHundredさん ありがとうございます!常に呼び出す方法についてUpdateから呼び出す以外に、コルーチン内でループさせるという考えがなかったです。Updateからの呼び出しを消してOnClickToNextString内でループさせることで行数参照用の変数が変な値を示すバグが解決しました。 yield return コルーチン名()のやり方についてもとても助かりました。前回の処理から指定フレーム数待つという処理を行いたかったのが実現できなかったのですが、これのおかげで解決できました。 変数iについてのアドバイスもありがとうございます。わかりやすい名前を付けるよう心がけてみます 本当にありがとうございました。 (質問欄で完結してしまったのでベストアンサーつけれなくて申し訳ありません)
fiveHundred

2023/02/23 03:53

お手数おかけしますが、解決した内容を回答欄に記載して、それをベストアンサーにしてください。 (いわゆる自己解決というやつです)
Sakurami

2023/02/23 04:13

fiveHundredさん、問題解決法の提示から自己解決の方法まで教えていただきありがとうございました。 また機会があればよろしくお願いします
guest

回答1

0

自己解決

フリーズ 行数参照用の変数が変な値を示すバグの解決法

コルーチン中のフリーズに関して

whileループの直後にフレーム待ち処理を追加することで解決しました

行数参照用の変数のバグに関して

Updateでコルーチン呼び出しを行っていたことが原因でした。Update内の呼び出しを削除し、コルーチン内でループするように変更したら解決しました。

C#

1 IEnumerator OnClickToNextString() 2 { 3 4 while(true) { 5 if(isMove && isNext) { 6 //isNext = false; 7 tmp = scenarioList[i]; 8 if(tmp[0] == '#') { //コマンドだったら 9 tmp = tmp.Remove(0,1); 10 commandText = tmp.Split(' '); 11 if(commandText[0] == "SetChara") { 12 this.currentPos = int.Parse(commandText[2]); 13 14 bool isNumber = float.TryParse(commandText[3],out this.waitTimeTimes); 15 if(isNumber == false) 16 this.waitTimeTimes = 1f; 17 18 yield return InstantCharacters(); 19 } else if(commandText[0] == "RefChara") { 20 this.currentPos = int.Parse(commandText[2]); 21 22 bool isNumber = float.TryParse(commandText[3],out this.waitTimeTimes); 23 if(isNumber == false) 24 this.waitTimeTimes = 1f; 25 26 yield return ChangeCharacters(); 27 } else if(commandText[0] == "SetBack") { 28 bool isNumber = float.TryParse(commandText[2],out this.waitTimeTimes); 29 if(isNumber == false) 30 this.waitTimeTimes = 1f; 31 32 yield return ChangeBackGround(); 33 } else if(commandText[0] == "RemChara") { 34 DestroyCharacters(int.Parse(commandText[1])); 35 } else if(commandText[0] == "MovChara") { 36 this.currentPos = int.Parse(commandText[1]); 37 this.toMovePos = int.Parse(commandText[2]); 38 39 bool isNumber = float.TryParse(commandText[3],out this.waitTimeTimes); 40 if(isNumber == false) 41 this.waitTimeTimes = 1f; 42 43 yield return MoveCharacters(); 44 } else if(commandText[0] == "RunAway") { 45 this.currentPos = int.Parse(commandText[2]); 46 47 bool isNumber = float.TryParse(commandText[3],out this.waitTimeTimes); 48 if(isNumber == false) 49 this.waitTimeTimes = 1f; 50 51 yield return RunAwayCharacters(); 52 } else if(commandText[0] == "OutScreen") { 53 bool isNumber = float.TryParse(commandText[1],out this.waitTimeTimes); 54 if(isNumber == false || commandText[1] == null) 55 this.waitTimeTimes = 1f; 56 57 yield return ScreenBlackOut(); 58 } 59 } else { //コメントでもコマンドでもなければ 60 yield return MainStringDisplay(); 61 } 62 i++; 63 isNext = true; 64 yield return null; 65 isMove = true; 66 } 67 } 68 }

投稿2023/02/23 04:12

Sakurami

総合スコア2

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問