首页 > 其他分享 >Unity 设计模式-状态模式(State Pattern)详解

Unity 设计模式-状态模式(State Pattern)详解

时间:2024-12-01 11:29:36浏览次数:9  
标签:状态 角色 Pattern void character Character State 设计模式 public

状态模式(State Pattern)

状态模式(State Pattern) 是一种行为型设计模式,它允许一个对象在其内部状态发生改变时改变其行为。状态模式将与状态相关的行为封装在独立的状态类中,系统在运行时根据状态的变化来切换不同的行为。

通过状态模式,状态转换和行为执行得到了很好的分离,符合面向对象设计的单一职责原则,即每个类只负责一项具体的职责。

状态模式的结构

  • 上下文类(Context Class):维护当前状态的引用,负责在运行时根据状态的变化调用不同的状态类的行为。
  • 状态接口(State Interface):定义状态类的共同行为,这通常是一个抽象类或接口。
  • 具体状态类(Concrete State Class):实现状态接口,提供每个状态下具体的行为。


1、什么时候使用状态模式

  • 对象的行为依赖于状态变化时,并且行为会随着状态的不同而发生变化。
  • 对象的状态变化频繁,而且状态之间的切换逻辑复杂,状态模式可以很好地管理这些状态。
  • 状态转换具有规律性,每个状态都有固定的行为模式或规则,状态模式可以简化这种逻辑。
  • 需要避免使用大量条件判断来实现不同状态下的行为时,状态模式是一个更优雅的解决方案。

2、使用状态模式的好处

  • 简化条件判断逻辑:通过将状态转换逻辑封装到各个具体状态类中,状态模式避免了大量的 if-else 或 switch 语句,代码更清晰。
  • 增强系统的扩展性:状态模式将状态相关的行为封装到独立的类中,因此添加新的状态或修改现有状态的行为不会影响其他代码,符合开闭原则。
  • 使状态行为与上下文解耦:上下文类仅负责状态的切换,而具体的行为由状态类来实现,保持了上下文类的简洁。
  • 提高代码可维护性:状态类各自独立,便于测试、调试和维护。

3、使用状态模式时的注意事项

  • 状态类的数量增加:状态模式的一个潜在问题是状态类的数量可能会随着状态的增多而增加,导致类过多。此时需要评估是否有必要使用状态模式,还是可以通过其他方式优化。
  • 上下文和状态类的依赖:虽然状态模式将状态行为独立出来,但状态类与上下文之间的相互引用可能导致依赖复杂性,需要控制好状态类的职责。
  • 状态转换规则复杂时:如果状态之间的转换规则非常复杂,可能需要将转换逻辑从具体状态类中抽离,避免具体状态类中的代码变得过于庞大。

在 Unity 中使用 状态模式

在 Unity 中,状态模式可以很好地用于角色的状态管理,例如角色的运动状态、攻击状态、死亡状态等。我们可以通过状态模式将这些行为封装在不同的状态类中,使得角色能够根据当前状态动态切换行为。

  • 下面我们使用状态模式,实现一个角色可以在站立、行走、奔跑和跳跃状态之间切换的示例

参考类图如下:

1、定义状态接口

我们首先定义一个接口 ICharacterState,每个具体的状态类都需要实现该接口。

public interface ICharacterState
{
    void HandleInput(Character character);
    void UpdateState(Character character);
}
2、具体状态类

根据不同的角色状态(站立、行走、奔跑、跳跃),我们为每个状态创建一个具体的类。每个状态类都实现了 ICharacterState 接口。

using UnityEngine;
 
// 站立状态类
public class StandState : ICharacterState
{
    public void HandleInput(Character character)
    {
        if (Input.GetKeyDown(KeyCode.W))
        {
            character.SetState(new WalkState());
        }
    }
 
    public void UpdateState(Character character)
    {
        Debug.Log("角色正在站立");
    }
}
 
// 行走状态类
public class WalkState : ICharacterState
{
    public void HandleInput(Character character)
    {
        if (Input.GetKeyDown(KeyCode.R))
        {
            character.SetState(new RunState());
        }
        else if (Input.GetKeyDown(KeyCode.Space))
        {
            character.SetState(new JumpState());
        }
    }
 
    public void UpdateState(Character character)
    {
        character.transform.Translate(Vector3.forward * 2f * Time.deltaTime);
        Debug.Log("角色正在行走");
    }
}
 
// 奔跑状态类
public class RunState : ICharacterState
{
    public void HandleInput(Character character)
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            character.SetState(new JumpState());
        }
    }
 
    public void UpdateState(Character character)
    {
        character.transform.Translate(Vector3.forward * 5f * Time.deltaTime);
        Debug.Log("角色正在奔跑");
    }
}
 
// 跳跃状态类
public class JumpState : ICharacterState
{
    public void HandleInput(Character character)
    {
        // 空中不允许其他输入
    }
 
    public void UpdateState(Character character)
    {
        character.transform.Translate(Vector3.up * 5f * Time.deltaTime);
        Debug.Log("角色正在跳跃");
        // 跳跃结束后返回站立状态
        character.SetState(new StandState());
    }
}
3、上下文类

接下来定义上下文类 Character,它维护当前的状态,并通过 SetState() 方法进行状态的切换。

using UnityEngine;
 
public class Character : MonoBehaviour
{
    private ICharacterState currentState;
 
    void Start()
    {
        // 初始化状态为站立
        currentState = new StandState();
    }
 
    void Update()
    {
        // 处理输入并更新状态
        currentState.HandleInput(this);
        currentState.UpdateState(this);
    }
 
    // 切换状态
    public void SetState(ICharacterState newState)
    {
        currentState = newState;
    }
}
4、使用场景中的角色

在 Unity 场景中,我们可以将此状态系统应用到一个角色对象上,比如一个 3D 模型。使用状态模式,角色将根据输入切换行为,比如从站立到行走,再到奔跑或跳跃。

创建一个新的脚本 GameController 来管理和初始化角色。

using UnityEngine;
 
public class GameController : MonoBehaviour
{
    public GameObject characterPrefab;
    private Character character;
 
    void Start()
    {
        // 初始化角色对象
        GameObject characterObject = Instantiate(characterPrefab);
        character = characterObject.AddComponent<Character>();
    }
    
}
5、在 Unity 中运行

创建一个空的 Unity 场景,放置一个 3D 角色(立方体、模型等)作为 characterPrefab。
添加 Character 和 GameController 脚本到 Unity 场景。
在游戏运行时,角色会根据键盘输入(W 切换到行走状态,R 切换到奔跑状态,空格键切换到跳跃状态)来切换不同的行为。


6、示例分析
  • 初始状态为站立:当游戏开始时,角色默认处于站立状态。此时控制台输出“角色正在站立”,并且没有移动。
  • 切换到行走状态:当玩家按下 W 键时,角色进入行走状态,角色开始向前移动,控制台输出“角色正在行走”。
  • 切换到奔跑状态:按下 R 键,角色从行走状态切换到奔跑状态,移动速度加快,控制台输出“角色正在奔跑”。
  • 切换到跳跃状态:按下空格键,角色进入跳跃状态,角色向上移动,跳跃结束后角色自动返回站立状态。

状态模式在 Unity 中非常适用于处理角色的状态转换。例如,角色的运动状态、游戏中的敌人 AI 状态等。通过将每个状态的行为封装成独立的类,我们可以灵活地进行状态切换并保持代码结构的清晰与可扩展性。

  • 简化了复杂的状态管理:避免使用大量的 if-else 或 switch-case 语句,减少了冗余代码。
  • 高可扩展性:当需要添加新的状态时,只需要新建一个状态类即可,不会影响现有的代码。
  • 增强了代码的可维护性:各个状态之间相互独立,符合单一职责原则,每个状态类只负责处理特定状态下的行为。

今天是2024年11月25日

重复一段毒鸡汤来勉励我和你

你的对手在看书

你的仇人在磨刀

你的闺蜜在减肥

隔壁的老王在练腰

而你在干嘛?

标签:状态,角色,Pattern,void,character,Character,State,设计模式,public
From: https://blog.csdn.net/qq_34800671/article/details/144029560

相关文章

  • Pattern: Service Mesh
     https://philcalcado.com/2017/08/03/pattern_service_mesh.html Sincetheirfirstintroductionmanydecadesago,welearntthatdistributedsystemsenableusecaseswecouldn’teventhinkaboutbeforethem,buttheyalsointroduceallsortsofnewissue......
  • TYUT设计模式精华版
    七大原则单一职责原则职责要单一不能将太多的职责放在一个类中开闭原则软件实体对扩展是开放的,但对修改是关闭的里氏代换原则一个可以接受基类对象的地方必然可以接受子类依赖倒转原则要针对抽象层编程,而不要针对具体类编程接口隔离原则使用多个专门的接口来取......
  • Flink四大基石之State(状态) 的使用详解
    目录一、有状态计算与无状态计算(一)概念差异(二)应用场景二、有状态计算中的状态分类(一)托管状态(ManagedState)与原生状态(RawState)两者的区别具体区别管理方式数据结构支持使用场景(二)托管状态细分 KeyedState和OperatorStateKeyedState(键控状态)按键分区状态(Ke......
  • Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
    背景事件:近日,优衣库宣布不再使用新疆棉花,这一举措引发了广泛的社会讨论。消费者的反应和舆论的压力,让优衣库的决策迅速影响了市场和品牌形象。类似的,许多系统也面临着需要根据外部事件或状态的变化,做出即时反应的需求。在软件设计中,观察者模式(ObserverPattern)就是为了处理这种......
  • [Vue] Sharing State
    ......
  • Java设计模式——职责链模式:解锁高效灵活的请求处理之道
    嘿,各位Java编程大神和爱好者们!今天咱们要一同深入探索一种超厉害的设计模式——职责链模式。它就像一条神奇的“处理链”,能让请求在多个对象之间有条不紊地传递,直到找到最合适的“处理者”。准备好跟我一起揭开它神秘的面纱,看看如何用代码实现这种强大的模式,让我们的程序变得更......
  • 设计模式-代理模式
    概念:代理模式是结构型模式之一,代理对象代替委托对对象完成业务功能,在委托对象完成功能前后可以做增强或限制。最典型的例子如:aop底层原理现实中的例子如:如房屋中介和房东的关系:房东提供房源,中介去进行售卖和出租,期间房东不做任何业务功能,但是最终本质上还是售卖和出租的是房东的......
  • 设计模式学习之——策略模式
    策略模式(StrategyPattern)是一种行为型设计模式,它允许定义一系列算法,并将每个算法封装在独立的类中,使它们可以互相替换。策略模式通过将算法的使用与算法的实现分离,使得算法可以独立于客户端而变化。一、策略模式的核心思想策略模式的核心思想是面向接口编程,而不是面向实现编......
  • [React]setState调用过于频繁的问题
    来自:文心一言在React中,如果setState被调用得太频繁,可能会出现状态没有按预期更新的情况。这是因为React为了性能优化,会批量更新状态,即便是连续快速调用setState,最终状态的更新仍会在一次渲染中执行。如果你尝试在某些异步操作(如事件监听器、网络请求或循环中)中连续多次调用setSt......
  • 设计模式概述
    设计模式(Designpattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码......