您当前的位置: 首页 >  unity
  • 4浏览

    0关注

    193博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unity简单实现FSM有限状态机

我寄人间雪满头丶 发布时间:2021-05-04 02:40:10 ,浏览量:4

前言

这段时间写游戏遇到实现敌人AI的需求,打算使用FSM。当然无论是FSM、行为树、亦或者简单粗暴的ifelse都能制作AI,但是考虑到FSM比ifelse、switch架构更清晰方便管理,比行为树更好把控(毕竟自己纯手撸代码),最后决定使用FSM。

代码多处使用到里氏替换原则,不了解的同学可以先了解一下更便于理解。

核心代码

FSM管理类

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

//AI状态
public enum FSMStateType
{
    Idle, Patrol, Seek, Attack,LookAt, Hit, Death
}

public class FSM : MonoBehaviour
{
	//这里使用list主要考虑到有可能需要状态并行
    private List currentState = new List();
    //存储所有状态
    protected Dictionary states = new Dictionary();
	
	//初始化状态机,传入所需状态并切换到初始状态
    protected void InitFSM(Dictionary states, List startState)
    {
        this.states = states;
        TransitionState(startState);
    }

	//执行所有状态的OnUpdate方法
    void Update()
    {
        if(currentState.Count != 0)
        {
            for (int i = 0; i  _.OnExit());
		
		//切换成传入的新状态
        currentState.Clear();
        List stateList = new List();
        type.ForEach(_ => stateList.Add(states[_]));
        currentState = stateList;
		
		//执行新状态的OnEnter
        currentState.ForEach(_ => _.OnEnter());
    }
}

IState类,所实现的具体状态类需集成该接口

public interface IState
{
    void OnEnter();

    void OnUpdate();

    void OnExit();
}
实际应用

具体的AI类,需继承FSM类。

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

public class Enemy1AI : FSM
{
	//实现的状态类
    private SeekState seekState;
    private EnemyAttackState attackState;
    private LookAtTargetState lookAtState;
    private EnemyDeathState deathState;

    private void Start()
    {
        seekState = GetComponent();
        attackState = GetComponent();
        lookAtState = GetComponent();
        deathState = GetComponent();
		
		//初始化FSM
        InitFSM(new Dictionary() { 
            { FSMStateType.Seek, seekState },
            { FSMStateType.Attack, attackState },
            { FSMStateType.LookAt,lookAtState},
            { FSMStateType.Death,deathState}
        }, new List() { FSMStateType.Seek });
    }
}

具体实现状态,这里是实现了一个寻路状态。注意继承IState接口。

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

public class SeekState : MonoBehaviour,IState
{
    private NavMeshAgent agent;

    public string tagStr; //根据标签寻找
    public Transform target; //目标
    public Vector3 targetPos; //目标点
    public float arriveDis; //距离多少为到达
    public float speed; //移速
    public float acceleration; //加速度
    public float angularSpeed; //角速度
    public List nextState; //完成后是否切换到下一个状态

    bool isComplete;

    void Start()
    {
        agent = GetComponent();
    }

    public void OnEnter()
    {
        isComplete = false;

        if (tagStr != string.Empty)
        {
            target = GameObject.FindWithTag(tagStr).transform;
        }
    }

    public void OnUpdate()
    {
        //Debug.Log(Vector3.Distance(target.position, transform.position));
        if (isComplete)
            return;

        if (target != null)
        {
            DoSeek(target.position);
        }
        else
        {
            DoSeek(targetPos);
        }
    }

    public void OnExit()
    {
    }

    void DoSeek(Vector3 pos)
    {
        agent.stoppingDistance = arriveDis;
        agent.angularSpeed = angularSpeed;
        agent.speed = speed;
        agent.acceleration = acceleration;
        agent.SetDestination(pos);

        if (Vector3.Distance(pos, transform.position)  temp.Add((FSMStateType)Enum.Parse(typeof(FSMStateType), _)));

				//由于里氏替换原则我们不需要获取Enemy1AI直接获取FSM即可
                GetComponent().TransitionState(temp);
            }
        }
    }
}

关注
打赏
1648518768
查看更多评论
立即登录/注册

微信扫码登录

0.2627s