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

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

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

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

4回答

1162閲覧

Unityでwhile文を追加するとフリーズする。

Occhiro

総合スコア9

C#

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2024/02/10 12:11

編集2024/02/11 10:34

実現したいこと

Unityで敵に8秒間待たせた後、今のplayerの位置にスムーズに移動したい。
なお、8秒間待たせた後のその時のplayerの位置に移動させたいので、playerが移動すると、よけれるようにしたい。

発生している問題・分からないこと

while文を追加すると、8秒間立った後にフリーズします。

エラーメッセージ

error

1フリーズ(タスクマネージャーなどで強制終了しなければならなくなっている状況)になっています。

該当のソースコード

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEditor; 4using UnityEngine; 5using System.Threading.Tasks; 6 7public class mobMove : MonoBehaviour 8{ 9 public Kusuri kusuri; //ゲーム内で使う「クスリ」という物体のスクリプト 10 public GameObject pl; //player 11 public GameObject ka; //自分自身(mob) 12 13 float startTime; 14 [SerializeField] private float duration = 100; 15 16 17 // Start is called before the first frame update 18 void Start() 19 { 20 transform.position = new Vector2(14f, 4f); //モブの初期位置 21 startTime = Time.time; 22 } 23 24 // Update is called once per frame 25 async void Update() 26 { 27 if (kusuri.stage == 3) 28 { 29 await waitTime(8); 30 int sw; 31 sw = Random.Range(1, 2); 32 Transform target = pl.transform; 33 switch (sw) 34 { 35 case 1: 36 while (target.position != ka.transform.position) //←ここから 37 { 38 var t = (Time.time - startTime) / duration; 39 var xPos = Mathf.SmoothStep(ka.transform.position.x, target.position.x, t); 40 var yPos = Mathf.SmoothStep(ka.transform.position.y, target.position.y, t); 41 var zPos = Mathf.SmoothStep(ka.transform.position.z, target.position.z, t); 42 ka.transform.position = new Vector3(xPos, yPos, zPos); 43 } 44 break; 45 } 46 Debug.Log(sw); 47 } 48 } 49 50 async Task waitTime(float time) 51 { 52 int T = (int)time * 1000; 53 await Task.Delay(T); 54 } 55} 56

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

検索して出てきたのを見ても、自分の状況とは違うかったので参考になりませんでした。(本当はなったのかもしれないけど)

補足

while文の内容だけ残して実行してもフリーズはしないので、while文に原因があると思っています。(違うかもしれません。)

ぼくは、モブを動かす際にMathf.SmoothStep();を使っているので、ループしないと目的地まで移動できなくなります。

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

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

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

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

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

guest

回答4

0

そのwhile条件の部分しか見てませんが、計算で求めた実数値同士が完全に一致することは希です。
「座標が完全に一致するまでループ」じゃなくて「距離がxx以下になるまでループ」にするのが普通でしょう。

ループが何時までも終わらないというバグはよくあります。
その場合は、継続条件/終了条件を構成する値がループ内でどう変化しているか、変化していないかを調べます。
今回だと、ループ前にtarget.positionの座標値を出力して、ループ内でka.transform.positionの座標値を出力する。

投稿2024/02/10 14:05

編集2024/02/10 14:18
otn

総合スコア84887

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

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

Occhiro

2024/02/11 09:40 編集

回答ありがとうございます。 ループ前にDebug.Logで、ループ前にtarget.positionの座標値を出力して、ループ内でka.transform.positionの座標値を出力しようとすると、ループ前のtarget.positionの座標値を出力するプログラムが実行される前にフリーズしました。 ですが、「距離がxx以下になるまで」という条件式を参考にさせてもらいます。→ ```Vector2.Distance(target.position, ka.transform.position) > 0.1f```
guest

0

そのスクリプトを入れると、まずまずループの意味がなくなってしまいます。

とのことですが、そもそもUpdate()自体、「何度も呼び出されるメインループの中の関数」のようなものなので、その考え自体が間違いです。

len_soukoさんの内容を踏まえると以下のようになります。
動作未確認ですが、これを参考にすればよいと思います。

C#

1 // Start()でもUpdate()でも使うので、メンバー変数化 2 int sw; 3 4 void Start() 5 { 6 transform.position = new Vector2(14f, 4f); //モブの初期位置 7 startTime = Time.time; 8 9 // 最初の1回のみ行う処理はStart()で行えばよい 10 if (kusuri.stage == 3) 11 { 12 sw = Random.Range(1, 2); 13 } 14 } 15 16 void Update() 17 { 18 if (kusuri.stage == 3) 19 { 20 // 8秒経過までは何もしない 21 if (Time.time - startTime < 8f) return; 22 23 Transform target = pl.transform; 24 switch (sw) 25 { 26 case 1: 27 // 毎フレーム実行されるので、内部でループする必要なし 28 if (target.position != ka.transform.position) 29 { 30 var t = (Time.time - startTime) / duration; 31 var xPos = Mathf.SmoothStep(ka.transform.position.x, target.position.x, t); 32 var yPos = Mathf.SmoothStep(ka.transform.position.y, target.position.y, t); 33 var zPos = Mathf.SmoothStep(ka.transform.position.z, target.position.z, t); 34 ka.transform.position = new Vector3(xPos, yPos, zPos); 35 } 36 break; 37 } 38 Debug.Log(sw); 39 } 40 }

投稿2024/02/11 09:22

fiveHundred

総合スコア9945

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

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

Occhiro

2024/02/11 09:35 編集

回答ありがとうございます。 確かにそちらでも行けますが、敵モブのスクリプトなのでアニメーションを何個か対応させたいと思っています。スクリプトの構成を参考にさしてもらいます。
fiveHundred

2024/02/11 09:35

> 確かにそちらでも行けますが、敵モブのスクリプトなのでアニメーションを何個か対応させたいと思っています。 このコードではアニメーションに対応できないということですか? 私はそう思いませんが。
Occhiro

2024/02/11 09:37

すみません。表現力がなかったですね。 「僕は、そのコードを参考にさしてもらってこっちのほうで多様なアニメーションに対応させます。」 まだ小学6年生なので、そのような風に読み取られたかもしれません。すみませんでした。
guest

0

まず大前提として、MonoBehaviourを継承したクラスは毎フレームごとにUpdate()メソッドが呼び出されます
なので、その中で一瞬で終わるループなら大丈夫ですが、何フレームもまたがるループを行ってしまうのはルール違反です(多分フレーム更新が止まってしまうのかな?)

そこで用意された機能がコルーチンというものなので通常ではそちらを使うべしとなるところですが、今回の場合はそもそも8秒後に行いたいというだけなので、updateのところで現在時刻がstartTimeから8秒後未満の場合はupdateを抜ける(return;するだけ)で実現できると思います。
async void Update()の中の大事な場所

c#

1if (Time.time - startTime < 8) return; 2// 8秒後以降にやりたいこと

投稿2024/02/11 08:40

編集2024/02/11 08:41
len_souko

総合スコア1361

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

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

Occhiro

2024/02/11 09:00

回答ありがとうございます。 そのスクリプトを入れると、まずまずループの意味がなくなってしまいます。こちらのほうの説明が足りていなかったようなので説明を補足しました。
guest

0

自己解決

皆さんの回答を参考にし、自分で改良したところフリーズはしなくなりました。ありがとうございます。コードはこちらです。↓

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEditor; 4using UnityEngine; 5 6public class mobMove : MonoBehaviour 7{ 8 public Kusuri kusuri; 9 public GameObject pl; 10 public GameObject ka; 11 int sw; //メンバー変数にしました。 12 bool Three = true; 13 14 Transform target; 15 16 float startTime; 17 [SerializeField] private float duration = 100; 18 19 20 // Start is called before the first frame update 21 void Start() 22 { 23 transform.position = new Vector2(14f, 4f); 24 st_reset(); 25 } 26 27 // Update is called once per frame 28 void Update() 29 { 30 if(kusuri.stage == 3 && Three) 31 { 32 sT_reset(); 33 Three = false; 34 } 35 36 if (kusuri.stage == 3) 37 { 38 // 4秒経過までは何もしない 39 if (Time.time - startTime < 4f) return; //4秒に変えました。 40 attak(); 41 } 42 } 43 44 void sT_reset() 45 { 46 startTime= Time.time; 47 target = pl.transform; 48 } 49 50 void attak() 51 { 52 sw = Random.Range(1, 2); //モブの攻撃方法の選択(1から1) 53 54 switch (sw) 55 { 56 case 1: 57 if (Vector2.Distance(target.position, ka.transform.position) > 0.1f) 58 { 59 var t = (Time.time - startTime) / duration; 60 var xPos = Mathf.SmoothStep(ka.transform.position.x, target.position.x, t); 61 var yPos = Mathf.SmoothStep(ka.transform.position.y, target.position.y, t); 62 var zPos = Mathf.SmoothStep(ka.transform.position.z, target.position.z, t); 63 ka.transform.position = new Vector3(xPos, yPos, zPos); 64 } 65 else 66 { 67 sT_reset(); 68 } 69 break; 70 } 71 } 72 73 /*async Task waitTime(float time) 74 { 75 int T = (int)time * 1000; 76 await Task.Delay(T); 77 }*/ 78} 79

ここで一つ質問なんですが、元の文にもある通り、よけれるようにしたいので、playerが移動してもtargetには反映しないようにしているはずなんですが...ずっと移動してもついてきます。これを改良する方法を教えてください。

投稿2024/02/11 10:15

編集2024/02/11 10:43
Occhiro

総合スコア9

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

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

Occhiro

2024/02/11 10:35

改良する方法は別の記事で書いたほうがいいですかね。
Occhiro

2024/02/11 10:42

別の記事に書きました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.44%

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

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

質問する

関連した質問