I have elaborated on my comment suggestion, but the answer to your questions are:
Yes, there are alternatives to a singleton. I present one shortly.
Whether you want to serialize your information to xml, a database, yaml, or whatever is up to you. I do not recommend serializing to your chosen method each time your character drinks a potion or whatever, but having a method to serialize out your game data is a good idea. Slick does not provide an api for writing to XML, just reading from it. YAML is a good alternative. SQLite might also be an alternative.
The solution I use:
Here is an example of how to share game data between states. This is an edited version of code I use as the basis of all of my own slick projects.
At the root, I have an abstract class ClientBase (client in this context means game client)
public abstract class ClientBase<T> extends StateBasedGame {
private T gameData = null;
public ClientBase(String name, T theGameData) {
super(name);
setGameData(theGameData);
}
private void setGameData(T theGameData) {
gameData = theGameData;
}
public T getGameData(){
return gameData;
}
}
And I have a GameStateBase class to encapsulate individuals states:
public abstract class GameStateBase<T, U extends StateBase> implements GameState {
private U state;
private ClientBase<T> client;
public GameStateBase(ClientBase<T> theClient,U theState){
setClient(theClient);
}
private void setState(U theState) {
state = theState;
}
public U getState(){
return state;
}
private void setClient(ClientBase<T> theClient) {
client = theClient;
}
public ClientBase<T> getClient(){
return client;
}
@Override
public int getID() {
return getState().getValue();
}
@Override
public boolean isAcceptingInput() {
return getClient().getCurrentState()==this;
}
/* also contains stubs for other GameState methods */
}
(to make the enum based method a little clearer, let me include StateBase here)
public interface StateBase {
int getValue();
}
And that concludes a simplification of the plumbing....
Now, to actually USE this stuff:
Here's a simple example of a States class, which implements the StatesBase interface.
public enum States implements StateBase{
SPLASH(0),
MAIN_MENU(1);
private int value;
States(int theValue){
value = theValue;
}
@Override
public int getValue() {
return value;
}
}
And a concrete class for my client:
public class Client extends ClientBase<GameData> {
public Client(String name) {
super(name, new GameData());
}
@Override
public void initStatesList(GameContainer arg0) throws SlickException {
addState(new SplashState(this, States.SPLASH));
addState(new MainMenuState(this,States.MAIN_MENU));
/* other states go here*/
}
}
And finally one of the game states itself:
public class SplashState extends GameStateBase<GameData,States>{
private static final int ELAPSED_INITIAL = 0;
private static final int ELAPSED_FINAL = 5000;
private int elapsed;
public SplashState(ClientBase<GameData> theClient, States theState) {
super(theClient, theState);
}
@Override
public void keyPressed(int theKey, char theCharacter) {
if(theKey==Input.KEY_ESCAPE){
elapsed = ELAPSED_FINAL;
}
}
@Override
protected void enter()
throws SlickException {
elapsed = ELAPSED_INITIAL;
}
@Override
protected void render(Graphics theGraphics)
throws SlickException {
theGraphics.clear();
theGraphics.drawString("SPLASH", 0.0f, 0.0f);
}
@Override
protected void update(int theDelta)
throws SlickException {
elapsed += theDelta;
if(elapsed>=ELAPSED_FINAL){
getClient().enterState(States.MAIN_MENU.getValue());
}
}
}
Anywhere within a game state that descends from GameStateBase, a call of:
GameData theGameData = getClient().getGameData();
Will return your shared data.
And what of the class GameData itself?
That's totally up to you. That's why it uses generics.
The pros of this method:
- All of the states have access to the game data
- You aren't forced to use a static singleton
- GameData works as an access layer to whatever storage medium you choose. If the backend is a database or xml file or whatever, GameData talks to it, and the game states don't have to care how it is implemented.
The cons of this method:
- Since any state has full access to the game data, any state can change the data. This might not seem like a big deal, but there are indeed plenty of states, like the Splash state, which does not care in the slightest about much of any thing in the game.