Unity 设计模式——状态模式

在游戏开发过程中,游戏中的部分对象可能会根据不同的情况做出不同的行为,我们把这种对象称为有状态的对象,而把影响对象行为的一个或多个动态变化的属性称为状态。当有状态的对象与外部事件产生互动时,其内部状态就会发生改变,从而使其行为也发生改变。如人都有高兴和伤心的时候,不同的情绪有不同的行为,当然外界也会影响其情绪变化。

对这种有状态的对象编程,传统的解决方案是:将这些所有可能发生的情况全都考虑到,然后使用 if-else 或 switch-case 语句来做状态判断,再进行不同情况的处理。但是显然这种做法对复杂的状态判断存在天然弊端,条件判断语句会过于臃肿,可读性差,且不具备扩展性,维护难度也大。且增加新的状态时要添加新的 if-else 语句,这违背了“开闭原则”,不利于程序的扩展。

优点

1、封装了转换规则。

2、枚举可能的状态,在枚举状态之前需要确定状态种类。

3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。

4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。

5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点

 1、状态模式的使用必然会增加系统类和对象的个数。

2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。

3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

结构图

 代码示例

 抽象状态类

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

namespace AI.Enemy
{

    public abstract class EnemyState  
    {
        public abstract void Handle(EnemyContext enemyBase);

    }
}

具体状态类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace AI.Enemy
{

    public class EnemyStateWalk : EnemyState
    {
        public override void Handle(EnemyContext enemyBase)
        {
            Debug.Log("我叫:"+enemyBase.EnemyName + "  当前是Walk状态");
        }
    }
}



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace AI.Enemy
{


    public class EnemyStateDeath : EnemyState
    {
        public override void Handle(EnemyContext enemyBase)
        {
            Debug.Log("我叫:" + enemyBase.EnemyName + "  当前是Death状态");
        }

     
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace AI.Enemy
{

    public class EnemyStateAttack : EnemyState
    {
        public override void Handle(EnemyContext enemyBase)
        {
            Debug.Log("我叫:" + enemyBase.EnemyName + "  当前是Attack状态");
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace AI.Enemy
{
    public class EnemyStateIdle : EnemyState
    {
        public override void Handle(EnemyContext enemyBase)
        {
            Debug.Log("我叫:" + enemyBase.EnemyName + "  当前是Idle状态");
        }
    }
}

环境类(Context 类)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace AI.Enemy
{
    public class EnemyContext
    {
        private string enemyName;
        public string EnemyName
        {
            get { return enemyName; }
        }
        /// <summary>
        /// 状态
        /// </summary>
        private EnemyState enemyState;
        /// <summary>
        /// 定义初始状态
        /// </summary>
        /// <param name="enemyState"></param>
        /// <param name="enemyName"></param>
        public EnemyContext(EnemyState enemyState,string enemyName)
        {

            this.enemyState = enemyState;
            this.enemyName = enemyName;
        }
        /// <summary>
        /// 对请求做处理,进入下一个状态
        /// </summary>
        public void Request()
        {
            enemyState.Handle(this);
        }
    }
}

Test类

通过枚举改变目标状态

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


 public enum EnemyStates
{
    Idle,
    Walk,
    Attack,
    Death

}
public class EnemyTest : MonoBehaviour
{
    private EnemyContext enemyBase;
    public EnemyStates enemyStates;

    void Start()
    {

    }

    private void Update()
    {
        switch (enemyStates)
        {
            case EnemyStates.Idle:
                enemyBase = new EnemyContext(new EnemyStateIdle(),transform.name);
                enemyBase.Request();
                break;
            case EnemyStates.Walk:
                enemyBase = new EnemyContext(new EnemyStateWalk(), transform.name);
                enemyBase.Request();
                break;
            case EnemyStates.Attack:
                enemyBase = new EnemyContext(new EnemyStateAttack(), transform.name);
                enemyBase.Request();
                break;
            case EnemyStates.Death:
                enemyBase = new EnemyContext(new EnemyStateDeath(), transform.name);
                enemyBase.Request();
                break;
            default:
                break;
        }
    }
}

最后陈述

当然在这里主要介绍一下状态模式的核心思想,这在游戏开发中是远远不够用的,在游戏中我们一般用有限状态机来实现人物或者NPC的状态管理,有限状态机的核心思想就是使用状态模式编写,这里就不做过多介绍了,在之后的文章里再介绍有限状态机的具体使用和逻辑处理吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值