[2021.10.21]<呆头熊的开发日记>怪物AI之有限状态机(1)

经过跟队长的一致讨论,决定还是用<有限状态机>来实现怪物的行为逻辑,这样耦合性更低,更好操作。

这次的还是定点巡逻的小怪。

有三个脚本文件,IState作为接口,NewIdleS记录所有存在的状态,NewFSM为有限状态机。

具体实现形式:

1.接口:

public interface NewIstate
{
    void OnEnter();

    void OnUpdate();

    void OnExit();
}

2.记录所有存在的状态:

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

public class NewIdleSta : NewIstate
{
    private NewFSM manager;
    private Parameter1 parameter;
    private float timer;


    //状态机对象
    public NewIdleSta(NewFSM manager)
    {
        this.manager = manager;
        this.parameter = manager.parameter;
    }
    public void OnEnter()
    {
        parameter.animator.Play("Idle");
    }

    public void OnUpdate()
    {
        timer += Time.deltaTime; //计时器

        if (timer >= parameter.idleTime)
        {
            manager.TransitionState(StateType1.Patrol);
        }

    }
    
    public void OnExit()
    {
        timer = 0; //清空计时器
    }
}


public class PatrolState1 : NewIstate
{
    private NewFSM manager;
    private Parameter1 parameter;

    private int patrolPosition; //切换巡逻点

    //状态机对象
    public PatrolState1(NewFSM manager)
    {
        this.manager = manager;
        this.parameter = manager.parameter;
    }
    public void OnEnter()
    {
        parameter.animator.Play("Walk");
    }

    public void OnUpdate()
    {
        manager.FlipTo(parameter.patrolPoints[patrolPosition]);

        manager.transform.position = Vector2.MoveTowards(manager.transform.position, parameter.patrolPoints[patrolPosition].position, parameter.moveSpeed * Time.deltaTime);
        
        if (Vector2.Distance(manager.transform.position, parameter.patrolPoints[patrolPosition].position) < .1f)
        {
            manager.TransitionState(StateType1.Patrol);
        }
    }
    
    public void OnExit()
    {
        //下一个巡逻点
        patrolPosition++;

        //超出数组范围,重新开始巡逻
        if (patrolPosition >= parameter.patrolPoints.Length)
        {
            patrolPosition = 0;
        }
    }
}



public class ChaseState1 : NewIstate
{
    private NewFSM manager;
    private Parameter1 parameter;

    //状态机对象
    public ChaseState1(NewFSM manager)
    {
        this.manager = manager;
        this.parameter = manager.parameter;
    }
    public void OnEnter()
    {

    }

    public void OnUpdate()
    {

    }
    
    public void OnExit()
    {

    }
}

public class AttackState1 : NewIstate
{
    private NewFSM manager;
    private Parameter1 parameter;

    //状态机对象
    public AttackState1(NewFSM manager)
    {
        this.manager = manager;
        this.parameter = manager.parameter;
    }
    public void OnEnter()
    {

    }

    public void OnUpdate()
    {

    }
    
    public void OnExit()
    {

    }
}

3.有限状态机;

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


public enum StateType1
{
    Idle, Patrol, Chase, Attack
}

[Serializable]    //序列化此类
//敌人参数
public class Parameter1
{
    public int health;
    public float moveSpeed;
    public float chaseSpeed;
    public float idleTime;
    public Transform[] patrolPoints;
    public Transform[] chasePoints;
    public Animator animator;
}
public class NewFSM : MonoBehaviour
{
    //声明当前状态
    private NewIstate currentState;

    public Parameter1 parameter;
    private Dictionary<StateType1, NewIstate> states = new Dictionary<StateType1, NewIstate>();

    void Start()
    {
        //增加字典键值对
        states.Add(StateType1.Idle, new NewIdleSta(this));
        states.Add(StateType1.Patrol, new PatrolState1(this));
        states.Add(StateType1.Chase, new ChaseState1(this));
        states.Add(StateType1.Attack, new AttackState1(this));

        //初始状态
        TransitionState(StateType1.Idle);
        parameter.animator = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        currentState.OnUpdate();
    }

    //切换状态
    public void TransitionState(StateType1 type)
    {
        if (currentState != null)
            currentState.OnExit();
        currentState = states[type]; //字典找到相应的状态类
        currentState.OnEnter();
    }

    //更改朝向
    public void FlipTo(Transform target)
    {
        if (target != null)
        {
            if (transform.position.x >= target.position.x)
            {
                
                transform.localScale = new Vector3(-1, 1, 1);
            }
            else if (transform.position.x < target.position.x)
            {
                transform.localScale = new Vector3(1, 1, 1);
            }
        }
    }

}

上一篇:批量栅格投影(arcpy)


下一篇:Mybatis分页插件PageHelper的原理