在相同状态类型的各种屏幕之间切换?

时间:2012-08-12 09:01:27

标签: c++ oop events state fsm

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

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

然而,我是一个非常新手的编码器(尽力学习),而且我从第一个州级课程开始遇到一个基本的问题...

我创建的第一个类是SplashScreenState。并且基本概念是具有基本上仅显示一系列“闪屏图像”的状态(例如,为了示例),并且每次用户按下键时,它切换到下一图像,并且最后(当它没有飞溅屏幕图像循环时)切换到下一个状态(menustate)。

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

现在我有两个主要问题:

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

  • 我的第二个问题是SplashScreenState的eventhandling()..我知道我希望屏幕上的图像改变像; * image1 - >图像2 - >图像3 - > changeState(menuState)..因此,每次用户点击键盘上的键时,它都会切换到下一个闪屏,直到最后一个闪屏,然后它会将状态更改为主菜单。我不确定这样做的最佳方式是:我应该为每个启动画面创建一个枚举并通过它们递增(直到它改变状态的最终屏幕)?我还认为,如果我将所有不同的屏幕存储在一个数组中,那么我可以很容易地通过它们增加,但那样会不会优化,因为所有屏幕都必须始终存储在内存中?

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

谢谢!

2 个答案:

答案 0 :(得分: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

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

您可以选择提前创建状态对象并且永远不会破坏它们,这可能在状态变化快速发生时很好,并且您希望避免破坏可能需要的状态。另一方面,它可能不方便,因为上下文必须保持对可能输入的所有状态的引用。

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

答案 1 :(得分:1)

首先要解释你的问题。

管理启动画面的游戏部分可以通过两种方式运行。你已经检查了这个问题,它真的很简单:

接收输入;设置下一个州。

所以,例子:

 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源是一个宝贵的资源和人,只不过是数百台状态机。 :)