前回はコイン取得演出の追加と、セーブ・ロード処理を追加し、ほぼ完成という状態になりました。
前回の記事↓
今回はサウンドの追加を行い、ゲームとしての完成を目指します。
サウンドの追加にはサウンドマネージャーを使用します。ここまで通して読んでいただいた方には申し訳ございませんが、一度サウンドマネージャー作成講座の方を先に見ていただき、改めてこちらへ進んでいただくとスムーズに制作が出来ます。
サウンドマネージャーの記事↓
サウンド追加
まずSceneにSoundManagerを配置しましょう。
CTRL+SHIFT+Nキーで新規オブジェクトを作成し、名前は「SoundManager」に。
スクリプトを新規追加で、こちらも名前は「SoundManager」にしておきましょう。
今回はSingletonを使ったアクセス方法にします。
SoundManagerスクリプトは以下のように修正します(サウンドマネージャー作成講座と同じ内容です)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundManager : MonoBehaviour { [System.Serializable] public class SoundData { public string name; public AudioClip audioClip; public float playedTime; //前回再生した時間 } [SerializeField] private SoundData[] soundDatas; //AudioSource(スピーカー)を同時に鳴らしたい音の数だけ用意 private AudioSource[] audioSourceList = new AudioSource[20]; //別名(name)をキーとした管理用Dictionary private Dictionary<string, SoundData> soundDictionary = new Dictionary<string, SoundData>(); //一度再生してから、次再生出来るまでの間隔(秒) [SerializeField] private float playableDistance = 0.2f; //1つであることを保証するため&グローバルアクセス用 public static SoundManager Instance { private set; get; } private void Awake() { if (Instance == null) { Instance = this; } else if (Instance != this) //自身が他にもあるようなら { Destroy(gameObject); //削除 return; } //auidioSourceList配列の数だけAudioSourceを自分自身に生成して配列に格納 for (var i = 0; i < audioSourceList.Length; ++i) { audioSourceList[i] = gameObject.AddComponent<AudioSource>(); } //soundDictionaryにセット foreach (var soundData in soundDatas) { soundDictionary.Add(soundData.name, soundData); } } //未使用のAudioSourceの取得 全て使用中の場合はnullを返却 private AudioSource GetUnusedAudioSource() { for (var i = 0; i < audioSourceList.Length; ++i) { if (audioSourceList[i].isPlaying == false) return audioSourceList[i]; } return null; //未使用のAudioSourceは見つかりませんでした } //指定されたAudioClipを未使用のAudioSourceで再生 public void Play(AudioClip clip) { var audioSource = GetUnusedAudioSource(); if (audioSource == null) return; //再生できませんでした audioSource.clip = clip; audioSource.Play(); } //指定された別名で登録されたAudioClipを再生 public void Play(string name) { if (soundDictionary.TryGetValue(name, out var soundData)) //管理用Dictionary から、別名で探索 { if (Time.realtimeSinceStartup - soundData.playedTime < playableDistance) return; //まだ再生するには早い soundData.playedTime = Time.realtimeSinceStartup;//次回用に今回の再生時間の保持 Play(soundData.audioClip); //見つかったら、再生 } else { Debug.LogWarning($"その別名は登録されていません:{name}"); } } } |
さて、このゲームに音を付けるわけですが、音を鳴らすポイントを列挙してみましょう。
- コインの取得音
- 売却ボタンのボタン音
- 羊購入音
- 羊毛刈り取り音
- 羊の鳴き声(羊毛が全て刈り取られた時)
まぁ、こんな所でしょうか。ゲームがシンプルなので大分少ないですね。
では、これらに対応した効果音を探しましょう。
効果音の用意
手元に大量の効果音素材を持っているような方はその中からそれっぽいものを探し出してくれれば良いですが、そうでない方はフリー素材で揃えてしまいましょう。
講座では 効果音ラボ様から以下ファイルをダウンロードしてきて使います。
自然・動物[1] から
・ヒツジの鳴き声.mp3
戦闘[1] から
・剣の素振り2.mp3
ボタン・システム音[1]
・決定・ボタン押下1.mp3
・カーソル移動1.mp3
初学者の方は揃えたほうがわかりやすいと思いますので同じく上記ファイル4つをダウンロードしておいてください。(以降、この4ファイル名を想定した内容になりますので、ご自分で用意した音素材を利用するかたは、適宜読み替えてください。)
この各種mp3ファイルをプロジェクトにインポートしたいのですが、まず先にAssetsフォルダに新規作成でSoundsフォルダを作成して、その中に音声ファイルをドラッグ・アンド・ドロップします。
これで、準備は完了です。
SoundManagerへの登録
では、これらをSoundManagerのSound Datasに登録します。
Sizeは4にし、それぞれにName(別名)とAudioClipのペアを登録します。
今回のAudioClipと登録名・その用途は以下になります。
効果音 | 登録名 | 用途 |
カーソル移動1 | コイン | コインの取得音 |
決定・ボタン押下1 | ボタン | 売却ボタンのボタン音 |
剣の素振り2 | 刈り取り | 羊毛刈り取り音 |
ヒツジの鳴き声 | メー | 羊の鳴き声(羊毛が全て刈り取られた時) 羊購入音 |
※登録名さえ同じであれば、登録するAudioClipは自由に入れ替えて構いません(そのための別名登録機能です)
スクリプトから効果音再生
それでは順にスクリプトから適宜効果音が再生されるように修正していきます。
まず
- コインの取得音
は、コインが消えると同時に鳴るようにしましょう。
CoinスクリプトのUpdateメソッド内、Destroy(gameObject);
の下に追加します。
音を鳴らすのはSoundManagerなので、CoinオブジェクトそのものがDestroyされても問題ないのがありがたいですね。
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
void Update() { waitTime -= Time.deltaTime; //カウントダウン if (waitTime > 0) return; //まだ待ち時間なので動かない var v = wallet.transform.position - transform.position;//現在の位置から、Walletオブジェクトまで進むベクトル transform.position += v * Time.deltaTime * 20; //近づいたら到着したとみなす if (v.magnitude < 0.5f) { wallet.money += value; Destroy(gameObject); SoundManager.Instance.Play("コイン"); } } } |
次に
- 売却ボタンのボタン音
です。これは GameMainスクリプトの SellAllWoolメソッド内に追加します。
14 15 16 17 18 19 20 21 22 |
private void SellAllWool() { var wools = FindObjectsOfType<Wool>(); //画面上の全てのWoolスクリプトが付いたオブジェクトを検索してWool配列woolsに格納 foreach (var wool in wools) { wool.Sell(wallet); } SoundManager.Instance.Play("ボタン"); } |
- 羊毛刈り取り音
これは、追加場所の候補が2つあります
- SheepスクリプトのShavingメソッド内
- Woolオブジェクトの生成時(Startメソッド内)
どちらでも構いませんが、今回は
- SheepスクリプトのShavingメソッド内
にしましょう。
SheepスクリプトのShavingメソッド内の一番最後に追加します。
加えて
- 羊の鳴き声(羊毛が全て刈り取られた時)
もSheepスクリプトのShavingメソッド内の 羊毛が無くなった(woolCnt <= 0)の中に書くことになります。
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
private void Shaving() { if (woolCnt <= 0) return; //もう刈り取れる羊毛はない var shavingWool = (int)(sheepData.woolCnt * Random.Range(0.3f, 0.4f)); //3~40%の羊毛を刈り取る if (woolCnt < shavingWool) shavingWool = woolCnt; //今羊に残っている羊毛より多い羊毛は取れないので、上限 woolCnt -= shavingWool; //今回刈り取る分を保持している羊毛から減らし if (woolCnt <= 0) //0になったようなら、 { sheepRenderer.sprite = cutSheepSprite; //画像をカットされたものに差し替え sheepRenderer.color = Color.white; //毛はもうないので色を白に戻す SoundManager.Instance.Play("メー"); } var wool = Instantiate(woolPrefab, transform.position, transform.rotation); //Woolオブジェクトに今回刈り取った羊毛を渡す wool.price = shavingWool; wool.woolColor = sheepData.color; SoundManager.Instance.Play("刈り取り"); } |
- 羊購入音
最後に羊の購入音になります。
まとめ
今回は効果音の追加を行い、ゲームのメイン部分を完成させることが出来ました。
最後に残るはスマホ対応化ですね!
次回が最後の講座、
全11回に加え、サウンドマネージャー作成も途中で入っているため非常に長い講座となってしまいました、ここまでお付き合い頂き誠にありがとうございました。
コメント