【GodController】スマホのマルチタッチに対応したバーチャルコントローラーを作ろう!(Unityエディタでも確認可能) https://github.com/okamura0510/GodController めっちゃ久しぶりのブログですw
...
こちらの記事でAnimator
の終了を検知するのに苦戦したのですが、
こいつを使えば良さそうだと気づきました!
なので実際に修正してみました。
目次
StateMachineBehaviourについて
Animator
のステートを検知できるコンポーネントですが、詳しくは以下をご確認ください。
Unity5 MecanimのStateMachineBehaviourと戯れる
Animatorのステート(状態)の変更を検知する StateMachineBehaviour【Unity】
修正内容
Animator
でモーションが終わったら処理を行いたい- モーションが開始してからモーション終了を検知しないと上手くいかなかった
という状況でUpdate
でモーション終了を監視していたのですが、
旧:UnityChan.cs
public class UnityChan : MonoBehaviour
{
void Update()
{
// 終了モーションがある場合は監視し、終わったら初期化する
// モーション開始と終了をスクリプトで監視してるけど、本当は Animator 任せにした方が良い(安定しない。。)
if(endMotion != "" && animator.GetBool(parameter))
{
var state = animator.GetCurrentAnimatorStateInfo(0);
if(!isPlayingMotion)
{
if(state.IsName(motion)) isPlayingMotion = true;
}
else
{
if(state.IsName(endMotion)) EndMotion();
}
}
}
}
新:UnityChanMotion.cs
public class UnityChanMotion : StateMachineBehaviour
{
public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
// 終了モーションを検知したらモーションを停止させる
if(endMotion != "" && animator.GetBool(parameter))
{
var state = animator.GetCurrentAnimatorStateInfo(0);
if(state.IsName(endMotion)) Stop();
}
}
}
修正した結果
Update
→OnStateExit
に変更したことで毎フレ監視する必要がなくなって負荷減少- モーション開始を検知する必要がなくなったのでコード量削減
(適切にイベントを検知できるようになった) UnityChanMotion
にモーション関連を移したことでUnityChan
クラスが小さくなる
(コンポーネント指向)
って感じで良くなった気がします!
【注意点】StateMachineBehaviourはSerializeFieldでシーンにあるオブジェクトを参照できない
なのでこんな感じでスクリプト側で初期化しています。
UnityChan.cs
public class UnityChan : MonoBehaviour
{
[SerializeField] Animator animator;
UnityChanMotion motion;
void Start()
{
motion = animator.GetBehaviour<UnityChanMotion>();
motion.Init(animator);
}
}
UnityChanMotion.cs
public class UnityChanMotion : StateMachineBehaviour
{
Animator animator;
// モーション初期化
public void Init(Animator animator)
{
this.animator = animator;
}
}
UnityChanMotion.cs
参考までにコード全文載せときます。
/// <summary>
/// ユニティちゃんモーション。モーション再生や、終了モーションの検知を行っている。
/// </summary>
public class UnityChanMotion : StateMachineBehaviour
{
Animator animator;
string parameter = "";
string endMotion = "";
public string Parameter => parameter;
public string EndMotion => endMotion;
// モーション初期化
public void Init(Animator animator)
{
this.animator = animator;
}
// モーション再生
public void Play(string parameter, string endMotion = "")
{
if(this.parameter == parameter) return;
this.parameter = parameter;
this.endMotion = (endMotion != "") ? $"Base Layer.{endMotion}" : "";
animator.SetBool(parameter, true);
}
// モーション変化
public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
// 終了モーションを検知したらモーションを停止させる
if(endMotion != "" && animator.GetBool(parameter))
{
var state = animator.GetCurrentAnimatorStateInfo(0);
if(state.IsName(endMotion)) Stop();
}
}
// モーション停止
public void Stop()
{
animator.SetBool(parameter, false);
parameter = "";
endMotion = "";
}
}
最後に
StateMachineBehaviour
、存在は知ってて実際の現場でも見たことあったんだけど、ちゃんと自分で使わないとわからないもんだね(´・ω・`)
〜オセロを作りながらゲームのプログラムを学ぼう〜