Showing posts with label patterns. Show all posts
Showing posts with label patterns. Show all posts

Monday, April 19, 2010

Menu State Management in Games

I've written about high-level game state management before, but I didn't provide any direct code. I got a couple questions about this recently, so I decided to put a post together.

Menu management is a very clear example of the State pattern. Each different page in the menu is a different concrete subclass derived from a common State base class and managed by a Context. There's a few tricks that make this a bit easier.
For example, menus are often nested. This suggests using a Stack pattern for the context. I generally have a GameContext class that has Push, Pop, and Switch methods. They can either take a State subclass instance as a parameter, or some sort of identifier. I think this choice is 50-50; I don't have a clear preference for either one.

There's two ways of doing identifiers. Again, I don't have a clear preference here either. I tend to switch back & forth between these two solutions. (1) Add an ID in the class itself, e.g.
  public static const MainMenu::kMenuId = 'main';
This tends to be the less error-prone, although it does mean that you've got to add an extra #include (in C++), and whatever language you use it means another dependency. (2) Use a string constant. C++ compilers tend to tolerate four-character codes, ie
  Context.Switch( 'main' ); 
The downside is that if you change the identifiers or add a new menu or have a typo, you run the risk of the system blowing up at runtime. However you might choose to do the identifiers, you also need a way to register them with the Context, and that adds another layer of complexity. So your choice is: that complexity, or require any class that requests a menu state change to refer to the new menu class -- which can get messy itself. Meh? All coding is tradeoffs. Pick one. Whatever your feelings on Good and Proper Coding Practices, neither one has been proven to cause cancer in lab rats.

The Context itself also tends to be an instance of the Singleton pattern, with some public, global access. Pop, Push, and Switch might be static methods, for example; I find that means less code and complexity on the client side. (Never trust anyone using your class to be able to code their way out of a paper bag! Simpler interfaces are better.)

I usually start with a simple, copy-n-pasted examples of the different Menu classes. For example, they'll have their own Scenes for 3D objects and 2D UI bits. This is usually easier, faster, and more reliable than trying to develop the Most Awesomest Generic Menu Class Ever. The UI manager will take button clicks, and then call Context.Switch() or Pop() as needed, or Push() if the user hits the 'previous menu' button.

Game startup, then, will do stuff like initialize the 3D environment, game asset libraries, sound, etc, then start up the game state context and tell it which State to start with, which is often a CompanyLogoState. Usually I have game startup then call Context.Run, which does a simple loop of CurrentState.HandlePendingEvents, CurrentState.Draw, and CurrentState.Tick. There's some complexity there with handling events, being able to handle Push and Pop, updating the state at the right time, etc.

CompanyLogoState.Tick() will usually draw a 2D company logo, gradually brightening from black to white, holding, then back to black. When it gets to black, Tick() will call Context.Switch( GameTitleState.kStateId ), which pops the CompanyLogo off the stack and puts GameTitle in its place. That state does the same thing -- bring up the lights, so the title screen, then switch to the Main Menu state. Both the CompanyLogo and GameTitle states will move on to the next state if a key is pressed; that's done in their HandlePendingEvents() method. Eventually, one of the various Menu states (MainMenu, PlayGameMenu, LoadSavedGameMenu / StartNewGameMenu, etc etc) will need to actually start the game. That's cake: just have it call Context.Push( GameState.kMenuId ). And if the game needs to switch to a full-screen menu at some point, it can pause itself and push a new state onto the stack: Context.Push( SaveGameMenu.kMenuId ). Of course it will be important to plan out all of your various menus and states, and make sure you don't have any recursive loops.

Using this pattern, all of the various high-level states in the game are handled through the Context, which also does event handling and rendering. I've even once modified the process to work in a nested window as well - such as when you bring up the 'game menu' while a game is in progress, which doesn't back out into a full-screen menu but instead shows the game in the background, paused & faded.

As with any code, start simple. Copy n paste as needed. When you need more complexity, well-written code is easy to extend.

Thursday, March 25, 2010

Adapter Pattern vs Proxy Pattern

These are two similar patterns that both wrap an object (or set of objects) to expose slightly different behavior to a client object. As with the difference between Bridge and Strategy patterns, the difference between an Adapter and a Proxy is partly one of focus; which pattern you use does not necessarily change the structure of your solution, but the choice depends on how you approach the problem. Both patterns are wrappers, but you use the two patterns for very different reasons.

Some of the confusion that I've seen between these two patterns is one of nomenclature. I was talking to a friend today (hence the reason for this post) where he got into an argument with someone, and the basic cause of confusion was between the idea of a class (any class) as a 'proxy' for a data object and the Proxy pattern itself. As for the Adapter pattern and the verb 'adapt' -- well, every line of code is an adaptation, right? It's a pretty generic verb.

So: Most of the confusion is proxy vs Proxy. I'm using the latter, the capitalization, to indicate the Design Pattern.

Adapter

Common descriptions of the Adapter pattern tend to say that it's an extension of the Facade pattern to deal with polymorphism or to provide a specific interface. Yeah, that's nice. In practice, when I'm getting my hands dirty writing code, I use the Adapter pattern when I am approaching the problem from the client end - as the user of the class that's about to be adapted, not as the author of the library or utility class that winds up getting adapted.

Usually what happens is that I'm writing a bit of code and I start to implement an algorithm when I realize that I can use a certain library class to do the job instead. But the class I'm working in demands a certain interface! Rather than rewriting the algorithm using that interface, I instead glue the library class in. And that, really, is all that an Adapter is: it's an implementation of an interface that doesn't do any of the work itself -- it just passes the calls along to some other, existing class.

It retrospect, you can see that you have Adapted the library class to the new interface.

Proxy

Proxies, on the other hand, tend to do work. Real work. Usually I create a proxy knowing exactly what it is that I want to do. I need a client-side representation of a server object, or a class to represent some big, unwieldy system object that I'm really only going to provide some minor methods on (and hence don't need to instantiate the whole thing). My proxy looks like the real object, but only provides the methods needed locally -- and so only has the complexity to do that limited work.

Often Proxies are one-to-one wrappers; you'll have two classes to represent the object. One class (the non-proxy, usually written first) represents the underlying data, and the Proxy wraps that class to add some specific, narrow behavior.

A proxy might exist across a network connection; it might represent a view into a data object, or a partial instance of a large data file, or maybe it just provides some functions that would be expensive or complex to access directly. I often write proxies to do one simple thing to a more complex class. Instead of making some class more complex, the Proxy steps in.

Which is Which?

In some cases the distinction is obvious. In a client-server application, you might write a client Proxy for a server-side object. You might gate calls to a complex central system through a Proxy, which will provide transaction ordering or synchronous behavior or somesuch. If you need to shove Tab A into Slot B and a simple pass-through class will do, that's an Adapter.

But say you want to write a class to encapsulate OS-level calls to the file system. Is that an Adapter or a Proxy? It's pretty simple, like a pass-through, so it's an Adapter, right? But an object of that class is treated like the underlying object, so is it a Proxy for the actual file on disk?

This is one of the cases where normal pattern use breaks down. Such a class is both a proxy and an adapter. A file object is a proxy for the actual file, but the class itself adapts the OS library calls to your custom project/application/module.

And so it doesn't really matter what you call it. The confusion comes because 'proxy' can be used to refer to the pattern itself (in which a class does work to hide complexity or extract specific behavior) or to an object that represents some real data object. One might say that every data-object instance in your application is a proxy. The concept of proxy still holds independent of the jargon that us OO design-pattern wonks use. Any class can be a proxy - even an Adapter class.

But note that you wouldn't normally have a Proxy that 'adapts' to anything. The Proxy pattern might 'adapt' something, but if the class you write is an Adapter, it might be a proxy but it won't be a Proxy.

As I said above, when I write an Adapter, I know it; the problem in front of me is fairly clear: "I need to shove this old/library class into this custom interface." And when I write a Proxy, it's clear that I'm providing specific new behavior.

Thursday, June 18, 2009

Builder Pattern vs Factory Pattern

Versus

The builder pattern is appropriate when object creation is more complex than just calling a constructor. The factory pattern is appropriate when you have a hierarchy of created objects and you want to abstract the mapping of creation parameters to a subclass.

These patterns are often used together. Many abstract factories that I've written use builder functions. Sometimes I'll put the builder function into a base class -- which means that I have a builder function that is actually an abstract factory, which might itself use builder functions.

Now for more detail:

Builder

A Builder encapsulates complex creation into a single method (or class). If creating an object is more complex than just calling the constructor, then all of the work that goes into creating the object can be moved into one method, and that method is the Builder. 'Builder' implies only one type of created object, but that is not necessarily so. Builder really just means encapsulating complex construction!

Say that you want a Widget object, and that creating one means making a DB query or loading something from disk, constructing the object (passing in the query results), then making a few more calls to set up the object before it can be used.

Instead of copying and pasting that creation code -- query, construction, setup -- every time you need to create a Widget, you move all of that crap into a single function. The Widget constructor probably takes a whole bunch of parameters; maybe those come from the database query. Maybe the Widget uses multi-phase construction. The Builder pattern helps hide all that.

If the setup and configuration isn't really part of the created class, ie if it doesn't make sense for that class to know about all the other crap that needs to be done, the builder function might go somewhere else. I think 9 times out of 10 my builder functions are static methods in the created class itself. Instead of calling the constructor I call the builder function, and probably make the constructor private.

I usually use builder functions, not builder classes. The separate functions in a builder class might each return the same object just with different configurations, or each function might return different subclasses.

In languages where multi-phase construction is the norm (instantiate an object then make a bunch of function calls to fill it out), refactoring the construction steps into its own method is an instance of the Builder pattern!

Factory

A factory can create several different types of objects, but it returns its objects via an interface (or base class) reference. Whereas a Builder encapsulates complex construction steps, a Factory encapsulates the decision-making that figures out which specific subclass to instantiate.

Factories are accessed through a single method; that's really the point. You call one function, and it creates either a Subclass1 or a Subclass2, returning it via IBaseClass.

The Gang of Four book (Design Patterns) names both a Factory Method pattern and an Abstract Factory pattern.

In the Factory Method pattern, the factory function is virtual, and different subclasses of the creating class return different subclasses of the created class. That is, you call one class (the factory) to instantiate the second class (the created). The factory class is actually a tree - base class and subclasses. You'll have something like:
virtual ICreated* IBaseFactory::Create(...params...)
So you have two class trees: the factories and the created objects. The two trees might be parallel, ie CFordFactory::CreateSedan returns an instance of CTaurus, and CNissanFactory returns CMaxima, etc etc. Or, the two trees might be disjoint: CFryingPan and CMicrowave return an instance of CFood, while CBlender returns an instance of CDrink (where both presumably derive from IConsumable).

You'll most likely use the Factory Method pattern when you have one hierarchy (the created objects), you're about to instantiate a whole bunch of objects, and you don't want to do a switch or if/else/else trees. So you move the creation into a new class tree, instantiate the factory subclass you want, and then use a method to create your objects.

Alternately, you might have a class that creates a bunch of objects, but that class is part of a hierarchy. Depending on which specific subclass you have, you'd get different created objects. That's the Factory Method pattern.

In the Abstract Factory pattern, you've actually got a set of factory methods. A food factory method, one for drinks, one for dishware, etc. More realistically, you might have a factory method for buttons, one for checkboxes, etc, where different factory subclasses create different appearances. In a game, you might have a barracks that will create an infantry, cavalry, and ranged unit, with different factories for each player race. Instead of disjoint classes for each type of unit, one class (IBarracks) will have three methods to create IInfantry, ICavalry, and IRanged units.

Besides subclassing, your abstract factory could be run off of some other logic. The factory function could do some magic to figure out which subclass to create. It could switch off of a parameter:
ICreated MyAbstractFactory.Create( Enum paramEnum )
or it could use static data or other state to decide:
ICreated MyAbstractFactory.Create()
Abstract Factory is a funky pattern. To use it, you'll want to be creating a matched set of objects. If you find yourself wanting to do that, Abstract Factory is your pattern.

see also
Bridge Pattern vs Strategy Pattern
Ownership, Aggregation, and Composition

Saturday, August 2, 2008

Ownership, Aggregation, and Composition

Object Oriented Programming has a lot of associated jargon. You don't need to know the jargon to be a good architect, but understanding the concepts is important.

Short Form: composition is when class A owns an instance of class B; aggregation is when class A contains a pointer to class B (ie as a member variable), but doesn't own it. (Ownership implies that when the owner is destroyed, it will delete its ownees.)

Problem

There's lots of other sites that explain these things. Do they do a good job? I don't think so. I think most of them are targeted at either someone that knows nothing about OO, or someone that knows it fairly well but just wants a refresher. Like me. What's the difference between aggregation and composition again? Oh, composition is when you own the object, yeah, ok... If you aren't familiar with these concepts, then go read up on OO. I'm assuming that you've run across them before, and most likely distinguish between these two when you're writing code.

It's the sort of thing that's almost automatic, if you've learned to avoid pitfalls. Ownership is an important concept because of memory leaks. In C++, you've also got to be wary of dangling pointers and double-deletion. Back (in the olden days) when I was writing C++, I was always very careful to mark which class owned a given object.

In complex projects (especially games) you often have a ton of different objects which each have to reference the same thing. Bullets are fired by players, need to be drawn, create visual effects, collide with world geometry, etc. And in order to optimize several subsystems -- graphics and physics being two time-intensive subsystems -- you might have arcane container types. So how do you keep everything in order?

Solution

The answer is explicit ownership. Make it clear, to yourself and to whomever else is using the code. Put it in comments in the code, probably at the variable declaration and also in the header file for the contained class. If you scribble a diagram up on your whiteboard, make sure you're marking ownership clearly. Have only one owner.

Stay away from two owners. Good architectures would be having one clear owner, or having many owners -- like five, or twenty. In the latter case, you'd use reference counting or some other scheme to control deletion, such as using a globally-accessible (ie Singleton) container or manager or cache for those objects.

Sometimes the problem is something like this: bullets belong to players, but are aggregated within some class in the graphics system. But then a player logs out, the player object gets deleted, and now the graphics system has an empty pointer. Do you reference count this object? Do you keep the player object around (even after the player has logged) until all associated objects are deleted? This latter solution is why you often see players still in the game after their connection has died -- it's not so much an issue of the game not noticing the player has disconnected as the code doesn't want to delete the object yet.

Usually the cleanest solutions I've found to these my-two-dads sort of problems comes from thinking laterally. Do something completely different with bullets. Maybe a custom "reference count" used only by those two systems (although I think this is a hacky solution). Maybe bullets aren't owned by players at all, but contain a reference to a player ID allowing whatever system deals with the bullets to back-track to the player without having to worry about the player object still being around.

Jargon

The are two reasons to learn standard OO concepts. One is to help you become a better programmer. The other is so that you can communicate these concepts to other programmers. For any given concept that you learn, it's important to have a tag, a name, a label by which to refer to that concept. Having to say "that thing where you own this object that then has a pointer to a base class" is messy, when you could just say "bridge" -- which also captures a bit of intention, as well as architecture.

Say someone comes up to you and asks you what the difference between Aggregation and Containment is. Do you know? Can you explain it clearly? Probably only if you use those names a lot. I think ownership is an important concept and I use that word a lot in my code -- but I don't say // this object is aggregated or // contained. That would be lame.

I know the difference between the two. I don't think I'd be able to explain which one is which next week. Maybe, because I spent the time to write a post about it -- but that would be why, not because I use those words all the time. I think they're an awkward way to look at a more fundamental issue -- ownership.

Friday, July 11, 2008

Bridge Pattern vs Strategy Pattern

Short Form: both patterns are uses of inheritance to add flexibility. In both patterns, one class (the Container) has a reference to an Interface or base class, which is obviously intended to be subclassed.

In the Bridge pattern, the Container serves as an Adapter to the Interface, allowing Container's public interface to vary independently of the implementation in the subclasses. Bridge is a pattern that makes it easier to maintain code and add features.

In contrast, the Container's public interface isn't relevant to the Strategy pattern. The idea behind Strategy is to add flexibility to a class via the use of a contained object, instead of putting code directly in the Container and using a switch statement or whatever.

See also Builder Pattern vs Factory Pattern or Aggregation vs Composition.

--

I asked an interviewee about the Strategy Pattern yesterday, and it got me thinking about how best to explain the concept to someone. I'm of the belief that if you can't explain a concept then you don't really know it. There are a lot of concepts that one might have a fuzzy grasp of, but there's a wide gulf between that fuzzy grasp and being able to explain a concept to someone else. Explaining stuff is a great way to learn. That's one of the main reasons why I blog. :)

A pattern is a way of helping you abstract what your code is doing. It's a learning tool. We use a pattern name so that we can quickly explain what we're doing to others and so we can quickly implement new code. If I tell you that I'm using a Bridge in this one piece of code, and you know what a Bridge is, then I don't have to go through the trouble of explaining what all is going on. The word "Bridge" captures all of that info. If you only have a fuzzy grasp of the concept then we haven't really communicated. I said "bridge" but you heard "some sort of abstract connection thingy."

Patterns also help us categorize past experiences. I've implemented the Strategy pattern frequently and there's a few things I like to do the same way each time, like using an enum to specify which strategy to use. Following an existing pattern means not having to make up something from whole cloth.

The Bridge and Strategy patterns are structurally the same thing. They differ in intent. They're also similar to the State pattern and sometimes confused with the Template Method pattern, so I'll go over all four. Keep in mind that the purpose of using jargon is to communicate not just the fact that you're using inheritance somewhere, but why you're using it, and how the code is making use of it.
A Bridge is a pattern that allows you to vary the interface and implementation separately.

A Strategy is the parameterized variation of behavior.

The State pattern allows the dynamic variation of behavior.

A Template Method allows the variation of implementation without changing the algorithm.
You might be thinking, "Huh?"

As I've said before, the best way to explain a concept is by using a few examples, including at least one negative example (to make sure you've communicated the limits of the concept). So let me give some examples of common usage.

A Strategy allows you to swap in different behaviors by using a base class or Interface. You'll have at least four classes in this model: the Container, the Base Class, and two (or more) Subclasses. Say you've got a game with creatures that do different behaviors, such as Guard or Patrol or Hunt. Your AI class for the creature (the Container) contains a base class pointer (the Interface), which is an instance of one of the various Subclasses. You could have just had a switch statement somewhere in your AI class; that would not be a Strategy. Moving the 'joint' into a new class and using various subclasses to implement the behavior is the Strategy pattern.

Or maybe you have a button in your UI, but that button could be drawn using a texture or by rendering text over a standard rounded-rectangle. Instead of implementing two different Button classes, you could create a new ButtonRenderer class to encapsulate how you draw the control. The Button class (the Container) contains a pointer to a ButtonRenderer (the Interface), which will be either TextureButtonRenderer or TextButtonRenderer.

Strategy example:
class Button
{
private ButtonRenderer _renderer;
public Button( ButtonTypeEnum visualAppearance )
{
if (visualAppearance==ButtonTypeEnum.TexturedButton)
_renderer = TexturedButtonRenderer;
else
_renderer = TextButtonRenderer;
}
...
}
A Bridge is when you want to vary the implementation and interface separately. Say you've got a data access layer. The layer talks to an underlying database; you might want to change the type of database that you connect to. This could range from changing the connection string (to switch from a development DB to the production DB) to changing the database type (from SQL to Access to a stored XML file). But this layer also exposes an interface to the next higher layer (the business logic layer). A data access layer is, essentially, a Bridge: it separates the public interface of a class (Business Logic -> DAL) from its implementation (DAL -> Database).

One can think of a Bridge is a combination of a Proxy (or Adapter) and a Strategy. Instead of just coding one base class and its subclasses, Bridge adds another object into the picture. This extra class provides the external interface, and maps that interface to the base class's interface. You can vary the interface (ie the extra class's public methods) separately from the implementation (ie the various subclasses).

You say "Strategy" when you want to vary behavior, and you do so not by writing different objects but by introducing a class heirarchy. You say "Bridge" when you expect that you will vary both the interface and the implementation. In both cases you're providing flexibility for a changing implementation; in a Bridge, you're also expecting the interface to change.

A Strategy is when one type of object implements some part of its behavior using another class. For example, a Button implements rendering (but not click-processing or message-sending) using a new class. A Bridge implies that you could have just used that class directly somewhere up the chain, but that you want to add in an Adapter or Proxy on top. The interface that a Bridge object exposes is usually similar to the base class; in a Strategy, the public interface of the container object is often completely different than the contained base class. A Strategy says that you are implementing part of the container's behavior using the base class.

The State pattern is similar to Strategy. Typically, a Strategy pattern means that you set an object's behavior at construction, like the Button example above. Buttons don't change from one appearance to another in the middle of a game! The AI example, though, is more like the State pattern: not only have you provided flexibility by adding a new base class and stuffing variation into new classes instead of using a switch statement or if statement, but you'll be changing out which subclass you use fairly frequently. "State" implies a Strategy that changes frequently over an object's lifetime. "State" also implies that you're trying to encapsulate some complex, dynamic portion of an object's behavior into a new class, where "Strategy" implies that, when the Container object is constructed, that its creator will tell the Container what approach to take for its entire lifetime.

The Template Method is really not similar to these, but sometimes people confuse it with one of the others. Say you've got an object's script in an XML file; in-game, you turn each one of the "commands" in the XML into a call into some other class. Say the XML script includes commands like Attack, Move, Find Target, Use Bandaid, etc. Different creatures could use the same script to do their thing, but they might do it in different ways -- Attack could be performed by casting Magic Missile, or firing a bow, or by swinging an axe -- the script is then a Template Method. It's an algorithm that can be implemented in different ways. A Template Method can be considered a sequence of different Strategy choices, and is often implemented that way.

Similar Posts:
Builder Pattern vs Factory Pattern
Aggregation vs Composition

See Also:
Bridge at Wikipedia or c2
Strategy at Wikipedia or c2
State at Wikipedia or c2
Adapter at Wikipedia or c2
Proxy at Wikipedia or c2

Game State Management : Finite State Machines

I've added a subsequent post on state management in game menus. My previous post on game state covered high-level game state management. I next tried writing this post, but felt that covering feature creep was first up. I'll explain that first.

The whole trick to writing a game state management system is figuring out where you need flexibility. A system that's too complex winds up being buggy and a pain to use. Stable, easy-to-use systems generally allow you to add more richness to a project, say by extending the system, and that's something that doesn't happen when you have buggy or painful code. Simple systems lead to power.

Game state systems are used to implement game AI or mechanics. For example, a building in an RTS might start in a Construction state, then transition into an Idle state, then move into a Production state then back to Idle. A Creature AI might use states like Patrol, Guard, Hunt, Attack, Move, or Sleep. Programmers usually implement these systems using finite state machines, and that's what I'll be talking about here.

Finite State Machines (FSMs) are easy to code. The major element is the State object; everything else is optional. That else includes Transitions & Transition Conditions, Events, and Actions.

So what's a state? Take the RTS example above. When a building is in the Construction state, it might cycle through several different stages, ie have several different images (for a 2D game) or models (for a 3D game) that represents that partial construction. Maybe the phase is one long animation; maybe it's a set of several different animations. Even for a 2D, non-animated game, you might display a progress bar or particle effect or something else indicating construction progress. Is each 'step' along that progress a different State?

And that's the decision to make. Why are you storing the state? I mentioned several different states for a building in an RTS, and these suggest the state that the building is considered to be in for the purposes of gameplay, not for animation. It doesn't matter how far along construction is, the player only has two choices: either leave it alone to continue construction, or cancel the construction. This is a good level to model the state. Leave the problem of animating the building to some other system; a useful state management system in this game will deal with "Under Construction" as one entire state. A building might have four states: Construction, Idle, Production, and Under Attack (a building under attack can't be repaired or start production).

Do you need a class to store this state? Another option is to store the state as an enum. Every game tick, you tell the building to draw itself, and it can switch depending on that enum, just as easily as looking at a state class. So why would you have a State class?

One reason would be to implement the Strategy pattern. The building object itself could hold a State object, where State is an abstract base class. Subclasses would implement virtual functions, which could be Events (User_Requested_Production, User_Cancels_Construction, etc) or queries (Can_Start_Production) or maybe even a Tick or Render function. This means creating new subclasses not just for each state that buildings could share (like Idle) but also per building and per game object. The question is, what behavior do different buildings share in their Idle states, and would different game objects (like Buildings and Infantry and Missiles) all have Production or Under Attack states? What's the shared code?

This is putting the cart before the horse. Don't be led into thinking that you need to implement a Finite State Machine class because lots of games use finite state machines. I recommend implementing (say) one game object (like Buildings) first, and one Building before the rest, and then see where you can pull common code out. Implement some simple method using a bunch of switch statements and enums and see, for your game genre and design, where you need flexibility. When you're writing the code for a particular building, you might wind up writing a bunch of switch statements, and when you see yourself doing that, that is a good time to decide to implement some kind of FSM abstraction into the code.

Do all game objects render themselves? Do all game objects share a common base class (maybe they don't!)? Maybe there's common code to render a game object. Maybe all Buildings share rendering code among themselves that isn't used by other game objects. Most likely, you're not going to want custom Render methods for each individual building, or worse, each state that each building can be in.

Let's go back to the Building interface. Other gameplay objects don't really care how buildings render themselves, or really even what state the building is in. They have specific questions: can you start production right now? Should I be displaying a Cancel button? Is the building damaged? There's lots of other state I'm skipping over, too, like how many hit points the building has. I reckon there's some OO nutball out there that thinks that hit points should be encapsulated into a state object, but you and me can laugh at him. My god, man, no way. Hit points are 'state', but there's no reason to have a state object there. An int is fine. Hit points are such a primary concept in a game like an RTS that your base Game Object (or Building) class should have an accessor for that value.

So the external interface that a Building object exposes doesn't contain any State-like abstract object. A State object might be useful for a Building to manage itself internally, but it's not something it tells its friends about.

The place to put flexibility in your code is where there's a lot of traffic. Buildings don't get a lot of traffic. There's not much that can be done to them -- they get attacked, they get repaired -- but they don't usually observe their environment. Buildings don't behave different when their hitpoints get low, or when an enemy comes into range, or if they see a friendly unit nearby. Maybe yours do, but at least they're far more "stable" when compared to other units (like infantry). A complex state management system with transitions and events getting fired and scriptable transition conditionals and substates and enter actions and exit actions and all that... not that useful for game objects that don't do a lot of those things.

Mobile AI units, like infantry in an RTS or mobs in a real-time RPG or enemies in a FPS, will do a lot of those things. A fancy state management system makes more sense for those kinds of AI units, and I'll cover them in more depth next time.

Friday, June 6, 2008

High-Level Game State Management

By 'state management' I mean high-level game state. For example, when a game starts up, it might display a sequence of loading screens, including company logos, a game title screen, and intro cinematics. Then the main menu; then the game proper. Within the game itself, the game might have different screens that it displays and moves among, from character info to world view to options, etc.

I've seen some weird state management systems in my time. Almost all of the "systems" I've seen other people use aren't really systems; they were just hand-coded transitions, often involving a lot of global variables, a bunch of free functions, large switch statements, etc. Or maybe just a bunch of nested function calls, meaning that, when you quit the game, it backs out all the way through the main menu, past the title screen, the company logo, and the intro loading screen...

A programmer that's used to doing something one way, and satisfied that the approach is efficient, is unlikely to do something different. So here's something new.

I use a class-based state management system, cuz I'm a C++/C# programmer. State is managed through a 2-level inheritance hierarchy -- no complex class relationships, just one base class and one subclass for each different state. The main loop calls a static singleton to do whatever needs to be done in the current state; that singleton calls the current state subclass (of course, through a virtual function) to do its thing.

Each call through the system renders one frame. Usually; the current state can spend a bunch of time if it wants, which really only happens when loading new content. Even then, I sometimes leave the loading work to a different thread and continue rendering frames. This is one instance where the specifics aren't important; how you handle loading is independent of the idea of using a State parent class and its children to switch between different high-level states.

When a State has figured out that the game needs to move to a different state, it tells the state manager. I stick an enum for the different states in a header file. (Note that this means a bunch of recompilation "every time" I add a new State subclass. The thing is, that doesn't happen that often. There'll be maybe eight or ten states in the entire game, and over the lifetime of the project, ten extra recompiles is no big deal.) Since each run through the state manager generates one frame, the state manager can do cleanup and transition to the new state cleanly on a frame boundary.

I typically use an event model for controller/keyboard/mouse input. The events are grabbed at a high level and fed through the state manager. Abstracting input is a handy thing, and this structure solves that problem.

I've sometimes built complex stuff like preloading and caching into the state system. Separating out each game screen makes a bunch of stuff easier. Since the state objects aren't unloaded when state changes, a "level" can keep itself in memory, cached provided there's enough memory for it, meaning no lengthy load when the user (say) backs out to the main menu then reloads from a save point.

The State parent class has, over time, morphed into a Screen class. The different 'states' that this system models are often the major screens in a game: the loading screen, the company logo, the game title, the main menu, submenus, and the game proper. If save/load is handled through a fullscreen interface, that's a chance to move that code into its own class.

It doesn't matter to me if you use this structure, of course. I hope it's given you some ideas for structuring the high-level bits of your game differently.

Note: I've made a followup post on state management in game menus.