• UE4 C++设计模式:状态模式(State Pattern)


    目录

    套路

    使用场景

    优缺点

    UE4实践

    创建状态抽象类(接口)

    创建状态具体类:UBaseStateWidget,作为UI的父类

    创建状态管理类


    描述

    允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类

    其别名为状态对象,状态模式是一种对象行为型模式

    有限状态机

    • 拥有状态机所有可能状态的集合
    • 状态机同时只能在一个状态
    • 一连串的输入或事件被发送给状态机
    • 每个状态都有一系列的状态转移,每个转移与输入和另一状态有关
    • 动画状态机、行为树系统

    并发状态机

    • 有些状态需要并行执行,例如动画状态机,经常分为上半身动画和下半身动画融合,如装备动作、射击动作、换弹动作与行走动作并行

    层次状态机

    • 状态中嵌套子状态,可以使用继承

    下推自动机

    • 用栈来存储一系列状态,有限状态机有一个指向状态的指针,下推自动机有一个栈指针
    • 新状态压入栈中,“当前”状态总是在栈顶
    • 弹出最上面的状态,这个状态就会被销毁,它下面的状态成为新状态,如UI界面管理

    套路

    • 环境类Context,用于改变状态
    • 抽象状态类State
    • 具体状态类ConcreteState

    使用场景

    • 对象的行为依赖于他的状态(属性)并且可以根据它的状态改变而改变它的相关行为
    • 代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便的增加和删除状态,使客户类与类库之间的耦合度强。这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态
    • 示例:
      • OA办公系统中多种状态:尚未办理,正在办理,正在批示,正在审核
      • TCP连接状态
      • 动画系统、AI行为树
      • UI界面管理

    优缺点

    • 优点
      • 封装了转换规则
      • 枚举可能的状态,在枚举状态之前需要确定状态种类
      • 将所有与某个状态有关的行为放到一个类中,并且可以方便的增加新的状态,只需要改变对象状态即可改变对象的行为
      • 允许状态转换逻辑与状态对象合为一体,而不是某一个巨大的条件语句块
      • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数
    • 缺点
      • 状态模式的使用必然会增加系统类和对象的个数
      • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码混乱
      • 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也许修改对应类的源代码

    UE4实践

    切换UI模式

    创建状态抽象类(接口)

    1. UINTERFACE(MinimalAPI)
    2. class UStateInterface : public UInterface
    3. {
    4. GENERATED_BODY()
    5. };
    6. /**
    7. *
    8. */
    9. class DESIGNPATTERNS_API IStateInterface
    10. {
    11. GENERATED_BODY()
    12. // Add interface functions to this class. This is the class that will be inherited to implement this interface.
    13. public:
    14. virtual void EnterState() = 0;
    15. virtual void ExitState() = 0;
    16. };

    创建状态具体类:UBaseStateWidget,作为UI的父类

    1. UCLASS()
    2. class DESIGNPATTERNS_API UBaseStateWidget : public UUserWidget, public IStateInterface
    3. {
    4. GENERATED_BODY()
    5. public:
    6. virtual void EnterState() override;
    7. virtual void ExitState() override;
    8. UFUNCTION(BlueprintNativeEvent,BlueprintCallable,Category="State Pattern")
    9. void OnEnterState();
    10. UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "State Pattern")
    11. void OnExitState();
    12. };
    1. void UBaseStateWidget::EnterState()
    2. {
    3. OnEnterState();
    4. }
    5. void UBaseStateWidget::ExitState()
    6. {
    7. OnExitState();
    8. }
    9. void UBaseStateWidget::OnEnterState_Implementation()
    10. {
    11. AddToViewport();
    12. }
    13. void UBaseStateWidget::OnExitState_Implementation()
    14. {
    15. RemoveFromParent();
    16. }

    创建状态管理类

    1. UCLASS()
    2. class DESIGNPATTERNS_API AUIStateManager : public AActor
    3. {
    4. GENERATED_BODY()
    5. public:
    6. // Sets default values for this actor's properties
    7. AUIStateManager();
    8. protected:
    9. // Called when the game starts or when spawned
    10. virtual void BeginPlay() override;
    11. public:
    12. // Called every frame
    13. virtual void Tick(float DeltaTime) override;
    14. // 改变状态
    15. UFUNCTION(BlueprintCallable, Category = "State Pattern")
    16. void EnterState(TSubclassOf StateWidgetClass);
    17. // 退出所有状态
    18. UFUNCTION(BlueprintCallable, Category = "State Pattern")
    19. void ExitAllState();
    20. // 当前状态实例
    21. UPROPERTY(BlueprintReadWrite, Category = "State Pattern")
    22. UBaseStateWidget* CurrentStateWidget;
    23. private:
    24. // 存储状态实例
    25. TMap, UBaseStateWidget*> WidgetInstances;
    26. };
    1. void AUIStateManager::EnterState(TSubclassOf StateWidgetClass)
    2. {
    3. if (CurrentStateWidget != nullptr)
    4. {
    5. CurrentStateWidget->ExitState();
    6. }
    7. if (WidgetInstances.Contains(StateWidgetClass))
    8. {
    9. CurrentStateWidget = WidgetInstances.FindRef(StateWidgetClass);
    10. }
    11. else
    12. {
    13. APlayerController* PC = UGameplayStatics::GetPlayerController(GetWorld(), 0);
    14. CurrentStateWidget = CreateWidget(PC, StateWidgetClass);
    15. WidgetInstances.Add(StateWidgetClass,CurrentStateWidget);
    16. }
    17. CurrentStateWidget->EnterState();
    18. }
    19. void AUIStateManager::ExitAllState()
    20. {
    21. for (auto& Elem : WidgetInstances)
    22. {
    23. (Elem.Value)->ExitState();
    24. }
    25. }

    4. 状态模式 — Graphic Design Patterns (design-patterns.readthedocs.io)

    状态模式 · Design Patterns Revisited · 游戏设计模式 (tkchu.me)

  • 相关阅读:
    怎么防止360安全卫士修改默认浏览器?
    LabVIEW学习记录 - 实时显示时间
    视频融合云平台EasyCVR进程启动时报错“update cluster server”的排查及解决方法
    韶关517功能水稻测产 国稻种芯-何登骥:中国水稻节广东活动
    STM32控制舵机精准角度
    DevOps系列文章之 Docker-compose
    Leetcode 937. Reorder Data in Log Files (字符串处理题)
    class的get和set
    测试理论: 一个总结和梳理
    .Net 锁的介绍
  • 原文地址:https://blog.csdn.net/Jason6620/article/details/126544065