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

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

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

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

Unity3D

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

Unity

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

Q&A

解決済

1回答

1636閲覧

UIのボタンを押したときにスペースキーを押したことにしたいのですが方法がわからず困っています

Papaseijin

総合スコア15

C#

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

Unity3D

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

Unity

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

0グッド

0クリップ

投稿2021/05/21 05:27

前提・実現したいこと

UIのボタンを押したときにスペースキーを押したことにしたいのですが方法がわからず困っています

Unityでアドベンチャーゲームを作っているのですが、会話システムにfungusというアセットを使っています。

主人公ではなくNPCなどのオブジェクトに下記スクリプトをアタッチしていて、Playerが対象オブジェクトに接触しているときにスペースキーを押すと話すことができるようになるのですがこのスペースキーの役割をUIのボタンに持たせたい状況です。

スペースキーにこだわっている理由は会話ウインドウの文字送りもスペースキーに紐づいているようなので念のためスペースキーにしたいです。

UIボタン押下⇨スペースキー押下⇨会話スタートを理想としています。

稚拙な文章で申し訳ございません。
皆様の知恵をお借りしたいです。
どうぞよろしくお願いします

該当のソースコード

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Fungus;
[RequireComponent(typeof(Flowchart))]
public class NPCController : MonoBehaviour
{
[SerializeField]
string message = "";
GameObject playerObj;
Flowchart Flowchart;
void Start()
{
playerObj = Gameobject.FindGameObjectWithTag("Player");
flowChart = GetComponent<Flowchart>();
}
private void OnCollisionEnter2D(UnityEngine.Collision2D other)
{
if (other.gameObject.tag == "Player" && Input.Getkey(KeyCode.Space))
{
StartCoroutine(Talk());
}
}
IEnumerator Talk()
{
flowChart.SendFungusMessage(message);
yield return new WaitUntil(() => flowChart.GetExecutingBlocks().Count == 0);
}
}

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

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

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

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

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

ayousanz

2021/05/21 08:10

> スペースキーにこだわっている理由は会話ウインドウの文字送りもスペースキーに紐づいているようなので念のためスペースキーにしたいです。 この部分を任意のUIButtonやcallback関数に結び付けるのはなにか問題があるのでしょうか? 別の解決方法があるのではないかと思い,疑問に思ったため確認です.
Papaseijin

2021/05/21 11:40

ご確認の投稿ありがとうございます 全く問題ございません! お恥ずかしい話なのですがプログラムを始めて3ヶ月ほどでfungusアセットの中のプログラムを読解する自信がないということが元々の理由です。 他の方法をご教授いただけるのでしたらお伺いしたいです!
YAmaGNZ

2021/05/21 12:38

ボタンが押されたときにもStartCoroutineすればいいのでは?
Papaseijin

2021/05/21 13:46

ご回答ありがとうございます シーン上にこのスクリプトを持っているゲームオブジェクト(NPC)が複数存在していて、接触しているゲームオブジェクトのスクリプト情報を保持しておく必要があると思うのですがそのやり方がわからないです 何か良い方法はありますでしょうか
YAmaGNZ

2021/05/21 23:54

会話可能なNPCが同時に2人以上にならないのであれば、シーン上のスクリプトに会話可能NPCのゲームオブジェクトを保持しておくものを用意しておき、NPC側のスクリプトで会話可能状態になったらその部分に自分を代入、会話不可能になったらその部分をクリア ボタンが押下されたら、会話可能と保持してあるNPCオブジェクトの会話を開始するメソッドを呼ぶ みたいな構造はどうでしょうか?
guest

回答1

0

ベストアンサー

スクリプトを見る限り「 StartCoroutine(Talk());」で会話が始めるようですね。
なのでUIでボタンを作成し、「 StartCoroutine(Talk());」を読んであげればいいだけなのですが、
この会話の呼出し処理をNPCが行っているというのが少々面倒になりそうです。

UIボタンを押したときに全てのNPCをチェックして、近くにプレイヤーがいたら会話処理をする、という方法で実現できますが、
これだとプレイヤーの近くにNPCが複数人いたらどうなるの?とか、NPCの数が多いとチェックに時間が掛かるという問題が起きそうです。

ですので、UIボタンを押すと、プレイヤーの会話処理を呼び出す。その中では一番近くにいるNPCを探して、
それの「 StartCoroutine(Talk());」を呼び出してあげればいいと思います。

また、「OnCollisionEnter2D」は衝突したときだけ呼ばれます。
https://docs.unity3d.com/ja/current/ScriptReference/Collider2D.OnCollisionEnter2D.html

接触しているときにスペースキー(あるいはUIのボタンなど)で会話したいなら「OnCollisionStay2D」をお使いください。
https://docs.unity3d.com/ja/current/ScriptReference/Collider2D.OnCollisionStay2D.html

投稿2021/05/22 05:07

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Papaseijin

2021/05/22 13:24

ご回答ありがとうございます!勉強不足で申し訳ないです。深掘りしてお伺いしたいのですが 全てのNPCをチェックして近くにプレイヤーがいたらというのは具体的にはどのようにすれば検出すれば良いでしょうか? UIボタンを押したときにStartCoroutineを会話したい対象のオブジェクトから拾ってくる方法が思いつかないのです。
Papaseijin

2021/05/22 13:26

あとOnCollisionEnterではなくOnCollisionStayを使っているのにOnCollisionEnterと記載してしまっていました! ご指摘ありがとうございます
退会済みユーザー

退会済みユーザー

2021/05/22 13:53

>>全てのNPCをチェックして近くにプレイヤーがいたら~ これは「①全てのNPC取得する」と「②その中からプレイヤーに近いものを探す」二つの処理に分けられます。 ①について手っ取り早いのはNPCにタグを設定し、GameObject.FindGameObjectsWithTagを使う方法です。 https://docs.unity3d.com/ja/current/ScriptReference/GameObject.FindGameObjectsWithTag.html ②については、①で取得したオブジェクトからVector3.Distanceで、値が最も小さいものを一番近くにいることになります。 https://docs.unity3d.com/ja/current/ScriptReference/Vector3.Distance.html これで一番近いオブジェクトを取得し、GetComponentで「NPCController」の処理を呼び出せるはずです。
Papaseijin

2021/05/22 14:11

すぐご回答いただきありがとうございます???? 今家に着いたので早速試してみます! できたら報告します!
Papaseijin

2021/05/22 15:53

色々試したみたのですが②の作業としては、①で取得している複数のオブジェクトの中から距離が一番距離が短いものを見つけるために一つ一つ距離を計算していくということで合っていますでしょうか 複数のオブジェクトの距離を測るのはforeachでできそうなのですがその中から最小値を拾うにはどうしたら良いでしょうか
退会済みユーザー

退会済みユーザー

2021/05/22 16:17

まず取得したNPCとプレイヤー間の距離をVector3.Distanceを使用して距離を測ることは出来ましたか? それができれば、以下のような感じですね。 ①取得したNPC群のなかから1個目のNPCを一番近いNPCとして変数に入れる。 ②foreeachでNPC群を1個ずつ、一番近いNPCの変数とで距離を比較。 ③比較結果、NPC群のものが一番近いNPCの変数より、近ければそれを変数に保存。 ④foreeachの終了した結果、変数に一番近いNPCが入ってる。
Papaseijin

2021/05/23 01:02

ありがとうございます???? 今日帰ったら試してみます!
Papaseijin

2021/05/23 15:49 編集

public Fungus.Flowchart flowchart; [SerializeField] GameObject[] friends; [SerializeField] GameObject dammy; [SerializeField] GameObject main; [SerializeField] float sqrLen; [SerializeField] float sqrRen; void Start() { Vector3 offset = dammy.transform.position - main.transform.position; sqrLen = offset.sqrMagnitude; } public void StartTalk() { Vector3 offset = dammy.transform.position - main.transform.position; sqrLen = offset.sqrMagnitude; foreach (GameObject friend in friends) { Vector3 offset1 = friend.transform.position - main.transform.position; sqrRen = offset1.sqrMagnitude; if(sqrLen >= sqrRen) { dammy = null; dammy = friend; } } if(sqrRen <= 1.0f) { dammy.GetComponent<NPCTALK>().StartConversation(); } } public void PushUIButton() { StartTalk(); } }
Papaseijin

2021/05/23 15:52

上記のようなコードで作ってみたのですが、ボタンを経由して会話をスタートすることができるようになりました!ありがとうございます! 現状は「③比較結果、NPC群のものが一番近いNPCの変数より、近ければそれを変数に保存。」がうまくいかない状態です。 「①取得したNPC群のなかから1個目のNPCを一番近いNPCとして変数に入れる」で仮で格納したNPCとしか会話ができずに③で会話先の変更がなされない状況なのですが原因はわかりますでしょうか? なんども質問してしまい申し訳ございません
Papaseijin

2021/05/23 16:01

GameObject.FindGameObjectsWithTagはうまく機能させることができなかったのでインスペクター上で先に指定しました また距離を測るときはsqrをつけるとよいと書いてあったのでそのようにしました
退会済みユーザー

退会済みユーザー

2021/05/23 16:13

>>仮で格納したNPCとしか会話ができない問題ですが、距離の計算が間違っているかもしれません。 sqrMagnitudeによる距離の比較をしたことがない(試すのも面倒なので)、どう間違っているか分かりませんが、計算した距離を確認しましょう。 「sqrRen = offset1.sqrMagnitude;」の後に、 「Debug.log("sqrLen:" + sqrLen)」と「Debug.log(friend.name + ":" + sqrRen)」みたいな感じの処理を入れて実行すれば、if文がtrueにならず、dammyが変わらない理由が分かるはずです。
退会済みユーザー

退会済みユーザー

2021/05/23 16:17

>>GameObject.FindGameObjectsWithTagはうまく機能させることができなかったので これは問題ありません。そのような方法でもできるので、まずはやりたいことを優先させて後から改善方法などを探ればいいかと。 また、ループ部分にもちょっと問題があり、現状だと2番目当たりに近いキャラを取得できても、1番目近いキャラは取得できないかもしれません。 「dammy」の名前を「nearFriend」に、「sqrLen」の名前を「neartFriendLen」に、「sqrRen」の名前を「FreindLen」に変えると理解しやすく、問題も分かりやすくなると思います。
Papaseijin

2021/05/23 16:22

ご回答ありがとうございます 一度sqrMagnitudeではなくdistanceでも試してみます ループ文も見直して早速試してみます
Papaseijin

2021/05/24 01:44

using System.Collections; using System.Collections.Generic; using UnityEngine; public class ButtonPush : MonoBehaviour { public Fungus.Flowchart flowchart; [SerializeField] GameObject[] friends; [SerializeField] GameObject closest; [SerializeField] GameObject main; [SerializeField] float nearFriendLen; private float friendLen; void Start() { Vector3 offset = closest.transform.position - main.transform.position; nearFriendLen = offset.sqrMagnitude; } public void StartTalk() { if(GetPlayerTalking()) { } else { Vector3 offset = closest.transform.position - main.transform.position; nearFriendLen = offset.sqrMagnitude; foreach (GameObject friend in friends) { Vector3 offset1 = friend.transform.position - main.transform.position; friendLen = offset1.sqrMagnitude; if(friendLen < nearFriendLen) { closest = null; closest = friend; } } if(nearFriendLen <= 1.0f) { closest.GetComponent<NPCTALK>().StartConversation(); } } Off(); } private bool GetPlayerTalking() { return flowchart.GetBooleanVariable("Talking"); } public void Off() { } }
Papaseijin

2021/05/24 01:45

無駄が多いかとは思いますが上記のスクリプトでやりたいことができるようになりました! 潜在的な問題点まで考えていただきありがとうございました! 本当に助かりました!
退会済みユーザー

退会済みユーザー

2021/05/24 11:12

動いたなら何よりですが、このままだと潜在的なバグは解決してませんね。 「 if(friendLen < nearFriendLen)」がtrueなら、「nearFriendLen = friendLen」してnearFriendLenを更新してあげてください そうしないと、一番近くにいるclosestの距離が10。1人目のfriend距離が5の場合、 closestが1人目のfriendになりますが、次に2人目のfriendの距離が7の場合、closestが2人目のfriendになってしまいます。 要するにfriedの人数やそれぞれの距離によって一番近くではない人が取得できてしまいます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問