Unity_设计模式_有限状态机_010

FSM,有限状态机,可以理解成是对行为逻辑的抽象,就好象人在生活中会做出各种行为,例如吃饭、睡觉等,这些所有我们都看作是“行为”的分支,由大脑决定每种行为具体是什么实施。
在整个FSM架构中,其实与上面解释一致,首先有一个状态基类stateObject,里面有三个方法,分别是状态前、状态中、状态后。所有具体行为都要继承这个基类,在这三个方法中具体实现各种方法的逻辑。然后,需要一个stateManager(大脑)状态管理类来管理这些状态,特别注意的是里面changeState方法,他是状态跳转的关键。至于如果存储各种状态,你可以用list类 ,字典类等等。
有限状态机是把一个对象的行为分解称为易于处理的“块”或状态。
例如,灯的开关,就是一个简单的有限状态机。它有两种状态:开和关。
*总而言之就是分离游戏逻辑代码的编码技巧,或者可以称之为模式,即经验和套路 不仅在游戏中有应用,在人工智能领域用途也很广泛
我们使用动画状态机时,有手动拖拽的方法,这时我们利用FSM的话就可以省略拖拽操作了。*

有限状态机的优点
比如说我们游戏中需要些一个脚本来控制角色的一些逻辑。角色的移动,攻击等属性时,我们不可能把代码放在一个脚本中完成,我们肯定要通过一定的方法,把它们划分成多个脚本或者说多个部分,依次来实现。因为这样把复杂的代码划分成一个一个小部分去实现,可以提高我们代码的可维护性,以及重用性,这也就是为什么我们要使用状态机的原因!

在数据中的本质
FSM本质上是张连通图。
每个节点之间满足一定条件之后可以相互转化。

FSM生成的脚本和C#的模板不同,
我们首先要在Add Behaviour按键处生成,这类脚本继承于StateMachineBehavior。
经过以下的验证我们得出方法的运行是这样运行的,如果动画要执行首先执行OnStateEnter,然后一直执行OnStateUpdate,直到动画执行结束,执行OnStateExit。动画此时结束。
using UnityEngine;
using System.Collections;
public class Idle : StateMachineBehaviour {

 // OnStateEnter is called before OnStateEnter is called on any state inside this state machine

override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
    Debug.Log("idle enter");

}

// OnStateUpdate is called before OnStateUpdate is called on any state inside this state machine

override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
    Debug.Log("idle update");
}

// OnStateExit is called before OnStateExit is called on any state inside this state machine

override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
    Debug.Log("idle exit");
}

有限动态机的操作步骤:
using UnityEngine;
using System.Collections;
public class State {
public StateMachine machine;

//这里的方法名和StateMachineBehaviour里面的方法的一样 
public virtual void EnterState() { }   
//
public virtual void UpdateState() { }   
//
public virtual void ExitState() { }

}
//注册的每一个状态知道自己被那个机器所管理
public class Sleep : State
{

public override void EnterState()
{
    Debug.Log("睡前");
}
public override void UpdateState()
{
    Debug.Log("睡中");
    if (Input.GetKeyDown(KeyCode.A))
    {
        this.machine.ChangeState("Eat");

    }
}
public override void ExitState()
{
    Debug.Log("睡后,起床了");
}

}
public class Eat : State
{

public override void EnterState()
{
    Debug.Log("饭前");
}
public override void UpdateState()
{
    Debug.Log("饭中");
    if (Input.GetKeyDown(KeyCode.B))
    {
        this.machine.ChangeState("Sleep");
    }
}
public override void ExitState()
{
    Debug.Log("饭后");
}

}
public class Work : State
{

public override void EnterState()
{
    Debug.Log("打卡");
}
public override void UpdateState()
{
    Debug.Log("敲代码");
}
public override void ExitState()
{
    Debug.Log("准备下班");
}

}
public class OverTime : State
{

public override void EnterState()
{
    Debug.Log("准备加班");
}
public override void UpdateState()
{
    Debug.Log("加班中");
}
public override void ExitState()
{
    Debug.Log("终于下班了");
}

}
public class Study : State
{

public override void EnterState()
{
    Debug.Log("准备学习");
}
public override void UpdateState()
{
    Debug.Log("学习中");
}
public override void ExitState()
{
    Debug.Log("准备睡觉了");
}

}
using UnityEngine;
using System.Collections.Generic;
using System;
//状态机类 维护所有状态的注册,设置默认,切换,执行
public class StateMachine {

private Dictionary<string, State> _stateDic = new Dictionary<string, State>();    
     //注册    
public void Register(string key, State value)
{
    value.machine = this;
    _stateDic.Add(key,value);
}        
    //设置默认  
    private State _currentState;    
    private State _lastState;
    public void Setdefault(string key)
{

    if (_stateDic.ContainsKey(key))
    {
        _currentState = _stateDic[key];
    }
    else
    {
        Debug.Log("设置默认失败");
    }
}
public void ChangeState(string key)
{
    if (_stateDic.ContainsKey(key))
    {
        _currentState = _stateDic[key];
    }
    else
    {
        Debug.Log("切换状态失败");
    }
}

public void DoWork()
{

 //执行的命令(重点)

   if (_currentState!=_lastState)//_current=Sleep,_last=null
    {
        _currentState.EnterState();//sleeo.enter,_current=sleep,_last=sleep++++++_current=eat,_last=sleep
        _lastState = _currentState;
    }
    _lastState.UpdateState();//sleep.update,_current=eat,_last=sleep++++++eat.enter
    if (_lastState!=_currentState
        )//+++++++++_current=rat,_last=eat
    {
        _lastState.ExitState();//sleep,exit
    }
}

}
using UnityEngine;
using System.Collections;
public class TestMachine : MonoBehaviour {

   //状态机    
   public StateMachine stateMachine =new StateMachine();
   // Use this for initialization   
  void Start () {
    //注册,
    stateMachine.Register("Sleep", new Sleep());
    stateMachine.Register("Eat", new Eat());
    //默认动画
    stateMachine.Setdefault("Sleep");
}   
// Update is called once per frame
void Update () {
    //持续更新
   stateMachine.DoWork();
}

}
using UnityEngine;
using System.Collections;
public class State {

//被谁所管理
public StateMachine machine;
//继承变量,方便此类和派生类使用( protected受保护的)
protected float _time;

public virtual void EnterState() { }
public virtual void UpdateState() { }
public virtual void ExitState() { }

}
public class Idie : State
{

private float _toWalkTime;
public override void EnterState()
{
    Debug.Log("进入站岗状态");
    _toWalkTime = Random.Range(2.0f, 3.0f);
}
public override void UpdateState()
{
    Debug.Log("持续站岗状态");
    _time += Time.deltaTime;
    if (_time>=_toWalkTime)
    {
        this.machine.ChangeState(StateType.Walk);
        //此时我们不能使用协程,因为协程是继承于(MonoBehaviour)
    }
    if (Input.GetKeyDown(KeyCode.F))
    {
        this.machine.ChangeState(StateType.Fire);
    }

}
public override void ExitState()
{
    _time = 0;
}

}
public class Walk : State
{

private float _toIdieTime;
public override void EnterState()
{
    Debug.Log("进入巡逻状态");
    _toIdieTime = Random.Range(3.0f, 5.0f);
}
public override void UpdateState()
{
    Debug.Log("持续巡逻状态");
    _time += Time.deltaTime;
    if (_time >= _toIdieTime)
    {
        this.machine.ChangeState(StateType.Idie);

    }
    if (Input.GetKeyDown(KeyCode.F))
    {
        this.machine.ChangeState(StateType.Fire);
    }
    if (this.machine.hp<=0)
    {
        this.machine.ChangeState(StateType.Die);
    }
}
public override void ExitState()
{
    _time = 0;
}

}
public class Fire : State
{

public override void EnterState()
{
    Debug.Log("进入开火状态");
}
public override void UpdateState()
{
    Debug.Log("持续开火状态");
    if (Input.GetKeyDown(KeyCode.L))
    {
        this.machine.ChangeState(StateType.Walk);
    }
    if (this.machine.hp <= 0)
    {
        this.machine.ChangeState(StateType.Die);
    }
}
public override void ExitState()
{

}

}
public class Die : State
{
public override void EnterState()
{
Debug.Log(“死了”);
}
public override void UpdateState()
{

}
public override void ExitState()
{

}

}
using UnityEngine;
using System.Collections.Generic;
public enum StateType
{

Idie,
Walk,
Fire,
Die

}
public class StateMachine
{

public Dictionary<StateType, State> _dic = new Dictionary<StateType, State>();
private State _currentState;
private State _lastState;
public int hp=5;

public void Register(StateType key,State valua)
{
    valua.machine = this;
    _dic.Add(key,valua);
}
public void ChangeState(StateType key)
{
    if (_dic.ContainsKey(key))
    {
        Debug.Log("初始成功");
        _currentState = _dic[key];
    }
    else
    {
        Debug.Log("初始失败");
    }
}

public void DoWork()
{
    if (_currentState!=_lastState)
    {
        _currentState.EnterState();
        _lastState = _currentState;
    }
    _lastState.UpdateState();
    if (_lastState!=_currentState)
    {
        _lastState.ExitState();
    }
    if (Input.GetKeyDown(KeyCode.S))
    {
        //手动减血
        hp--;
    }
}

}
using UnityEngine;
using System.Collections;
public class AI : MonoBehaviour {

private StateMachine _stateMachine=new StateMachine();  
// Use this for initialization
void Start () {
    _stateMachine.Register(StateType.Idie, new Idie());
    _stateMachine.Register(StateType.Walk, new Walk());
    _stateMachine.Register(StateType.Fire, new Fire());
    _stateMachine.Register(StateType.Die, new Die());
    //初始状态
    _stateMachine.ChangeState(StateType.Idie);
}   
// Update is called once per frame
void Update () {
    _stateMachine.DoWork();
}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值