jump to navigation

Game actor state management April 14, 2010

Posted by Jesse in : Game Development , trackback

I could use a little advice.

Slowly but surely, my new game is starting to take shape. Recently, however, I’ve run into a bit of problem.

In Being, controlling the state of a game actor (both physics and animation) was very straightforward. After all, there were only a few options. Standing still, walking, jumping, and reacting to taking damage. There was no special work to transition between those states, and they were all very clearly defined so there was never any ambiguity about the status of the player.

I started out with a switch statement. Here’s a trimmed down version:

switch(state)
{
	case State.Idle:
		if(playerHit())
		{
			state = State.Hit;
			velocity.Y = HIT_VELOCITY;
			playAnimation("Hit");
			playSound("Ouch");
		}
		else if(playerJumped())
		{
			state = State.InAir;
			velocity.Y = JUMP_VELOCITY;
			playAnimation("Jump");
		}
		else if(playerLeft())
		{
			state = State.Walking;
			direction = Direction.Left;
			velocity.X = -WALK_VELOCITY;
			playAnimation("Walk");
		}
		else if(playerLeft())
		{
			state = State.Walking;
			direction = Direction.Right;
			velocity.X = WALK_VELOCITY;
			playAnimation("Walk");
		}
		break;
	case State.InAir:
		...
}

You can see, for even something as simple as this basic player, this becomes a very long chunk of code quickly. I read an article showing how I might break each state up into a class. You’d have a basic ActorState class, and derive from that to have an IdleState, InAirState, WalkingState, etc. This would simplify a few things, since any transition effects of changing state would be handled in the OnEnter method of the correct class.

An example of that:

class WalkingState : ActorState
{
	public override void OnEnter()
	{
		playAnimation("Walk");
	}

	public override string Update(GameTime gameTime)
	{
		if(playerRight())
		{
			velocity.X = WALK_VELOCITY;
			direction = Direction.Right;
			return "Walking";
		}
		else if (playerLeft())
		{
			...
		}

		...

		return "Idle";
	}
}

Well, that works, and certainly looks a little cleaner to me. But now I’ve got a whole mess of classes in a really big file, or I can stretch the player’s state code over a whole mess of little files. And if I do that for every Actor in the game, it would be a huge nightmare to find anything if I needed to make a change.

And now my big problem. While simple, my new game is significantly more complicated than Being. Currently the player can stand idle, walk, jump, double jump, and throw weapons. I’d also like to add wall jumping and possibly melee attacks. This pile of options leaves room for all sorts of ambiguity, as well as a bunch of transition issues. My code is starting to become unwieldy and impossible to maintain. I know it’s time to refactor, but I’m not really sure how to make it better.

And this is still a pretty simple game, all things considered. I can’t imagine how complicated things are in a modern big budget game.

Since every game needs this sort of system, this is a pretty well solved problem, right? I welcome all advice anyone wants to share.

Comments»

1. Warspawn - April 15, 2010

well, I don’t have any code for you, but perhaps an idea: use an Abstract Factory Pattern with Reflection and Interfaces.

it’s only an idea, dunno how right or wrong… but I’ll let you know if I come up with any code to back it up. đŸ™‚