有限状态机

学习自: http://www.taikr.com/my/course/448 泰课在线 Erick

FSM优势:简单高效 易于扩展 模块化处理
有限状态机
FSMState 抽象类 不继承mono
抽离一些子类共有的东西
例如:巡逻点 移动速度 旋转速度 追逐范围 攻击范围 等等
还有放一个存储转换过程的字典
公有方法:增加状态的方法
删除状态的方法
根据状态返回行为的方法
抽象状态转变的原因
抽象状态转变的行为

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

namespace FSM {
    public abstract class FSMState {
        /// <summary>
        /// 存储转换过程的字典
        /// </summary>
        protected Dictionary<Transition, FSMActionId> dic = new Dictionary<Transition, FSMActionId>();

        protected FSMActionId actionId;
        public FSMActionId ActionId { get { return actionId; } }

        protected Vector3 destinationPos;// 目标点
        protected Transform[] wayPoints;//巡逻点

        protected float rotateSpeed;// 旋转速度
        protected float moveSpeed;// 移动速度

        protected float chaseDistance = 40;// 距离40码追逐
        protected float attackDistance = 5;// 距离20码攻击
        protected float arriveDistance = 2;// 距离2码到达巡逻点

        /// <summary>
        /// 往字典里添加状态
        /// </summary>
        public void AddTransition(Transition trans,FSMActionId actionId) {
            if (dic.ContainsKey(trans))
                return;
            dic.Add(trans, actionId);
            //Debug.Log("状态" + trans + "添加成功");
        }

        /// <summary>
        /// 删除
        /// </summary>
        public void DeleteTransition(Transition trans) {
            if (dic.ContainsKey(trans)) {
                dic.Remove(trans);
                return;
            } 
        }

        /// <summary>
        /// 根据状态返回行为
        /// </summary>
        /// <param name="trans"></param>
        /// <returns></returns>
        public FSMActionId GetOutAction(Transition trans) {
            return dic[trans];
        }

        /// <summary>
        /// 寻找下一个寻路点
        /// </summary>
        public void FindNextPoint() {
            int num = Random.Range(0, wayPoints.Length);
            Vector3 pos = wayPoints[num].position;
            // 如果可以 可以加一个干扰值
            Debug.Log(num);
            destinationPos = pos;
        }

        /// <summary>
        /// 抽象状态转变的行为
        /// </summary>
        /// <param name="boss"></param>
        /// <param name="player"></param>
        public abstract void Act(Transform boss, Transform player);

        /// <summary>
        /// 抽象状态转变的原因
        /// </summary>
        /// <param name="boss"></param>
        /// <param name="player"></param>
        public abstract void Reason(Transform boss, Transform player);

    }
}

Patrol

namespace FSM {
    /// <summary>
    /// 巡逻
    /// </summary>
    public class Patrol : FSMState
    {
        /// <summary>
        /// 初始化
        /// </summary>
        public Patrol(Transform[] wp) {
            wayPoints = wp;
            actionId = FSMActionId.Patrol;
            rotateSpeed = 6;
            moveSpeed = 80;
            FindNextPoint();
        } 

        /// <summary>
        /// 巡逻行为中
        /// </summary>
        /// <param name="boss"></param>
        /// <param name="player"></param>
        public override void Act(Transform boss, Transform player)
        {
            Debug.Log(destinationPos);
            if (Vector3.Distance(boss.position, destinationPos) <  arriveDistance) {
                Debug.Log("到达了目标点");
                FindNextPoint();//选择下一个目标点

            }
            // 确定boss方向

            Quaternion targetRotation = Quaternion.LookRotation(destinationPos - boss.position);
            boss.rotation = Quaternion.Slerp(boss.rotation, targetRotation, Time.deltaTime * rotateSpeed);

            // 让角色移动
            CharacterController c = boss.GetComponent<CharacterController>();
            c.SimpleMove(boss.forward * Time.deltaTime * moveSpeed);

            // 播放动画
            Animation anim = boss.GetComponent<Animation>();
            anim.CrossFade("run");
        }

        /// <summary>
        /// 巡逻状态中
        /// </summary>
        /// <param name="boss"></param>
        /// <param name="player"></param>
        public override void Reason(Transform boss, Transform player)
        {
            if (Vector3.Distance(boss.position, player.position) <= chaseDistance) {
                Debug.Log("转换为追逐状态");
                boss.GetComponent<AIController>().SetTransition(Transition.SawPlayer);
            }
        }
    }
}

Chase
Attack
Death
继承FSMState
在这些类的构造函数中初始化成员变量
重写状态转变的行为抽象方法:
做具体的事情,播放具体的动画等等
重写状态转变的原因抽象犯法:
达到某种条件转换为某种状态
FSMBase:

public class FSMBase : MonoBehaviour {

    protected Transform player;
    protected GameObject[] wayPoints;// 寻路点
    protected Vector3 distination;// 目的地

    // 针对自身框架的方法
    protected virtual void Initialize() { }
    protected virtual void FSMUpdate() { }
    protected virtual void FSMFixedUpdata() { }


    void Start () {
        Initialize();
    }

    void Update () {
        FSMUpdate();
    }

    private void FixedUpdate()
    {
        FSMFixedUpdata();
    }

AdavanceFSM:

/// <summary>
/// 状态
/// </summary>
public enum Transition {
    SawPlayer,
    ReachPlayer,
    LostPlayer,
    NoHealth
}
/// <summary>
/// 行为
/// </summary>
public enum FSMActionId {
    Patrol,
    Chase,
    Attack,
    Dead
}

/// <summary>
/// 管理类
/// </summary>
public class AdavanceFSM : FSMBase
{
    private List<FSMState> FSMStates;// 存储所有状态

    public FSMActionId CurrentActionId { get; private set; }// 当前行为Id
    public FSMState CurrentFSMState { get; private set; } // 当前状态

    public AdavanceFSM() {
        FSMStates = new List<FSMState>();
    }

    /// <summary>
    /// 向列表中增加状态
    /// </summary>
    /// <param name="state"></param>
    public void AddFSMState(FSMState state) {
        if (state == null)
            return;
        // 状态列表什么都没有
        if (FSMStates.Count == 0) {
            FSMStates.Add(state);
            CurrentFSMState = state;
            CurrentActionId = state.ActionId;
            return;
        }
        // 要加入的状态是不是在列表中存在
        for (int i = 0; i < FSMStates.Count; i++)
        {
            if (FSMStates[i].ActionId == state.ActionId) {
                return; 
            }
        }
        // 如果不存在
        FSMStates.Add(state);
    }

    /// <summary>
    /// 删除状态列表中的状态
    /// </summary>
    /// <param name="state"></param>
    public void DeleteFSMState(FSMActionId fsmState) {
        foreach (FSMState state in FSMStates)
        {
            if (state.ActionId == fsmState) {
                FSMStates.Remove(state);
                return;
            }
        }
        Debug.Log("当前列表中不存在这个状态");
    }

    /// <summary>
    /// 转变状态
    /// </summary>
    /// <param name="trans"></param>
    public void PerformTransition(Transition trans) {
        FSMActionId id = CurrentFSMState.GetOutAction(trans);
        CurrentActionId = id;
        for (int i = 0; i < FSMStates.Count; i++)
        {
            if (FSMStates[i].ActionId == CurrentActionId) {
                CurrentFSMState = FSMStates[i];
                break;
            }
        }
    }

AIController:
挂载在游戏对象身上

public class AIController : AdavanceFSM
{
    /// <summary>
    /// 初始化
    /// </summary>
    protected override void Initialize()
    {
        player = GameObject.FindGameObjectWithTag("Player").gameObject.transform;
        ConstructFSM();
    }

    private void ConstructFSM()
    {
        // 进行路点初始化
        wayPoints = GameObject.FindGameObjectsWithTag("Point");

        for (int i = 0; i < wayPointsTranform.Length; i++)
        {
            wayPointsTranform[i] = wayPoints[i].transform;
        }

        // 针对每一个行为进行初始化  针对每个行为进行状态到行为转变的添加
        Patrol patrol = new Patrol(wayPointsTranform);
        patrol.AddTransition(Transition.SawPlayer, FSMActionId.Chase);
        patrol.AddTransition(Transition.NoHealth, FSMActionId.Dead);
        Chase chase = new Chase(wayPointsTranform);
        chase.AddTransition(Transition.ReachPlayer, FSMActionId.Attack);
        chase.AddTransition(Transition.LostPlayer, FSMActionId.Patrol);

        Attack attack = new Attack(wayPointsTranform);
        attack.AddTransition(Transition.SawPlayer, FSMActionId.Chase);
        attack.AddTransition(Transition.LostPlayer, FSMActionId.Patrol);
        attack.AddTransition(Transition.NoHealth, FSMActionId.Dead);
        Dead dead = new Dead();


        // 把状态列表进行初始化 
        AddFSMState(patrol);
        AddFSMState(chase); 
        AddFSMState(attack);
        AddFSMState(dead); 
    }

    protected override void FSMUpdate()
    {        

    protected override void FSMFixedUpdata()
    {
        CurrentFSMState.Reason(transform, player.transform);
        CurrentFSMState.Act(transform, player.transform);
    }

    /// <summary>
    /// 设置状态
    /// </summary>
    /// <param name="trans"></param>
    public void SetTransition(Transition trans)
    {
        PerformTransition(trans);
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值