【Unity】一度に一発ずつ弾を発射する

投稿者: | 2020-07-31

マウスを連打しても、一度のアニメーションで弾が一発ずつ発射されるようにします。

そのためにStateMachineBehaviourで攻撃可能かどうかを切り替えます。

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

public class PlayerStateMachine : StateMachineBehaviour
{

    [SerializeField] GameObject bullet; // 弾のプレハブ
    public Transform player; // プレイヤーのTransoform
    bool attackable = false; // 攻撃可能かどうか

    //OnStateEnter is called before OnStateEnter is called on any state inside this state machine
    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // 攻撃可能なステートに入ったら攻撃可能にする
        if (stateInfo.IsTag("Attackable"))
        {
            attackable = true;
        }
    }

    // OnStateUpdate is called before OnStateUpdate is called on any state inside this state machine
    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // 攻撃可能な時にマウスクリックで攻撃する
        if (Input.GetMouseButtonDown(0) && attackable)
        {
            animator.SetTrigger("Attack"); // 攻撃ステートへ
            attackable = false; // 攻撃不可能にする

            if (animator.GetInteger("Weapon") == 5) // 武器が銃のとき
            {
                var b = Instantiate(bullet, player.position + player.forward, player.rotation); // 銃弾を生成
                Rigidbody r = b.GetComponent<Rigidbody>(); // 銃弾のRigidbody
                r.AddForce(Vector3.Lerp(player.forward, player.up, 0.02f) * 38f, ForceMode.Impulse); // 銃弾を発射
            }
        }
    }

    // OnStateExit is called before OnStateExit is called on any state inside this state machine
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // 攻撃可能なステートを出たら攻撃不可能にする
        if (stateInfo.IsTag("Attackable"))
        {
            attackable = false;
        }
    }

    // OnStateMove is called before OnStateMove is called on any state inside this state machine
    //override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    
    //}

    // OnStateIK is called before OnStateIK is called on any state inside this state machine
    //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    
    //}

    // OnStateMachineEnter is called when entering a state machine via its Entry Node
    //override public void OnStateMachineEnter(Animator animator, int stateMachinePathHash)
    //{
    //    
    //}

    // OnStateMachineExit is called when exiting a state machine via its Exit Node
    //override public void OnStateMachineExit(Animator animator, int stateMachinePathHash)
    //{
    //    
    //}
}

攻撃可能なステートに入ったときに、Bool型の変数をtrueにして、出た時にfalseにしています。そして、trueのときにマウスの左クリックで攻撃し、それと同時にfalseにします。

攻撃可能なステートにいれば攻撃できるとすると弾を連射できてしまいます。Transition Durationが0だと一発ずつ出ますが、0より大きいとその間はまだ攻撃可能なステートに留まるようです。

攻撃可能ステートから攻撃ステートへはトリガーパラメーターだけで遷移して、戻るときは時間によって遷移します。

なので、攻撃と同時に攻撃不可能にしています。

攻撃可能なステートや攻撃中のステートが複数あるときは、AnimatorStateInfo.IsNameを使うと面倒なので、ステートにタグを設定します。

タグを使うと名前の違う複数のステートで同じ処理ができます。これで刀やスモークグレネードも一度に一回ずつ攻撃するようになりました。

銃弾のプレハブはインスペクタから設定できます。プレイヤーのトランスフォームはMonoBehaviourのスクリプトから設定しました。

// プレイヤーのスクリプト

PlayerStateMachine sm_player;

// Start()
sm_player = animator.GetBehaviour<PlayerStateMachine>(); // 冒頭のStateMachineBehaviourを取得
sm_player.player = transform; // プレイヤーのトランスフォームを設定

コメントを残す

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