UnityでFPSをつくる その11-1 [ 音 ]

今回からは「音」を付けていきます。
実装予定の音は以下のとおりです。

No.650

音素材を用意してあるので、以下のファイルをダウンロードしてください。

音素材まとめ

解凍して中身を見てみると、全部で11の音声ファイルが入っています。

No.651
※今回、音の素材や加工に「Scratch」を使用しています。
“Scratchは、MITメディア・ラボのライフロング・キンダーガーテン・グループの協力により、Scratch財団が進めているプロジェクトです。https://scratch.mit.edu から自由に入手できます。"

まずは、BGMを付けていきましょう。
ProjectウィンドウのAssetsフォルダ直下に「Sounds」という名前で新規にフォルダを作成してください。
Soundsフォルダの直下には「BGM」「SE」という名前でフォルダを作成。
さきほどダウンロードしたファイルの内、ファイル名に"BGM"と付いているものはBGMフォルダへ、それ以外はSEフォルダへインポートします。

No.652

TitleSceneに切り替えて、SceneManagerを選択、
Add Componentから「Audio」→「Audio Source」を選択してください。

No.653

追加されたAudio Sourceの「AudioClip」に「BGM_TitleScene」ファイルを指定、
「Loop」のチェックボックスにチェックを入れてください。

No.654

Unityで音が聞こえる仕組みは、以下のようなイメージです。

No.655

鳴らしたい音を、AudioClipとしてAudioSourceから再生し、AudioListenerで音を聞きます。
音を聞く役割をするAudioListenerは、予めCameraにComponentとしてアタッチされています。

No.656

実際に音が鳴るようになったか、実行して確認します。

AudioSourceの「Play On Awake」「Loop」にチェックが入っているため、シーン起動と同時にBGMが繰り返し再生されるようなりました。

No.658

次はボタンがクリックされた際の”決定音”を実装していきます。

No.659

決定音は、ユーザーがボタンをクリックした任意のタイミングで鳴らしたいので、スクリプトを使います。
Scriptsフォルダへ「DecisionSoundManage」と名付けたスクリプトを、新規に作成してください。

No.660

ここに以下のコードをコピペします。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DecisionSoundManage : MonoBehaviour
{
    [SerializeField] AudioClip decisionSound;

    AudioSource audioSource;

    //1回だけ音を鳴らす為の判定フラグ
    bool justOnce_decisionSound;

    void Start()
    {
        audioSource = GetComponent<AudioSource>();
    }

    void Update()
    {
        //マウスの左ボタンがクリックされたら
        if (Input.GetMouseButtonDown(0) && !justOnce_decisionSound)
        {
            //重ねて再生したい音を鳴らす
            audioSource.PlayOneShot(decisionSound);


            justOnce_decisionSound = true;
        }
    }
}

7,9行目でAudioClipとAudioSourceを操作する為の変数を宣言。

No.661

12行目では、ボタンが1回押された時だけ決定音が再生されればいいので、2回目以降と区別する為のフラグに使う変数を宣言しています。

No.662

16行目で、自身のAudioSourceコンポーネントを取得。

No.663

22~28行目で、ボタン押下時にAudioSourceからAudioClipを再生して、2回目以降に反応しないようフラグを立てています。

No.664

既に再生されているBGMに重ねて音を鳴らす為に、PlayOneShot(AudioClip clip)メソッドを使っています。

このスクリプトをSceneManagerオブジェクトにアタッチし、DecisionSoundの項目に同名の音声ファイルを指定します。

No.665

実行して、聞いてみましょう。

連続でボタンを押しても、1回しか決定音が再生されないように実装できました。
しかし、「PRESS START」のUIがボタン連打に反応してしまう不具合が見つかりました。
これを修正していきましょう。

「ToMainScene」スクリプトを開き、以下をコピペしてください。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//シーンを扱う為の名前空間
using UnityEngine.SceneManagement;

public class ToMainScene : MonoBehaviour
{
    //11-1追記
    bool justOnce = false;

    [SerializeField] Text pressStart;

    [SerializeField] Image fadeBoard;

    [SerializeField] SpriteRenderer titleImage;

    //色、透明度
    float fadeBoardColorRed, fadeBoardColorGreen, fadeBoardColorBlue, fadeBoardColorAlpha,
            titleImageColorRed, titleImageColorGreen, titleImageColorBlue, titleImageColorAlpha,
                pressStartColorRed, pressStartColorGreen, pressStartColorBlue, pressStartColorAlpha;

    //点滅の間隔
    float textBlinkDuration = 8f;

    //アルファ値加算許可、スタートボタン押下済みフラグ
    bool alphaAdditionFlag, pressStartDoneFlag;

    // Start is called before the first frame update
    void Start()
    {
        //colorの個々の値は取得できても変更できない為、変数に代入する
        fadeBoardColorRed = fadeBoard.color.r;

        fadeBoardColorGreen = fadeBoard.color.g;

        fadeBoardColorBlue = fadeBoard.color.b;

        fadeBoardColorAlpha = fadeBoard.color.a;

        titleImageColorRed = titleImage.color.r;

        titleImageColorGreen = titleImage.color.g;

        titleImageColorBlue = titleImage.color.b;

        titleImageColorAlpha = titleImage.color.a;

        pressStartColorRed = pressStart.color.r;

        pressStartColorGreen = pressStart.color.g;

        pressStartColorBlue = pressStart.color.b;

        pressStartColorAlpha = pressStart.color.a;
    }

    // Update is called once per frame
    void Update()
    {
        BeforePressStart();

        if (Input.GetMouseButtonDown(0) && !justOnce)
        {
            //11-1追記
            //連打されて何度も呼び出されないようにする為
            justOnce = true;

            //スタートボタン押下前のテキスト点滅間隔を終了
            pressStartDoneFlag = true;

            StartCoroutine(FadeOut());
        }
    }

    IEnumerator FadeOut()
    {
        //フェードアウト
        var isFadeOut = true;

        //何秒かけて暗転させるか
        var fadeOutDuration = 3f;

        //点滅の間隔
        var textBlinkDurationAfterPressStart = 0.3f;

        while (isFadeOut)
        {
            //fadeOutDurationの時間で暗転するよう、アルファ値を加算
            fadeBoardColorAlpha += Time.deltaTime / fadeOutDuration;

            //titleImageはfadeBoard暗転の影響を受けないので、個別にアルファ値を減算
            titleImageColorAlpha -= Time.deltaTime / fadeOutDuration;

            //STARTキーのクリック前より、短い間隔でアルファ値 0.5 ~ 1 の間を行き来するようにする
            if (pressStartColorAlpha >= 0.5f && !alphaAdditionFlag)
            {
                pressStartColorAlpha -= Time.deltaTime / textBlinkDurationAfterPressStart;

                pressStart.color = new Color(pressStartColorRed, pressStartColorGreen, pressStartColorBlue, pressStartColorAlpha);

                if (pressStartColorAlpha <= 0.5f)
                {
                    alphaAdditionFlag = true;
                }
            }
            else if (pressStartColorAlpha <= 1f && alphaAdditionFlag)
            {
                pressStartColorAlpha += Time.deltaTime / textBlinkDurationAfterPressStart;

                pressStart.color = new Color(pressStartColorRed, pressStartColorGreen, pressStartColorBlue, pressStartColorAlpha);

                if (pressStartColorAlpha >= 1f)
                {
                    alphaAdditionFlag = false;
                }
            }

            //アルファ値以外は変更せずにcolorに値を代入
            fadeBoard.color = new Color(fadeBoardColorRed, fadeBoardColorGreen, fadeBoardColorBlue, fadeBoardColorAlpha);

            titleImage.color = new Color(titleImageColorRed, titleImageColorGreen, titleImageColorBlue, titleImageColorAlpha);

            //fadeBoardの透明度が1(完全に不透明)かつ、titleImageの透明度が0(完全に透明)になったら
            if (fadeBoardColorAlpha >= 1 && titleImageColorAlpha <= 0)
            {
                //フェードアウト終了
                isFadeOut = false;
            }

            yield return null;
        }

        yield return new WaitForSeconds(1f);

        //メインシーンに切り替え
        SceneManager.LoadScene("MainScene");
    }

    //スタートボタン押下前のテキスト点滅
    void BeforePressStart()
    {
        //アルファ値加算許可&スタートボタン押下済みフラグが立っていない場合
        if (pressStartColorAlpha >= 0.5f && !alphaAdditionFlag && !pressStartDoneFlag)
        {
            pressStartColorAlpha -= Time.deltaTime / textBlinkDuration;

            pressStart.color = new Color(pressStartColorRed, pressStartColorGreen, pressStartColorBlue, pressStartColorAlpha);

            if (pressStartColorAlpha <= 0.5f)
            {
                alphaAdditionFlag = true;
            }
        }
        //完全に透明にならないよう、アルファ値 0.5 ~ 1 の間を行き来するようにする
        else if (pressStartColorAlpha <= 1f && alphaAdditionFlag && !pressStartDoneFlag)
        {
            pressStartColorAlpha += Time.deltaTime / textBlinkDuration;

            pressStart.color = new Color(pressStartColorRed, pressStartColorGreen, pressStartColorBlue, pressStartColorAlpha);

            if (pressStartColorAlpha >= 1f)
            {
                alphaAdditionFlag = false;
            }
        }
    }
}

追記部分を見ていきましょう。
11行目、決定音の時と同様に、2回目以降と区別する為のフラグを宣言して初期化しています。

No.667

68行目、ボタンが1回押された時にフラグを立て、2回目以降のボタン押下に反応しないようにしています。

No.668

再度実行してみましょう。

想定通りの挙動になりました。
長くなってきたので続きは次回にしたいと思います。おつかれさまでした!

FPS

Posted by kenji