一、有限状态机FSM概述
二、不用有限状态机实现角色的走路、攻击动作
(1)新建角色、地面、为角色添加动画
(2)为角色添加脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player1Control : MonoBehaviour
{
private Animator ani;
void Start()
{
ani = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
float vertical = Input.GetAxis("Vertical");
float horizontal = Input.GetAxis("Horizontal");
Vector3 dir = new Vector3(horizontal, 0, vertical);
if (dir != Vector3.zero)
{
transform.rotation = Quaternion.LookRotation(dir);
transform.Translate(Vector3.forward * 3 * Time.deltaTime);
ani.SetBool("IsWalk", true);
}
else
{
ani.SetBool("IsWalk", false);
}
if (Input.GetKeyDown(KeyCode.Space))
{
ani.SetTrigger("Attack");
}
}
}
这样是能够实现角色的各种动画,但是由于if语句过多,可能以后修改起来会很麻烦。
三、用方法实现角色的走路、攻击动作
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum PlayerState
{
idle,
walk,
attack
}
public class Player2Control2 : MonoBehaviour
{
private Animator ani;
private PlayerState state = PlayerState.idle;
// Start is called before the first frame update
void Start()
{
ani = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
switch (state)
{
case PlayerState.idle:
idle();
break;
case PlayerState.walk:
walk();
break;
case PlayerState.attack:
attack();
break;
}
}
void idle()
{
//站立方法
ani.SetBool("IsWalk", false);
float vertical = Input.GetAxis("Vertical");
float horizontal = Input.GetAxis("Horizontal");
Vector3 dir = new Vector3(horizontal, 0, vertical);
if (dir != Vector3.zero)
{
//切换为走路状态
state = PlayerState.walk;
}
if (Input.GetKeyDown(KeyCode.Space))
{
//切换为攻击状态
state = PlayerState.attack;
}
}
void walk()
{
ani.SetBool("IsWalk", true);
float vertical = Input.GetAxis("Vertical");
float horizontal = Input.GetAxis("Horizontal");
Vector3 dir = new Vector3(horizontal, 0, vertical);
if (dir != Vector3.zero)
{
transform.rotation = Quaternion.LookRotation(dir);
transform.Translate(Vector3.forward * 3 * Time.deltaTime);
}
else
{
state = PlayerState.idle;
}
}
void attack()
{
ani.SetTrigger("Attack");
//如果你当前的状态不是攻击,切换状态
if (!ani.GetCurrentAnimatorStateInfo(0).IsName("Elemental@UnarmedAttack01")) ;
{
state = PlayerState.idle;
}
}
}
三、用类实现角色的走路、攻击动作
状态类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum PlayerState
{
idle,
walk,
attack
}
public abstract class FSMstate
{
//当前状态ID
public int StateID;
//当前状态拥有者
public MonoBehaviour mono;
//状态所属管理器
public FSMManager fSMManager;
public FSMstate(int StateID,MonoBehaviour mono,FSMManager manager)
{
this.StateID = StateID;
this.mono = mono;
this.fSMManager = manager;
}
public abstract void OnEnter();
public abstract void OnUpdate();
}
状态管理类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FSMManager : MonoBehaviour
{
// Start is called before the first frame update
//列表状态
public List<FSMstate> stateList = new List<FSMstate>();
//当前状态
public int CurrentIndex = -1;
public void ChangeState(int StateID)
{
stateList[CurrentIndex].OnEnter();
CurrentIndex = StateID;
}
//更新
public void Update()
{
if (CurrentIndex != -1)
{
stateList[CurrentIndex].OnUpdate();
}
}
}
PlayerControl类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Payer : MonoBehaviour
{
private FSMManager fSMManager;
void Start()
{
fSMManager = new FSMManager();
IdleState idle = new IdleState(0,this,fSMManager);
WalkState walk = new WalkState(1, this, fSMManager);
AttackState attack = new AttackState(2, this, fSMManager);
fSMManager.stateList.Add(idle);
fSMManager.stateList.Add(walk);
fSMManager.stateList.Add(attack);
fSMManager.ChangeState((int)PlayerState.idle);
}
void Update()
{
fSMManager.Update();
}
}
IdleState类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class IdleState : FSMState
{
public IdleState(int stateID,MonoBehaviour mono,FSMManager manager) : base(stateID, mono, manager)
{
}
public override void OnEnter()
{
mono.GetComponent<Animator>().SetBool("IsWalk", false);
}
public override void OnUpdate()
{
float vertical = Input.GetAxis("Vertical");
float horizontal = Input.GetAxis("Horizontal");
Vector3 dir = new Vector3(horizontal, 0, vertical);
if (dir != Vector3.zero)
{
fSMManager.ChangeState((int)PlayerState.walk);
}
//监听攻击状态切换
if (Input.GetKeyDown(KeyCode.Space))
{
fSMManager.ChangeState((int)PlayerState.attack);
}
}
}
WalkState类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WalkState : FSMState
{
public WalkState(int stateID,MonoBehaviour mono,FSMManager manager) : base(stateID, mono, manager)
{
}
public override void OnEnter()
{
mono.GetComponent<Animator>().SetBool("IsWalk", true);
}
public override void OnUpdate()
{
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 dir = new Vector3(horizontal, 0, vertical);
if (dir != Vector3.zero)
{
mono.transform.rotation = Quaternion.LookRotation(dir);
mono.transform.Translate(Vector3.forward * 3 * Time.deltaTime);
}
else
{
//切换到站立状态
fSMManager.ChangeState((int)PlayerState.idle);
}
}
// Start is called before the first frame update
}
AttackState类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AttackState : FSMState
{
public AttackState(int stateID,MonoBehaviour mono,FSMManager manager) : base(stateID, mono, manager)
{
}
public override void OnEnter()
{
mono.GetComponent<Animator>().SetTrigger("Attack");
}
public override void OnUpdate()
{
if (!mono.GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).IsName("Elemental@UnarmedAttack01"))
{
fSMManager.ChangeState((int)PlayerState.idle);
}
}
}