マウスを連打しても、一度のアニメーションで弾が一発ずつ発射されるようにします。
そのために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; // プレイヤーのトランスフォームを設定