6
\$\begingroup\$

I'm using the Game State Management (GSM) concept in my prototype and I like it very much. One of the screen has a "Game" embeded in it, where all the "good stuff" happens. The menu launching the game works fine, but I'm not sure how I should allow the game to request a screen from the ScreenManager. I'm not talking about a menu screen, but about something contextual to the game.

For clarity's sake, let's say that when I click on a game element (a rendered model for example) I want a screen that asks me what color I want that model to be drawn next. Right now, my game knows that model is "targeted" with the mouse (I use a Ray picking approach).

I looked at the Role-Playing sample to see how they did this, but when their GameScreen handles the keys, to open the inventory for example, it's never contextual to what's actually happening in the GameScreen.

Ideas welcomed!

Edit: The game must also be able to get a feedback or something from the "contextual screen" to get the new model color, for example.

\$\endgroup\$
7
  • \$\begingroup\$ It's not quite clear what you problem is, if any. \$\endgroup\$ Jul 8, 2011 at 12:08
  • \$\begingroup\$ Just highlighted the actual problematic :-) \$\endgroup\$
    – Tipx
    Jul 8, 2011 at 13:14
  • 2
    \$\begingroup\$ I'm pretty sure you do not want that as a state. You just want a UI menu. \$\endgroup\$ Jul 8, 2011 at 13:24
  • \$\begingroup\$ +1 TCD, You want to use an in game UI menu, not use state screens. \$\endgroup\$ Jul 8, 2011 at 13:46
  • \$\begingroup\$ I thought about using GSM's ScreenManager since I want my "popup" window to have transitions, load on top of the game and pause the game in the meantime, but more importantly, I don't want that menu interrupting the Update/Draw cycle. \$\endgroup\$
    – Tipx
    Jul 8, 2011 at 13:46

3 Answers 3

5
\$\begingroup\$

The problem here is that you are trying to get a controlled object (screen you're in) to direct it's controlling object (ScreenManager). Two approaches come to mind:

  1. Adapt the code of the library so that the ScreenManager listens for and acts on custom events fired from the screens it manages. You could send events that carry an instance of class object that you can fill with data every time, and respond accordingly in the ScreenManager.

  2. Define an object with static data members, which you can then reference from any other class. When you want to change state with context, push the context into this central class; fire the request to change; when the change is about to occur, check the central class and act accordingly. I find this approach hackish as I hate relying on statics to hold globally accessible info this way.

When I developed a gamestate system for Disjunction, I got around this by method 1: I explicitly designed the state subsystem to carry data on every transition, informing the new state as to the old state's intent. Whether you do this via events or direct references is up to you. The state pattern is a really easy one to get to grips with -- maybe you should roll your own.

\$\endgroup\$
2
  • \$\begingroup\$ My answer is basically point 1 in this answer. \$\endgroup\$
    – jhocking
    Aug 3, 2011 at 14:58
  • \$\begingroup\$ I've proceeded with something completely different after reading TCD & 3nixios comment, but your point 1 is the way I would do it if I needed a real "state change" for whatever reasons. I know I will later on, but I'm not there yet! Thanks. \$\endgroup\$
    – Tipx
    Aug 5, 2011 at 5:57
3
+50
\$\begingroup\$

A good architecture is keeping the GameState and ScreenManager objects separate so they don't directly know about each other and only indirectly communicate though an EventDispatcher object; ScreenManager registers with EventDispatcher as listening for messages about models being picked, and GameState sends a message to EventDispatcher about a model being picked (along with a parameter for which model was picked).

Going in the other direction is as simple as having ScreenManager dispatch events about buttons being clicked, and GameState listens for messages about buttons being clicked.

Now you can change either the GameState object or the ScreenManager at will and, as long as you don't change the messages each is dispatching/listening to, changing one will never affect the other.

I believe this is the Observer pattern, although frankly my knowledge of design patterns is kinda ad hoc.

EDIT: I misunderstood the question slightly, but I'm not changing my answer because it's still how I would do it. The relationship between the Game object and the ScreenManager in GSM is different from what I originally thought you were talking about, but using an EventDispatcher like this is still how I would pass messages around.

\$\endgroup\$
2
\$\begingroup\$

A simple solution would be to create an InputBoxScreen, ColourPickerScreen etc. all deriving from GameScreen. These would have in the constructor some context object (e.g. your model / object that was clicked on).

It would also have a delegate to run.

When the user made their selection it should run the delegate passing in the context, and the selection, then remove its self from the screen manager.

An example usage below (using generics to strongly type the context object):

//User clicked the model
var colourPickerScreen =
    new ColourPickerScreen<Model>(modelSelected, (context, colourSelected) =>
        {
            context.Colour = colourSelected;
        });

screenManager.AddScreen(colourPickerScreen);

The tricky part is often ensuring that the context/action is still valid when the user makes the selection. e.g. the model still exists.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .