有限状态机&抽象类多态 勇士传说3.4笔记

麦扣老师《勇士传说》教程

⬆️麦扣老师教程中的设计模式 - 有限状态机&抽象类多态笔记

类的继承

子类可以使用父类的变量和函数方法,也可以通过override重写父类中的方法。

状态机

包含了状态进入、状态持续中、状态退出等需要执行的内容。

教程之前写的HurtAnimation就是继承自StateMachineBehavior状态机,这就是一个抽象类。

抽象类

  • 使用Abstract声明。
  • 里面所有的方法都是(virtual)虚的方法,可以被重写。
  • 抽象类中的方法只需要声明,不写实现。必须在继承抽象类的类中实现。

教程中举了个披萨的例子:

  • 父类继承:我要做披萨,每个披萨都要用写好的饼皮,然后往上加配料。
  • 抽象类:规定你必须要有饼皮,但不限制饼皮的实现,用什么材料,是厚皮还是薄皮等。

有限状态机

一个物体在一段时间、一定条件下只执行一个状态,不会同时有其他状态影响。比如,巡逻状态下,不会有追击状态同时执行。

抽象类状态机的写法

不继承M ono Behavior(也就是不能挂在unity场景物体中)

使用Abstract声明。内部定义必须要使用的函数方法(是abstract类型)

public abstract class BaseState
{
    public abstract void OnEnter();
    public abstract void LogicUpdate();
    public abstract void PhysicUpdate();
    public abstract void OnExit();
}
  • OnEnter() -状态进入时的要执行的。
  • LogicUpdate()-逻辑判断。将放在Enemy的update中,持续进行所有的逻辑判断。
  • PhysicUpdate() -fixupdate中做物理逻辑判断。
  • OnExit() -退出状态。

为什么StateMachine Behavior中用virtual,此处却用abstrat?

因为StateMachine Behavior继承了scriptable object?

创建野猪巡逻的逻辑BoarPatrolState,继承BaseState抽象类

必须实现抽象类中的方法!

在需要调用状态机的代码文件中创建BaseState类型的变量

    protected BaseState currentState;
    protected BaseState ChaseState;
    protected BaseState patrolState;    
    private void OnEnable()
    {
        currentState = patrolState;
        currentState.OnEnter();
    }
    private void Update()
    {
        currentState.LogicUpdate();
    }    
    private void FixedUpdate()
    {
        currentState.PhysicUpdate();

    }    
    private void OnDisable()
    {
        currentState.OnExit();
    }

有限状态机-巡逻状态PatrolState

 状态的进入

在野猪自己的awake中,为patrolState赋值,new一个野猪巡逻状态机

  • Enemy.cs
    protected virtual void Awake()
  • Boar.cs
public class Boar : Enemy
{
    protected override void Awake()
    {
        base.Awake();
        patrolState = new BoarPatrolState();
    }

}

巡逻进行时

物理检测撞墙、到悬崖等待后转身

在当前的状态中调用对应的Enemy代码中的方法

在BaseState中创建Enemy类型的变量currentEnemy来保存当前对应的Enemy即可。对应的实现也要进行修改。

  • BaseState.cs
    protected Enemy currentEnemy;

    public abstract void OnEnter(Enemy enemy);
  • BoarPatrolState.cs
    public override void OnEnter(Enemy enemy)
    {
        currentEnemy = enemy;
    }    
  • Enemy.cs
    private void OnEnable()
    {
        currentState = patrolState;
        currentState.OnEnter(this);
    }

原本的代码移动到状态机中。如果要使用Enemy中的变量,需要修改访问权限为public,再通过currentEnemy变量实现调用。不想在inspector中暴露的变量,在定义最前面标注[HideInInspector]。

  • BaseState.cs
public override void LogicUpdate()
    {
        //发现player之后切换到chase状态

        //撞墙或到达悬崖进入等待,停止播放walk动画
        if (!currentEnemy.physicCheck.isGround ||(currentEnemy.physicCheck.touchLeftWall && currentEnemy.faceDir.x < 0) || (currentEnemy.physicCheck.touchRightWall && currentEnemy.faceDir.x > 0))
        {
            currentEnemy.wait = true;
            currentEnemy.anim.SetBool("walk", false);
        }        
else
        {
            currentEnemy.anim.SetBool("walk", true);
        }
    }

我都这样写了为什么猪还会掉落悬崖!

因为Enemy.cs的fixupdate中,持续执行了Move()。那怎么加判断让他别动了?

重新说明一下逻辑:在LogicUpdate中,检测碰到悬崖、墙壁之后先设置进入等待,不播放walk动画(walk=false),等待时间结束后转身。所以,设置等待(wait=true)时,也不能执行Move()。

private void FixedUpdate()
    {
        if (!isHurt && !isDead && !wait) 
        {
            Move();
        }
        currentState.PhysicUpdate();
    }

状态的退出

  • BoarPatrolState.cs
    public override void OnExit()
    {
        currentEnemy.anim.SetBool("walk", false);
    }

我的猪为什么每次启动都要等两秒?

发现每次启动时,wait都会置为true。

那么找到将wait置为true的那一段,也就是在判断时,猪不在地上/撞墙。。所以。。是猪在scene编辑窗口中的位置不在地面上。。所以在编辑器里把野猪的isGround勾选上就好了

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值