【Unity】長押し中に作動させて進行度をゲージに表示する

投稿者: | 2020-09-12

左クリックを長押ししている間に作動するものを作って、その進行度を進行バーで表示します。進行中はアニメーションさせて音声を鳴らし、終了すると別の音を鳴らします。

まずCubeにコライダーとスクリプト、アニメーター、オーディオソースコンポーネントを追加しました。

新規タグも付けます。

アニメーターコンポーネントはCubeに適当なアニメーションを付けたときに自動で追加されました。アニメーターコントローラーでは、まずEntryからモーションの無いステートに遷移し、その後作動中のモーションの付いたステートと行き来するようにします。

+ボタンからBoolパラメーターを作って、行き来するときの遷移の条件にします。

両方の遷移の矢印でHas Exit Timeのチェックをはずして、Conditionsにパラメーターの条件を設定します。

trueだと作動中へ遷移してfalseで戻ります。

Cubeにつけるスクリプトでこのパラメーターや進行度を管理します。

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

public class TaskScript : MonoBehaviour
{
    public bool isInProgress; // 進行中かどうか
    public float Progress { get; private set; } = 0f; // 進行度
    public float difficulty = 0.001f; // 進行速度

    Animator animator;
    AudioSource audioSource;
    [SerializeField] AudioClip[] audioClips;

    // Start is called before the first frame update
    void Start()
    {
        animator = GetComponent<Animator>();
        audioSource = GetComponent<AudioSource>();
        audioSource.loop = true;
    }

    // Update is called once per frame
    void Update()
    {
        // 進行中のとき
        if (isInProgress)
        {            
            Progress += difficulty; // 進行度を上げる

            // 進行度が1以上になったら停止
            if (Progress >= 1f)
            {
                Progress = 1f;
                isInProgress = false;
                animator.SetBool("IsStarted", false);

                audioSource.loop = false;
                audioSource.clip = audioClips[1]; // 停止音
                audioSource.Play();
            }
            else
            {

            }
        }
    }

    // 作業を開始する
    public void StartWorking()
    {      

         if (Progress < 1f)
        {
            animator.speed = 1f;// animatorSpeed;
            isInProgress = true;
            animator.SetBool("IsStarted", true);

            audioSource.clip = audioClips[0]; // 作動音
            audioSource.Play();
        }
    }

    // 作業を停止する
    public void StopWorking()
    {
        isInProgress = false;
        animator.speed = 0f; // アニメーションを一時停止

        if(Progress < 1f) audioSource.Pause(); // 音声を一時停止
    }

}

publicメソッドで作業の開始/停止ができるようにします。進行度が1未満のとき開始すると、パラメーターがtrueになって作動音が再生されます。作動中はUpdate()で進行度が上がっていき、1以上になったら停止します。

停止すると、パラメーターがfalseになって、停止音を再生します。このときに音声がループしないようにします。

// 進行度が1以上になったら停止
if (Progress >= 1f)
{
    Progress = 1f;
    isInProgress = false;
    animator.SetBool("IsStarted", false);

    audioSource.loop = false;
    audioSource.clip = audioClips[1]; // 停止音
    audioSource.Play();
}

メソッドで作業が停止されたときは、アニメーターのスピードを0にすることでアニメーションを一時停止し、音声もStop()でなくPause()を呼びます。

// 作業を停止する
public void StopWorking()
{
    isInProgress = false;
    animator.speed = 0f; // アニメーションを一時停止

    if(Progress < 1f) audioSource.Pause(); // 音声を一時停止
}

進行度が1以上のときも音声を一時停止すると、左クリックで停止音も止まってしまうので、1未満の条件を付けました。

作業の開始/停止

FirstPersonControllerクラスで顔からレイを飛ばして、Cubeに当たっているときに左クリックで作業の開始/停止をします。

int state;      
TaskScript sc_task;
[SerializeField] Image bar; // 進行バー
[SerializeField] float armLength = 3f; // 手の長さ
[SerializeField] GameObject hand; // 手の画像


// ---
// Update()

// 何もしていないとき
if (state == 0)
{
    RaycastHit hit;
    if (Physics.Raycast(m_Camera.transform.position, m_Camera.transform.forward, out hit, 50f,~(1 << 9)))
    {
        Debug.DrawRay(m_Camera.transform.position, m_Camera.transform.forward * 50f);

        GameObject hitObj = hit.collider.gameObject;
        string hitTag = hit.collider.tag;
        float hitDistance = hit.distance;
	
        // 手が届く時
        if (armLength >= hitDistance)
        {

            if (hitTag == "Task")
            {
                // 手のマーク表示
                hand.SetActive(true);

                //作業中へ
                if (Input.GetMouseButtonDown(0))
                {
                    // 手のマーク非表示
                    hand.SetActive(false);

                    sc_task = hitObj.GetComponent<TaskScript>();
                    sc_task.StartWorking(); // 作業開始

                    // 進行バーを表示      
                    bar.gameObject.SetActive(true);
                    bar.fillAmount = sc_task.Progress;

                    state = 1;

                }

            }
            // それ以外のタグのとき
            else {

                // 手のマーク非表示
                hand.SetActive(false);
            }

        }
        // 手が届かないとき
        else {

            // 手のマーク非表示
            hand.SetActive(false);
        }
    }
    // レイが当たらないとき
    else
    {
        // 手のマーク非表示
        hand.SetActive(false);

    }
}
// 作業中
else if (state == 1)
{
    // 進行度を進行バーに反映
    bar.fillAmount = sc_task.Progress;

    // 左クリックを離すと何もしていない状態へ
    if (Input.GetMouseButtonUp(0))
    {
        bar.gameObject.SetActive(false); // 進行バーを非表示
        sc_task.StopWorking(); // 作業を停止

        sc_task = null;
        state = 0;
    }

}

頭からのレイが自分の体に当たってしまうので、体にレイヤーを追加して、それを無視するようにレイヤーマスクを設定しました。

~(1 << 9)

インスペクタで設定する手の長さより近くでレイが当たると、タグでCubeを見分けて、手のマークを表示します。左クリックが押されると手のマークを消して、作業開始のメソッドを呼び、進行バーを表示します。

進行バーは前の記事の方法で作って、上のスクリプトで進行度の値を反映しています。左クリックを離すとバーを非表示にして作業停止のメソッドを呼びます。

プレイヤーの状態を整数で管理しています。何もしていないとき0で、作業開始すると1にします。そして、作業を停止するときに0にして何もしていない状態に戻しています。

コメントを残す

メールアドレスが公開されることはありません。