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

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

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

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

Unity

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

Q&A

1回答

857閲覧

【Unity】マインスイーパーにてタイル状態別で効果音を鳴らしたいがエラーが出力される

Tata

総合スコア0

C#

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

Unity

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

0グッド

0クリップ

投稿2023/05/05 06:28

編集2023/05/08 04:09

実現したいこと

マインスイーパーにて

  • タイルを開けたとき
  • フラグを立てたとき
  • 爆弾を開けたとき

でそれぞれ別のSEを流したい。

前提

Unity初心者です。アセットストアの Minesweeper - Game Template を元にどのようなことが出来るかを試しています。Unity 2021.3.15f1 を使用し、下記の順で作業・確認しました。

①新たなprefabsであるSound Managerを作成し、AudioSourceやAudioClipを設定後それ単体では音が出ることを確認しました。

②GameManagerにSound Managerを設定し、例えば下記を追加して画面上を左クリックしたとき音がでることを確認しました。

[SerializeField] SoundManager soundManager; public void PlayRevealBombSound() { soundManager.PlayRevealBombSound(); } void Update() { if (Input.GetMouseButtonDown(0)) //左クリック { PlayRevealBombSound(); } }

③タイルの状態で鳴らすSEを分岐させるため、TileInputHandler に GameManager を設定するようにし、タイルの状態によって鳴らす音を変えることを試みるとエラーになり音がでません。

[SerializeField] GameManager gameManager; //Normal click 左クリックが0.5秒以内ならタイルを開く if (elapsed < 0.5f) { // Play reveal tile sound or reveal bomb sound if (tile.CompareTag(Bomb.Tag)) { gameManager.PlayRevealBombSound(); } else { gameManager.PlayRevealTileSound(); } MessageSystem.Send<ITileClickListener>(listener => { listener.OnTileClick(tile); }); }

追加した class SoundManager のコード

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class SoundManager : MonoBehaviour { [SerializeField] private AudioSource source; [SerializeField] private AudioClip revealTileSound; //音源データ1 [SerializeField] private AudioClip flagTileSound; //音源データ2 [SerializeField] private AudioClip revealBombSound; //音源データ3 [SerializeField] [Range(0f, 1f)] private float soundVolume = 0.5f; public void PlayRevealTileSound() { source.PlayOneShot(revealTileSound, soundVolume); } public void PlayFlagTileSound() { source.PlayOneShot(flagTileSound, soundVolume); } public void PlayRevealBombSound() { source.PlayOneShot(revealBombSound, soundVolume); } }

発生しているエラーメッセージ

Can not play a disabled audio source UnityEngine.AudioSource:PlayOneShot (UnityEngine.AudioClip,single) SoundManager:PlayRevealBombSound () (at Assets/Ilumisoft/Minesweeper/Scripts/SoundManager.cs:36) Ilumisoft.Minesweeper.GameManager:PlayRevealBombSound () (at Assets/Ilumisoft/Minesweeper/Scripts/GameManager.cs:201) Ilumisoft.Minesweeper.TileInputHandler:OnPointerUp (UnityEngine.EventSystems.PointerEventData) (at Assets/Ilumisoft/Minesweeper/Scripts/Tile/TileInputHandler.cs:81) UnityEngine.EventSystems.EventSystem:Update ()

試したこと

出力されたエラーで検索し、原因となりそうな下記を試しました。

  • 明示的にAwake()メソッド内で audioSource.enabled = true; としてみる。

  • SoundManagerクラス内で、AudioSourceが有効であるかどうかを確認する条件分岐を追加する。

    [SerializeField] private AudioSource source; public void PlayRevealTileSound() { if (source.enabled) { source.PlayOneShot(revealTileSound, soundVolume); } else { Debug.LogError("AudioSource is disabled in SoundManager."); } }
  • Sound Managerを使用せず、GameManagerにAudioSource, Clipを設定した場合。違うエラーメッセージ(※)が出力されました。下記条件分岐を用いてPlayOneShotの引数がnullでないことを確認しても、同じエラー(※)です。

    if (revealTileClip != null) { audioSource.PlayOneShot(revealTileClip, soundVolume); }

※GameManagerで効果音を鳴らす処理としたときのエラーメッセージ

ArgumentNullException: Value cannot be null. Parameter name: source UnityEngine.AudioSource.PlayOneShot (UnityEngine.AudioClip clip, System.Single volumeScale) (at <bdec5cc4d87f4049ad39114441fe4d1e>:0) Ilumisoft.Minesweeper.GameManager.PlayRevealBombSound () (at Assets/Ilumisoft/Minesweeper/Scripts/GameManager.cs:221)

自分の考察

上記の試したことから、audio sourceが有効である場合にPlayOneShotを実行するよう条件分岐したにも関わらず、a disabled audio source と出力されていることがわかりました。

そのため、私のしらない制約か仕様があると考えています。
例えば、Tile はゲーム開始後に生成された prefab のためそこで参照するようにした Game Manager は現在実行されているものと異なるものとなりそれが悪さをしているなどです。

情報が不足している、そもそも実装の方針から間違えているなどありましたら、教えていただければ有難いです。
お願いいたします。

補足情報(FW/ツールのバージョンなど)

Unity 2021.3.15f1

2023/5/8 追記
原因はわかっていませんが、下記のようにして実現したいことは達成しました。

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class SoundManager : MonoBehaviour { //--シングルトン始まり-- public static SoundManager instance; private void Awake() { if (instance == null) { instance = this; DontDestroyOnLoad(this.gameObject); } else { Destroy(this.gameObject); } } //--シングルトン終わり-- [SerializeField] private AudioSource source; [SerializeField] private AudioClip revealTileSound; //音源データ1 [SerializeField] private AudioClip flagTileSound; //音源データ2 [SerializeField] private AudioClip revealBombSound; //音源データ3 [SerializeField] [Range(0f, 1f)] private float soundVolume = 0.3f; public void PlayRevealTileSound() { source.PlayOneShot(revealTileSound, soundVolume); } public void PlayFlagTileSound() { source.PlayOneShot(flagTileSound, soundVolume); } public void PlayRevealBombSound() { source.PlayOneShot(revealBombSound, soundVolume); } }

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

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

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

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

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

guest

回答1

0

私の方でもUnityAssetsのMinesweeper - Game Templateをimportして試しました。エラーの原因は分かったので警告は解消されたのだけど音が出ず回答になるか分かりませんが答えます。
①発生しているエラーメッセージ
なぜ警告が出ているのか?
→SoundManagerのすべての変数はprivateです。
(例)[SerializeField] private AudioSource source;
別のスクリプトで参照、使う事は出来るはずがありません。

#解決方法#
ではどうすれば良いのか?
→リファクタリング機能を使いましょう。プロパティにすることで別のスクリプトでも変数が参照あるいは使う事が出来ます。
(例)public AudioSource Source{ get=>source;}
この場合Sourceという変数は別のスクリプトでも使う事が出来ます。
シングルトンと組み合わせて使うと[SerializeField]でスクリプト参照せずに以下のような書き方が出来ます。

C#

1SoundManager2.Instance.PlayRevealBombSound(SoundManager2.Instance.Source, SoundManager2.Instance.RevealBombSound);

②GameManagerで効果音を鳴らす処理としたときのエラーメッセージ
エラー内容としてNull Reference Exceptionが出ました。オブジェクト参照で例外が発生した模様です。
こちらは自分もよく理解していませんが二重参照はできないよという感じだと思います。繰り返しになりますがUnity歴は4年間のまだまだ素人の考えなので鵜呑みにしないでください。

以上の変更をしたところエラーは消えましたが音が鳴らないのでもう少し粘ってみようと思います。質問が流れて行ってしまうので途中でもと思い、中途半端な回答になってしまいすみません。参考になった、ヒントが得られた等助けになれば幸いです。

投稿2023/05/06 07:37

isimasa

総合スコア295

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

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

Tata

2023/05/08 04:06

ご回答ありがとうございます。 今回は効果音を少し鳴らしてみよう程度の考えで、SoundManagerでSEを管理する必要が無かったのですが、シングルトン化することで音を想定どおり鳴らすことが出来ました。 私のなかでは原因を未だ特定できていません。 教えていただいた →①SoundManagerのすべての変数はprivate であることは、SoundManagerのメソッドが全てpublicであることから問題ないという理解です。(前提②より別のスクリプトから呼び出しが成功しています) 私のC#に対しての理解が不足していたら申し訳ございません。
isimasa

2023/05/10 10:05 編集

2023/05/10 すみません。私の方が間違っています。まとめると以下のようになります。 >①SoundManagerのすべての変数はprivate であることは、SoundManagerのメソッドが全てpublicであることから問題ないという理解です。 →その理解で合っています。さらに言えば、PrefabはProjectViewにあります。TileInputHandlerはPrefabに付いているのでHierarchyにあるオブジェクトとは別物です。ですので、PrefabのInspectorからHierarchyのオブジェクトをセットしようとしても出来ません。ゲーム実行後にスクリプトから動的に生成したプレハブのクローンのゲームオブジェクトは、シーンビューにあるゲームオブジェクトとは直接関連付けられないため、スクリプトを使って設定を行う必要があるということです。プレハブにしたときに、ヒエラルキーウインドウにあるゲームオブジェクトのアサインが外れてしまいます。 初期設定を行う場合、そのスクリプト内で情報を探すのではなく、外部のクラスから情報の提供を受けてそれをそのまま設定する、という手法です。メソッドの引数を活用することで問題を解消できます。 今回の場合、TileInputHandlerに書き込むのではなく、GameManagerの関数に飛んでもらってOnTileClick関数内でSoundManagerの関数を呼び出します。(OnTileClick関数はTileInputHandlerで呼ばれているので問題ない。) if (tile.CompareTag(Bomb.Tag)) { gameManager.PlayRevealBombSound(); // ここでNullReferenceException(gameManagerがNull) } else { gameManager.PlayRevealTileSound(); // ここでNullReferenceException(gameManagerがNull) } 2023/05/08 Youtubeの方でUnityやゲーム開発に関する質問・相談に答える活動をしている方がいます。 私は毎週そのコミュニティで勉強しています。 その方の活動名は”あのゲームさん”です。 許可をいただいたのでCMしておきます。 あなたもコミュニティに参加して仲間とともにゲーム開発しませんか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

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

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

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問