游戏开发中的有限状态机(FMS)

游戏开发中的有限状态机(FMS)

这个可以看成是一个AI模板,无论大小游戏中敌人以及一些NPC都是是游戏中不可或缺的一些元素,他们AI的好坏会严重影响我们的游戏体验,而有限状态机可以制作一些简单的AI,并且可以保持逻辑的有序性以及代码的可阅读性。
用干净的代码实现一些基本功能。

创建一个最基本的接口,所有状态都基于这个接口

public interface IState 
{
    void OnEnter();//进入状态
    void OnUpdate();//状态进行中
    void OnExit();//离开状态
}

创建几个基本的状态作为示范
Idle状态

public class IdleState : IState
{
    private FMS fms;
    private Character character;
    private float timer;
    public IdleState(FMS fms,Character character)//在状态机中实例化的时候可以指定是哪个状态机与属性类
    {
        this.fms = fms;
        this.character = character;
    }
    public void OnEnter()
    {
        fms.PlayAnimation("Idle");
    }

    public void OnExit()
    {
        timer = 0;
    }

    public void OnUpdate()
    {
        timer += Time.deltaTime;
        if (timer > 3)
        {
            fms.SetState(Enum.StateType.walk);
        }
    }
}

Walk状态

public class WalkState : IState
{
    private FMS fms;
    private Character character;
    public WalkState(FMS fms, Character character)
    {
        this.fms = fms;
        this.character = character;
    }
    public void OnEnter()
    {
        fms.PlayAnimation("Walking");
    }

    public void OnExit()
    {
        character.StopMove();
        fms.positionIndex++;
        if (fms.positionIndex > fms.position.Length-1)
            fms.positionIndex = 0;
        character.SetTarget(fms.position[fms.positionIndex]);
    }

    public void OnUpdate()
    {
        if (character.ToWard())
        {
            if (character.isAttack)
                fms.SetState(Enum.StateType.attack);
            else
                fms.SetState(Enum.StateType.idle);
        }
    }
}

Attack状态

public class AttackState : IState
{
    private FMS fms;
    private Character character;
    public AttackState(FMS fms, Character character)
    {
        this.fms = fms;
        this.character = character;
    }
    public void OnEnter()
    {
        fms.PlayAnimation("Attacking");
    }

    public void OnExit()
    {
    }

    public void OnUpdate()
    {
        if (!character.isAttack)
            fms.SetState(Enum.StateType.idle);
    }

}

状态机的实现

public class FMS : MonoBehaviour
{
    private IState currentState;
    private Dictionary<Enum.StateType, IState> states = new Dictionary<Enum.StateType, IState>();
    private Character character;
    private Animator animator;
    public Transform[] position;
    public int positionIndex = 0;
    private void Awake()
    {
        character = GetComponent<Character>();
        animator = GetComponent<Animator>();
    }
    private void Start()
    {
        states.Add(Enum.StateType.idle, new IdleState(this,character));
        states.Add(Enum.StateType.walk, new WalkState(this,character));
        states.Add(Enum.StateType.attack, new AttackState(this,character));
        SetState(Enum.StateType.idle);
        character.SetTarget(position[positionIndex]);
    }

    private void Update()
    {
        currentState.OnUpdate();
    }
    public void SetState(Enum.StateType stateType)//设置状态,如果当前状态不为空,调用当前状态的离开方法,设置当前状态,调用当前状态的进入方法
    {
        if (currentState != null)
        {
            currentState.OnExit();
        }
        currentState = states[stateType];
        currentState.OnEnter();
    }
    public void PlayAnimation(string name)
    {
        animator.Play(name);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.tag != this.tag)
        {
            character.isAttack = true;
            character.SetEenemy(collision.gameObject.GetComponent<Character>());
            SetState(Enum.StateType.attack);
        }

    }
}

基本属性类的实现

public class Character : MonoBehaviour
{
    private Animator animator;
    private new Rigidbody2D rigidbody2D;
    [SerializeField]private Transform target;
    [SerializeField]private float moveSpeed;
    public bool isAttack = false;
    [SerializeField] private float hp;
    [SerializeField] private float atk;
    [SerializeField] private float df;
    private Character enmemyCharacter;//敌人的属性脚本
    void Start()
    {
        animator = GetComponent<Animator>();
        rigidbody2D = GetComponent<Rigidbody2D>();
    }
    public bool ToWard()//移向目标
    {
        if (Vector2.Distance(target.position, transform.position) < 0.1f)
        {
            return true;
        }
        if (target.position.x < transform.position.x)
        {
            transform.localScale = new Vector3(-1,1);
        }
        else
        {
            transform.localScale = new Vector3(1, 1);
        }
        rigidbody2D.velocity=((target.position-transform.position).normalized)*moveSpeed;
        return false;
    }

    public void StopMove()
    {
        rigidbody2D.velocity = Vector2.zero;
    }

    public void SetTarget(Transform target)
    {
        this.target = target;
    }

    public void SetEenemy(Character character)
    {
        enmemyCharacter = character;
    }

    public void GetDamage(float atk)
    {
        hp -= atk - df;
    }

    public void Attack()
    {
        enmemyCharacter.GetDamage(atk);
    }
}

通过FMS与Character这两个脚本便可以实现一些战斗功能,具体效果如下:

只能放动态图勉强看一下
在这里插入图片描述
双方会走向绿点在过程中遭遇然后战斗。
这样简单的有限状态机就完成了,大家可以根据需求完善脚本。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值