How to handle states of sprites

Most of sprites in games has states that will change after fires some event.

Simple example:
We have one sprite “Dot”. This sprite has 3 states. Sprite can be clicked, when it will change state. Every state has different texture.

SHOW_EMPTY – empty Dot, sprite will not change it state
SHOW_SELECTED – Dot will be filled, sprite will not change it state
DRAW_EMPTY – Empty dot to change, sprite will change state to DRAW_SELECTED
DRAW_SELECTED- Filled Dot to change, sprite will change state to DRAW_EMPTY

BAD SOLUTION
We will use “if … else” statement and some methods and fields to handle states.

It will look like this.

boolean selected;
boolean clickable;

funtion void setSelected(boolean selected) {
  this.seleced = selected;
}
function boolean getSelected() {
   return selected;
}
function void setCkickable(boolean clickable) {
   this.clickable = clickable;
}
function boolean getClickable() {
   return clickable;
}

and for checking state and draw texture from touch listener:

function void manageTexture() {
if (clickable && selected) {
   // do something with texture
} else if (!clickable && selected) {
   // do something else with texture
}

… and so on.

For simple sprites it might look OK, but after some time new state comes, eg. HINT that will be same like SHOW_SELECTED but with minor changes. Then we must add new “if … else” statement.

After adding 3 or more sates code is hard to maintenance.

Pros:
Simple and fast to start implement
For 1-3 states small lines of code

Cons:
For more than 3 states huge number of lines that is hard to maintenance.

BETTER SOLUTION
I will use enums and interfaces
My enums will be:

enum DotState {
SHOW_EMPTY
SHOW_SELECTED
DRAW_SELECTED
DRAW_HINT
}

I will define our textures, lets simplified this to use TiledTexture from Andengine (integers define index of texture in image file.

enum DotState {
SHOW_EMPTY(0),
SHOW_SELECTED(1),
DRAW_SELECTED(2),
DRAW_HINT(3)
}

Then I will define what will happen after click. Click will be managed in touch listener that call our function but this function will be inside enum as a object that implements interface.

My interface will be:

private interface IManageMyState {
manage();
}

I will create objects for all states inside Sprite class like this:

private static final IManageMyState manageDrawSelected = new IManageMyState() {
public void manage(Dot dot) {
dot.state = DotState.DRAW_EMPTY;
}
};

Because enum is static my ImanageMyState objects must be static also. Dot object to handle will be passed as a parameter “manage(Dot dot)”.

And at the end I will pass my manager objects to enum:

enum DotState {
SHOW_EMPTY(0, manageShowEmpty),
SHOW_SELECTED(1, manageshowSelected),
DRAW_ENPTY(2, manageDrawEmpty),
DRAW_SELECTED(3, manageDrawSelected)
} 

We can manage textures simple to use our state.

@Override
function void onTouch(…) {
this.state.manager.manage(this);
}

Note that I passed “this” to manage method, this my dot to manage.

And that’s it!

WHY IT IS BETTER SOLUTION?

We can simply add new functions to IManageMyState, all states is simple to maintenance because all thins is in one place.

If you know better solution to handle states please write your comment 🙂

Pros:
Simple to maintenece for more than 3 states

Cons:
Lot of empty methods for states that do nothing

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s