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

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

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

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

Q&A

解決済

1回答

2863閲覧

Unityでモグラ叩きゲームを作っています。プレハブのモグラを叩いて消えたら3秒後に生成する仕組みを作りたいです。

defour

総合スコア21

C#

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

0グッド

0クリップ

投稿2020/01/30 09:55

編集2020/01/30 13:56

イメージ説明
StageViewスクリプトで、monsterViewPrefabをインタンシエイトしています。

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.UI; 5 6public class StageView : MonoBehaviour 7{ 8 [SerializeField] GameObject monsterViewPrefab; 9 [SerializeField] GameObject monster; 10 11 public void SpawnMonster() 12 { 13 monster = Instantiate(monsterViewPrefab); 14 monster.transform.SetParent(transform, false); 15 //return monster.GetComponent<MonsterView>(); 16 } 17 18 19}

その後、MonsterViewスクリプトを用いてmonsterViewPrefabにボタン機能をアタッチしており、生成されたmonsterViewPrefabをクリックすると、Destroyされます。Destoryされ3秒後にまたmonsterViewPrefabを生成したいのですが、うまくいきません。

using System.Collections; using System.Collections.Generic; using UnityEngine; using System; public class MonsterView : MonoBehaviour { //[SerializeField] StageView stageView; /*Action onTap; // public void AddListenerOnTap(Action action) { onTap += action; }*/ public void OnTap() { Debug.Log("MonsterをTap"); Destroy(this.gameObject); //Invoke("SpawnLead",3.0f); } /*void SpwanLead() { stageView.SpawnMonster(); }*/ }

MonsterViewスクリプトでOnTap関数の中で、ボタンが押されたら、 SpwanLead関数を作って、その中にmonsterViewPrefabを生成するSpawnMonster関数を入れて見ましたが、Playボタンを押しても反応がありませんでした。

生成する関数SpawnMonsterは、下のMainPresenterスクリプトで行っています。
StageViewクラスでは、monster変数にInstantiateしたものを入れているので、
これがnullで何も入っていなかったらInvoke関数を用いて、Invoke("SpawnMonster", 3.0f);このように呼び出せるかと思いましたが、「stageView.monster == null」のmonsterはアクセスできない保護レベルになっていてできませんでした。

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.UI; 5using UnityEngine.SceneManagement; 6 7public class MainPresenter : MonoBehaviour 8{ 9 [SerializeField] PlayerStatusView playerStatusView; 10 [SerializeField] StageView stageView1; 11 [SerializeField] StageView stageView2; 12 [SerializeField] StageView stageView3; 13 [SerializeField] GameObject menuView; 14 [SerializeField] GameObject finalScoreText; 15 16 [SerializeField] GameObject leftTimeText; 17 //TimeController timeController; 18 PlayerModel playerModel; 19 StageView stageView; 20 public float leftTime = 20; 21 22 23 24 public void OnRetryButton() 25 { 26 SceneManager.LoadScene("Main"); 27 } 28 29 public void OnToTitleButton() 30 { 31 SceneManager.LoadScene("Title"); 32 } 33 34 void Start() 35 { 36 playerModel = new PlayerModel(); 37 stageView = new StageView(); 38 39 //timeController = new TimeController(); 40 41 stageView1.SpawnMonster(); 42 stageView2.SpawnMonster(); 43 stageView3.SpawnMonster(); 44 //playerStatusView.UpdateText(playerModel); 45 leftTimeText.GetComponent<Text>().text = ((int)leftTime).ToString(); 46 } 47 48 void Update() 49 { 50 51 leftTime -= Time.deltaTime; 52 53 if (leftTime < 0) leftTime = 0; 54 //GetComponent<Text>().text = "残り時間:" + ((int)leftTime).ToString(); 55 56 57 if(stageView.monster == null) 58 { 59 Debug.Log("nothing"); 60 Invoke("SpawnMonster", 3.0f); 61 } 62 63 64 65 if (leftTime <= 0) 66 { 67 menuView.SetActive(true); 68 finalScoreText.SetActive(true); 69 } 70 71 leftTimeText.GetComponent<Text>().text = "残り時間:" + ((int)leftTime).ToString(); 72 } 73 74}

行いたいことは、プレハブのモグラを叩いて消えたら3秒後に生成することです。
どなたか、ご教示よろしくお願いいたします。
何か不十分な点があれば、情報を追記いたします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

StageViewのmonsterには[SerializeField]が付いています。
こいつはざっくり言うと「この変数はprivate(StageViewの中からしかアクセス出来ない)けど、インスペクタ上には表示されてそこから値を設定出来るよ」という効果があります。
なのでStageViewの外(MainPresenter)からアクセス出来ないのは当然というか仕様通りの動きです。

考えられる方法は3つ。

1.monsterをpublicにする
[SerializeField]を取ってpublicにしてしまう方法。
但しこうするとStageViewの外からmonsterを書き換えられるので、設計上あまりよくありません。

2.Getterを作る/チェック用メソッドを作る
StageViewにpublic void GetMonster() {return monster;}的なメソッドを作って呼び出し。
Nullかどうかのチェックをしたいだけならpublic void IsNullMonster() {return (monster == null);}でもいいかもしれません。
ただ今回の本質はここではないです。

3.全部StageViewに管理させる【最適】
今のInvokeの書き方上、これだとMainPresenterのSpawnMonsterを呼び出そうとするので間違っています(=StageViewのSpawnMonsterを呼び出すようになっていない)。
更にUpdateの中に組み込んでいるので、monsterがnullになってから実際にメソッドが実行されるまでの3秒間、ずっとInvokeされ続けるので3秒後に大量に生成されることでしょう。

やりたいことは「プレハブのモグラを叩いて消えたら3秒後に生成」なので、全部StageViewに任せましょう。
つまり「自分のモグラの生成」と「自分のモグラが存在しているかのチェック」と「自分のモグラが消えてたら3秒後に生成」ということだけ注視させます。
本当はコルーチンにした方がいいかもですが雑に書くと以下の通り。(動作未チェック)
後はどこかからSpawnMonsterメソッドを呼び出せば後は延々勝手に動作し続けます。(停止機能が欲しければ任意で付け足してください)

C#

1public class StageView : MonoBehaviour 2{ 3 [SerializeField] GameObject monsterViewPrefab; 4 [SerializeField] GameObject monster; 5 bool isThereMonster; //monster存在フラグ。待機時間を設ける為にフラグを持つ 6 7 public void SpawnMonster() 8 { 9 monster = Instantiate(monsterViewPrefab); 10 monster.transform.SetParent(transform, false); 11 isThereMonster = true; 12 } 13 14 void Update() 15 { 16 // monsterがさっきまで存在していたが今は無い場合、3秒後に生成 17 if (isThereMonster && monster == null) { 18 isThereMonster = false; 19 Invoke("SpawnMonster", 3.0f); 20 } 21 } 22}

投稿2020/01/31 01:19

sakura_hana

総合スコア11427

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

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

defour

2020/02/02 13:03

StageViewに管理させて解決できました。丁寧にサンプルコードまで載せていただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問