你如何模拟应用程序状态? [英] How do you model application states?

查看:171
本文介绍了你如何模拟应用程序状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个游戏,我想建立一个干净的,面向对象的方式来建模不同的状态(Game Maker的类比将是框架,我猜)。以前,我已经通过以下方式完成了:

  class Game 
{
enum AppStates
{
APP_STARTING,
APP_TITLE,
APP_NEWGAME,
APP_NEWLEVEL,
APP_PLAYING,
APP_PAUSED,
APP_ENDED
} ;

typedef AppState(Game :: * StateFn)();
typedef std :: vector< StateFn> StateFnArray;

void Run()
{
//要在此处注册的StateFn将在

AppState lastState(APP_STARTING);
while(lastState!= APP_ENDED)
{
lastState = GetCycle_(lastState);
}
//清理
}

protected:
//定义StateFn在这里

AppState GetCycle_(AppState a)
{
//根据传递的变量选取StateFn,调用它并返回其结果。
}

StateFnArray states_;
};

这对于一个较小的项目来说几乎不能管理。状态所有使用的变量被转储到Game类中,但是我想要保持面向对象的最大化,只暴露由多个状态共享的变量。我也希望能够在切换到它时初始化一个新状态,而不是在刚刚完成的状态下进行初始化(因为它可能有多个结果 - APP_PLAYING可以切换到APP_PAUSED,APP_GAMEOVER,APP_NEWLEVEL等)。 / p>

我想到了这样的东西(注意!FUZZY STUFF!):

  struct AppState 
{
枚举{LAST_STATE = -1; }
typedef int StateID;
typedef std :: vector< AppState *> StateArray;

static bool Add(AppState * state,StateID desiredID);
//如果需要,则返回false ID是已分配给

的空白static void Execute(StateID state)
{
while(id!= LAST_STATE)
{
// bounds check etc
states_ [id] - > Execute();
}
}

AppState(){};
virtual〜AppState(){};

virtual StateID Execute()= 0; //返回要执行的下一个状态的ID

protected:
static StageArray stages_;
};

这里的问题是类和实例级别变得混乱(静态vs虚拟)。状态需要从AppState继承,但是我可以想像,大部分都是具有全静态成员的类,或至少我不需要一个类的多个实例(TitleState,LevelIntroState,PlayingState ,GameOverState,EndSequenceState,EditorState ... - 暂停不再是一个状态,而不是在有意义的州被照顾)。



如何

解决方案

以下文章给出了一种很好的简单的管理游戏状态的方法:



http://gamedevgeek.com / tutorials / manage-game-states-in-c /



基本上,你维护一堆游戏状态,只是运行最高状态。你是对的,许多州只会有一个实例,但这不是一个真正的问题。实际上,你说的很多州可能有多个实例。例如:

  push TitleState 
push MenuState
push LevelIntroState
change_to PlayingState
change_to GameOverState
pop(返回MenuState)

...你可以重新开始一个新的实例 LevelIntroState ,等等。


I'm writing a game, and I want to model its different states (the Game Maker analogy would be frames, I guess) in a clean, object-oriented way. Previously, I've done it in the following way:

class Game
{
  enum AppStates
  {
    APP_STARTING,
    APP_TITLE,
    APP_NEWGAME,
    APP_NEWLEVEL,
    APP_PLAYING,
    APP_PAUSED,
    APP_ENDED
  };

  typedef AppState(Game::*StateFn)();
  typedef std::vector<StateFn> StateFnArray;

  void Run()
  {
    // StateFn's to be registered here

    AppState lastState(APP_STARTING);
    while(lastState != APP_ENDED)
    {
      lastState = GetCycle_(lastState);
    }
    // cleanup
  }

protected:
  // define StateFn's here

  AppState GetCycle_(AppState a)
  {
    // pick StateFn based on passed variable, call it and return its result.
  }

  StateFnArray states_;
};

This was hardly manageble for a smaller project. All the variables that the states were using were dumped in the Game class, however I'd want to keep object-orientedness to a maximum, only exposing variables that are shared by more than one state. I also want to be able to initialize a new state when switching to it rather than having to do it in the state that's just finishing (as it might have multiple outcomes - APP_PLAYING can switch to APP_PAUSED, APP_GAMEOVER, APP_NEWLEVEL, etc.).

I thought of something like this (CAUTION! FUZZY STUFF!):

struct AppState
{
  enum { LAST_STATE = -1; }
  typedef int StateID;
  typedef std::vector<AppState*> StateArray;

  static bool Add(AppState *state, StateID desiredID);
  // return false if desiredID is an id already assigned to

  static void Execute(StateID state)
  {
    while(id != LAST_STATE)
    {
      // bounds check etc.
      states_[id]->Execute();
    }
  }

  AppState() {};
  virtual ~AppState() {};

  virtual StateID Execute() =0; // return the ID for the next state to be executed

protected:
  static StageArray stages_;
};

The problem here is that the class and instance levels are getting jumbled up (static vs virtual). The states need to inherit from AppState, but - how I'd imagine - most of them would be classes with all-static members, or, at least I won't need more than one instance from one class (TitleState, LevelIntroState, PlayingState, GameOverState, EndSequenceState, EditorState... - pausing would no longer be a state, rather than being taken care of in the states where it makes sense).

How can it be done elegantly and efficiently?

解决方案

The following article gives a nice, simple way to manage game states:

http://gamedevgeek.com/tutorials/managing-game-states-in-c/

Basically, you maintain a stack of game states, and just run the top state. You're right that many states would only have one instance, but this isn't really a problem. Actually, though, many of the states you're talking about could have multiple instances. E.g.:

push TitleState
push MenuState
push LevelIntroState
change_to PlayingState
change_to GameOverState
pop (back to MenuState)

... and you can start over with a new instance of LevelIntroState, and so on.

这篇关于你如何模拟应用程序状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆