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

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

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

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

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Q&A

0回答

654閲覧

【Unity3D】キャラとの会話が一度しかできない

AcrossKodez

総合スコア0

C#

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

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

0グッド

0クリップ

投稿2022/01/08 17:40

編集2022/01/09 07:35

###【要望】キャラに触れたら会話発生→会話が終わる→キャラに触れたらまた会話発生...のように、ループさせたい
下記スクリプトは、
プレイヤーが、フィールド内に立っているモブキャラクターに触れると吹き出しとセリフが表示される仕組みになっています(コライダー同士の当たり判定によって会話が発生OnCollisionEnter)。
プレイヤーがモブに触れるたびに、吹き出しとセリフとが繰り返し表示されるようにコルーチンをループさせたい
のですが、
処理をループさせるにはvoid Update()メソッドに何か書かなければいけないと思うのですが、
思いつきません。

現状、コルーチンは一度しか実行されず、2回目以降、モブに触れてもセリフと吹き出しが一切表示されません。

新たなメソッドを作るか、あるいはwhileでループさせるという手法が適切なのか、
また、どのようにコードを書き加えればいいのか、
困っているので、お助け願います。

よろしくお願いいたします。

###モブキャラの会話発生スクリプト

c#

1using UnityEngine; 2using System.Collections; 3 4public class MessageScript : MonoBehaviour 5{ 6 [SerializeField] 7 private Message messageScript;// Messageスクリプトを読み込む 8 public string[] message1;// 管理したい会話の数だけ作成する 9 public string[] message2; 10 public string[] message3; 11 12 void Start() 13 { 14 15 } 16 17void Update() 18 { 19 20 } 21 22void OnCollisionEnter(Collision col) 23{ 24 if (col.gameObject.name == "Player") 25 { 26 StartCoroutine("Message",message1);// Messageコルーチンを実行する 27 } 28 29 if (Input.GetKeyDown(KeyCode.B))// Bキーがおされたら、 30 { 31 StartCoroutine("Message",message2);// Messageコルーチンを実行する 32 } 33 34 if (Input.GetKeyDown(KeyCode.C))// Cキーがおされたら、 35 { 36 StartCoroutine("Message",message3);// Messageコルーチンを実行する 37 } 38 } 39 40 IEnumerator Message(string[] Conversation)// Messageコルーチン 41 { 42 yield return new WaitForSeconds(0.01f);// 0.01秒待つ 43 messageScript.SetMessagePanel(Conversation);// messageScriptのSetMessagePanelを実行する 44 } 45}

###セリフと吹き出しの制御スクリプト

C#

1using UnityEngine; 2using System.Collections; 3using UnityEngine.UI;// UI機能を使用するために追記 4 5public class Message : MonoBehaviour 6{ 7 public bool isActive;// Canvasの表示非表示 8 public GameObject canvas;// 使用するCanvas 9 public Text messageText;// メッセージを表示する文字 10 private string message;// 表示するメッセージ 11 [SerializeField] 12 private int maxTextLength = 400;// 1回のメッセージの最大文字数 13 private int textLength = 0;// 1回のメッセージの現在の文字数 14 [SerializeField] 15 private int maxLine = 3;// メッセージの最大行数 16 private int nowLine = 0;// 現在の行 17 [SerializeField] 18 private float textSpeed = 0.05f;// テキストスピード 19 private float elapsedTime = 0f;// 経過時間 20 private int nowTextNum = 0;// 今見ている文字番号 21 private Image clickIcon;// マウスクリックを促すアイコン 22 [SerializeField] 23 private float clickFlashTime = 0.2f;// クリックアイコンの点滅秒数 24 private bool isOneMessage = false;// 1回分のメッセージを表示したかどうか 25 private bool isEndMessage = false;// メッセージをすべて表示したかどうか 26 private string[] conversation;// 会話 27 private int i = 0;// 文字列の列 28 private int stringsCount = 0;// 文字列の総行数 29 30 void Start() 31 { 32 gameObject.SetActive(true);// このオブジェクトを表示する 33 clickIcon = canvas.transform.Find("Panel/Image").GetComponent<Image>();// clickIconをキャンバスの中のPanelの中のImageにする 34 clickIcon.enabled = false;// clickIconのコンポーネントをオフにする 35 messageText.text = "";// 文字を空白にする 36 } 37 38 void Update() 39 { 40 if (isEndMessage || message == null)// もし、メッセージが終わっていない、または設定されているなら 41 { 42 return;// 返す 43 } 44 45 if (!isOneMessage)// もし、1回に表示するメッセージを表示していなくて、 46 { 47 if (elapsedTime >= textSpeed)// テキスト表示時間が経過したら、 48 { 49 messageText.text += message[nowTextNum];// 次の文字番号にする 50 51 if (message[nowTextNum] == '\n')// もし、改行文字だったら 52 { 53 nowLine++;// 行数を足す 54 } 55 56 nowTextNum++;// 次の文字番号にする 57 textLength++;// 次の文字数にする 58 elapsedTime = 0f;// 経過時間を0にする 59 60 if (nowTextNum >= message.Length || textLength >= maxTextLength || nowLine >= maxLine)// もし、メッセージを全部表示、または行数が最大数表示されたなら、 61 { 62 isOneMessage = true;// isOneMessageをtrueにする 63 } 64 } 65 66 elapsedTime += Time.deltaTime;// 経過時間に時間の経過分足す 67 68 //ここからエンターキーを押して一気に表示させる処理 69 if (Input.GetKeyDown(KeyCode.Return))// もし、メッセージ表示中にエンターキーが押されたら、 70 { 71 var allText = messageText.text;// allTextに、文字を入れる 72 73 for (var i = nowTextNum; i < message.Length; i++)// 表示するメッセージ文繰り返す 74 { 75 allText += message[i];//allTextに表示するi番目のメッセージを足す 76 77 if (message[i] == '\n')// もし、改行文字だったら、 78 { 79 nowLine++;// 今の行に一行足す 80 } 81 82 nowTextNum++;// 次の文字番号にする 83 textLength++;// 次の文字数にする 84 85 if (nowTextNum >= message.Length || textLength >= maxTextLength || nowLine >= maxLine)// もし、メッセージがすべて表示される、または1回表示限度を超えたなら、 86 { 87 messageText.text = allText;// messageTextをallTextにする 88 isOneMessage = true;// isOneMessageをtrueにする 89 break;// 処理を止める 90 } 91 } 92 } 93 } 94 95 else// エンターキーが押されていなければ、 96 { 97 elapsedTime += Time.deltaTime;// 経過時間に時間の経過分足す 98 99 if (elapsedTime >= clickFlashTime)// クリックアイコンを点滅する時間を超えたなら、 100 { 101 clickIcon.enabled = !clickIcon.enabled;// クリックアイコンを点滅させる 102 elapsedTime = 0f;// 経過時間を0にする 103 } 104 105 // クリックされたら次の文字を表示する処理 106 if (Input.GetKeyDown(KeyCode.Return))// もし、エンターキーが押されたら、、 107 { 108 messageText.text = "";// メッセージを空白にする 109 nowLine = 0;// 今の行を0にする 110 clickIcon.enabled = false;// クリックアイコンをオフにする 111 elapsedTime = 0f;// 経過時間を0にする 112 textLength = 0;// 文字数を0にする 113 isOneMessage = false;// isOneMessageを0にする 114 115 if (nowTextNum >= message.Length)// もし、メッセージが全部表示されていたら、 116 { 117 nowTextNum = 0;// 現在の文字番号を0にする 118 119 if (i == stringsCount - 1)// もし、文字列の総行数に達したら、 120 { 121 isEndMessage = true;// isEndMessageをtrueにする 122 canvas.transform.GetChild(0).gameObject.SetActive(false);// キャンバスの子オブジェクトを非表示にする 123 } 124 125 else// もし、文字列の総行数に達していなければ、 126 { 127 i++; //iを1増やす 128 SetMessage(conversation[i]);// SetMessageを実行する 129 } 130 } 131 } 132 } 133 } 134 135 void SetMessage(string message)// SetMessage 136 { 137 this.message = message;// このオブジェクトのmessageをmessageにする 138 } 139 140 public void SetMessagePanel(string[] message)// SetMessagePanel 141 { 142 i = 0;// iを0にする 143 stringsCount = message.Length;// 文字列の総行数をmessageの要素数にする 144 conversation = message;// coversationをmessageにする 145 canvas.SetActive(true);// キャンバスを表示する 146 SetMessage(conversation[0]);// SetMessageを実行する 147 canvas.transform.GetChild(1).gameObject.SetActive(true);// キャンバスの子オブジェクトを表示する 148 isEndMessage = false;// isEndMessageをfalseにする 149 } 150} 151

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

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

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

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

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

fiveHundred

2022/01/09 01:02

「触れる度にコルーチンを実行したい」とのことですが、OnCollisionEnter()は触れるたびに実行される関数であり、その実行毎にコルーチンを開始しているため、現状でも動作するはずです。 記載のコードをほぼそのままで実行しましたが、一度離れてから再度接触すると正しく動作します。 このコード以外に問題があるかもしれませんので、それらをもう一度確認してみてください。 また、「OnCollisionEnter()内でInput.GetKeyDown()を行っている」点が私は気になっており、これは以下のように問題があるので、そこも修正したほうがよろしいかと思います。 - OnCollisionEnter()は接触時に呼ばれるので、接触と同時にキーを押さなければ、その処理を行うことは出来ない - OnCollisionEnter()はどうやらFixedUpdate()と同じ扱いになっており、この中で実行するとバグの原因となる
AcrossKodez

2022/01/09 07:05

ご回答ありがとうございます。 モブキャラに接触した際に、発生する会話と吹き出しを制御するスクリプトの情報を追記したので、ご確認いただければ幸いです。 OnColisionEnter()内でInput.GetKeyDown()を実行するのは、相性的にあまりよくないのでしょうか。モブキャラの会話文が長い場合に、リターンキーで会話を更新できるようにしているのですが、別の方法が必要な気がしてきました。 引き続き、助言いただきたく思います。 よろしくお願いいたします。
AcrossKodez

2022/01/09 07:30 編集

当方がすでに試したことは、 Input.GetKeyDown()部分をすべてInput.GetMouseButtonDown(0)に書き換え、左クリックで会話を実行できるようにしても、コルーチンは一回のみ機能するということです。fiveHundredさん側で、スクリプトがコード記述通りに機能していることが不思議です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問