【问题标题】:Switching between various screens of the same state type?在相同状态类型的各个屏幕之间切换?
【发布时间】:2012-08-12 09:01:27
【问题描述】:

我正在处理的程序的基本结构存在问题。我是一个非常缺乏经验的程序员,试图自学使用多种状态的程序的基础知识。

现在,我有一个非常简单的游戏式程序,它带有一个游戏循环,将事件、逻辑和渲染重定向到我的 StateManager 类,它将状态推送和弹出到 . StateManager 类然后将事件、逻辑和渲染重定向到向量的 back() 上的任何状态。我们的想法是为程序的每个阶段(在这种情况下是一个简单的游戏,包括启动画面、菜单、游戏玩法、死亡画面等)提供各种不同的状态......

但是,我是一个非常新手的编码员(尽我所能去学习),我的程序从第一个状态类开始就遇到了一个基本问题......

我创建的第一个类是 SplashScreenState。基本概念是有一个状态,基本上只显示一系列“启动屏幕图像”(为了举例,让我们说 3),每次用户按下一个键,它切换到下一个图像,并且最后(当没有启动画面图像循环时)切换到下一个状态(菜单状态)。

我的问题是我很难弄清楚如何构建它。最初,我错误地将每个不同的初始屏幕图像视为 SplashScreenState 的一个实例。但是,我认为这样做是不正确的,因为从技术上讲,所有 3 个启动画面都属于同一个“状态”。

所以现在我有两个主要问题:

  • 第一个问题是我不确定如何/在哪里存储所有启动画面图像。如果我想在程序启动时在 3 个不同的屏幕图像之间循环,我应该让它们都成为 SplashScreenState 类的成员吗?还是只为“currentImage”设置一个类成员是否更聪明,并且每次用户点击一个键时,它都会运行一个 load() 函数将下一张图像加载到 currentImage 指针中?制作图像数组或矢量并循环浏览它们会更好吗?我只是不确定...

  • 我的第二个问题是 SplashScreenState 的 eventhandling()。我知道我希望屏幕上的图像发生变化; *image1 -> image 2 -> image 3 -> changeState(menuState).. 这样每次用户按下键盘上的一个键时,它就会切换到下一个启动画面,直到最后一个启动画面,然后它会改变状态到主菜单。我也不确定最好的方法是什么。我是否应该为每个初始屏幕创建一个枚举并通过它们递增(直到它改变状态的最终屏幕)?我还认为,如果我确实将所有各种屏幕存储在一个数组中,那么我可以轻松地通过它们递增,但是那会不会优化,因为所有屏幕都必须始终存储在内存中?

无论如何,我知道这个问题可能是非常基本和无聊的,但不幸的是,我现在就是这样!我没有接受过任何正规的编程教育,而且我一直在自学,所以我真的非常感谢这个网站上提供的所有帮助和专业知识! ^^

谢谢!

【问题讨论】:

  • 这是一个非常好的问题 - 组织得很好,解释得很好,做得很好!

标签: c++ oop events state fsm


【解决方案1】:

您似乎在面向对象和用于处理状态转换的过程范式之间左右为难。另一个建议使用 switch 语句来处理枚举状态更改的答案是一种很好的程序方法。这样做的缺点是,您最终可能会得到一个单一的游戏类,其中包含所有代码和所有多余的特定于状态的数据,用于处理所有可能状态的事件/逻辑/渲染。处理这个问题的面向对象的方法更加简洁,并将它们封装到它们自己独立的状态对象中,可以通过共享接口多态地使用它们。然后,您的游戏类不需要保存用于处理游戏类中所有状态的所有细节,而只需要存储一个状态指针,而不必担心具体状态对象的实现细节。这将处理状态转换的责任从游戏类移到它所属的状态类中。您应该阅读设计模式书籍中的状态/策略模式。处理状态的变化应该是状态对象本身的责任。这是一些阅读:

http://www.codeproject.com/Articles/14325/Understanding-State-Pattern-in-C

http://sourcemaking.com/design_patterns/state

http://sourcemaking.com/design_patterns/state/cpp/1

http://codewrangler.home.comcast.net/~codewrangler/tech_info/patterns_code.html#State

http://en.wikipedia.org/wiki/State_pattern

http://www.codeproject.com/Articles/38962/State-Design-Pattern

引用设计模式和面向模式的软件架构书籍: 基于模式的方法使用代码而不是数据结构来指定状态转换,但在适应状态转换动作方面做得很好。状态模式没有指定必须在哪里定义状态转换。它可以在上下文对象中完成,也可以在每个单独的派生状态类中完成。让状态子类指定它们的后继状态以及何时进行转换通常更灵活、更合适。

您可以选择提前创建状态对象并且从不销毁它们,这在状态变化迅速发生并且您希望避免销毁可能很快再次需要的状态时会很好。另一方面,这可能会带来不便,因为上下文必须保留对所有可能进入的状态的引用。

当将要进入的状态在运行时未知并且上下文不经常更改状态时,最好根据需要创建状态对象并在之后销毁它们。在确定使用哪个时,您需要考虑成本以及转换频率。

【讨论】:

  • 很棒的信息。非常感谢您提供详细的答案和所有链接!我绝对有兴趣学习以更加面向对象的方式工作。现在我的代码真的一团糟,我的类似乎很难了解其他类,我有大量的全局变量,而且我认为过程和面向对象的奇怪组合让我感到困惑(c++ 是我的第一个语言)。 -- 有一件事我仍然有点不清楚:如果我的程序有 3-4 个不同的启动屏幕徽标,每个徽标是否被视为一个状态、SplashScreenState 类的实例或类成员??
  • 我认为您在数组或其他容器中循环遍历它们的想法很好。逻辑似乎很简单。您只是在收到某种类型的输入后才进行转换,对吗?然后该输入可以触发更改图像,一旦您在最后一张图像上,它就可以触发转换。您可以通过在状态模式中包含状态模式来过度设计它,但显然这有点过分。这很简单,可以限制为单个状态对象。
  • 好的,太好了!感谢您的跟进! :) 我想我对从现在开始应该如何处理这个问题有了深刻的理解!
【解决方案2】:

首先很好地解释了您的问题。

游戏中管理启动画面的部分可以通过两种方式工作。您已经检查了问题,其实就是这么简单:

接收输入;设置下一个状态。

所以,例子:

 STATE_SPLASH1
 STATE_SPLASH2
 STATE_SPLASH3
 STATE_TITLE
 STATE_GAME_INIT
 STATE_GAME
 STATE_EXIT

伪代码:

state = STATE_SPLASH1

while (state != STATE_EXIT) 
  ... receive input ...
  ... process events to responders ...
  ... update ...
  ... yadda yadda ...
  switch (state) {
    case STATE_SPLASH1:
      show_splash1()
    case STATE_SPLASH2:
      show_splash2()
    case ..:

    case STATE_TITLE:
      show_title()
    case STATE_GAME_INIT:
      show_loading()
      setup_level()
      setup_characters()
    case STATE_GAME:
      game_update()
    case STATE_EXIT:
      cleanup_and_quit()

另一种方法是将启动画面管理为“游戏状态”,然后将启动画面的状态作为内部状态进行管理。当 splash 没有更多的逻辑可以运行时,将游戏状态设置为下一个。当我在学习的时候,我发现 DOOM 源是一个宝贵的资源和人,它只不过是数百个状态机。 :)

【讨论】:

  • 很好的答案!谢谢!这个方法比较简单,对我来说很有意义。虽然,我想养成学习 OOP 方法的习惯(我一直在努力学习 OOP)。如果我创建了一个 StateManager 类,是否有可能(或智能)让状态管理器类包含这样的结构?再次感谢您的帮助! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-18
  • 1970-01-01
  • 2015-04-15
  • 1970-01-01
相关资源
最近更新 更多