I'll give you my take on this here. Any comments and suggestions for improvements are appreciated. The following code is tested and works fine.
First I create an interface for my Actors. The methods included in this interface must be implemented to achieve the polymorph behavior (are there other ways of achieving the same?).
public interface Animatable {
public Animation getAnimation(int state); //Each Actor must poll Animations
public SkeletonData getSkeletonData(); //Each Actor must get a SkeletonData object
}
Then I make the Actor implement this interface. Also, the Actor has an instance of a Skeleton and an Animation instance (currentAnimation) that will be changed based on states. This will thus just be a reference to objects in an AnimationsContainer object (see below).
public abstract class ActorBaseClass extends Actor implements Animatable{
protected Skeleton skeleton;
protected Animation currentAnimation;
public ActorbaseClass(AssetsContainer assetsContainer){
this.assetsContainer = assetsContainer; //Reference to (protected) object containing AnimationsContainer object
skeleton = new Skeleton(getSkeletonData());
skeleton.setToBindPose();
currentAnimation = getAnimation(state);
}
//Stuff, note that this in an abstract Actor so the interface methods need not be implemented here.
}
Then I implement the two interface methods in an Actor of instance ActorBaseClass:
public class Figure2 extends ActorBaseClass{
public Figure2( AssetsContainer assetsContainer) {
super(assetsContainer);
}
@Override
public Animation getAnimation(int state) {
return assetsContainer.getAnimationsContainer().getFigure2Animation(state);
}
@Override
public SkeletonData getSkeletonData() {
return assetsContainer.getAnimationsContainer().getFigure2SkeletonData();
}
}
The AnimationsContainer class looks like:
public class AnimationsContainer {
private Figure2Animations figure2Animations;
//TODO: Add classes for other Actors
public AnimationsContainer( AssetsContainer assetsContainer ){
figure2Animations = new Figure2Animations(assetsContainer);
//TODO: Create instances of other classes
}
public Animation getFigure2Animation( int state ){
return figure2Animations.getAnimation(state);
}
public SkeletonData getFigure2SkeletonData(){
return figure2Animations.getSkeletonData();
}
}
where the figure2Animations instance is of the following class:
public class Figure2Animations {
private static final String name = GameParameters.FigureData.Figure2Data.name;
private SkeletonData skeletonData;
private Animation walkAnimation, //Animation for STATE_WALKING
dragAnimation, //Animation for STATE_DRAGGED
fallAnimation, //Animation for STATE_FALLING
bounceAnimation, //Animation for STATE_BOUNCING
stealAnimation, //Animation for STATE_STEALING
tapAnimation, //Animation for STATE_TAPPED
dieAnimation, //Animation for STATE_DEAD
dodgeAnimation, //Animation for STATE_DODGE
landAnimation; //Animation for STATE_LANDING
public Figure2Animations( AssetsContainer assetsContainer ){
SkeletonJson json = new SkeletonJson(assetsContainer.getTextureAtlas());
skeletonData = json.readSkeletonData(Gdx.files.internal("data/spine/"+name+"/"+name+"-skeleton.json"));
walkAnimation = json.readAnimation(Gdx.files.internal("data/spine/"+name+"/"+name+"-walk.json"), skeletonData);
dragAnimation = json.readAnimation(Gdx.files.internal("data/spine/"+name+"/"+name+"-drag.json"), skeletonData);
fallAnimation = json.readAnimation(Gdx.files.internal("data/spine/"+name+"/"+name+"-fall.json"), skeletonData);
bounceAnimation = json.readAnimation(Gdx.files.internal("data/spine/"+name+"/"+name+"-bounce.json"), skeletonData);
stealAnimation = json.readAnimation(Gdx.files.internal("data/spine/"+name+"/"+name+"-steal.json"), skeletonData);
tapAnimation = json.readAnimation(Gdx.files.internal("data/spine/"+name+"/"+name+"-walk.json"), skeletonData);
dieAnimation = json.readAnimation(Gdx.files.internal("data/spine/"+name+"/"+name+"-walk.json"), skeletonData);
dodgeAnimation = json.readAnimation(Gdx.files.internal("data/spine/"+name+"/"+name+"-walk.json"), skeletonData);
landAnimation = json.readAnimation(Gdx.files.internal("data/spine/"+name+"/"+name+"-land.json"), skeletonData);
}
public SkeletonData getSkeletonData(){
return skeletonData;
}
public Animation getAnimation( int state ){
switch ( state ) {
case ActorBaseClass.STATE_NONE:
return null; //TODO: Remove?
case ActorBaseClass.STATE_TOUCHED:
return null; //TODO: Remove?
case ActorBaseClass.STATE_WALKING:
return walkAnimation;
case ActorBaseClass.STATE_DRAGGED:
return dragAnimation;
case ActorBaseClass.STATE_FALLING:
return fallAnimation;
case ActorBaseClass.STATE_BOUNCING:
return bounceAnimation;
case ActorBaseClass.STATE_LANDING:
return landAnimation;
case ActorBaseClass.STATE_FLINGED:
return fallAnimation; //TODO: Do something else?
case ActorBaseClass.STATE_TAPPED:
return tapAnimation;
case ActorBaseClass.STATE_DODGE:
return dodgeAnimation;
case ActorBaseClass.STATE_STEALING:
return stealAnimation;
case ActorBaseClass.STATE_DEAD:
return dieAnimation;
case ActorBaseClass.STATE_STILL:
return null; //TODO: Do something else?
default:
return null; //TODO: Do something else? Throw?
}
}
}
Does this seem like a reasonable approach? I realize that for instance the Figure2Animations class may be refactored to a template class somehow.