patternjavaMinor
Creating and playing animations for a game using LibGDX
Viewed 0 times
playingcreatinganimationsgamelibgdxforusingand
Problem
It feels like there's quite a lot of code involved in order to manually build up an animation using the libGDX framework. In my specific case, I am creating a number of animations for a portrait view of a character. The character will do things like talk, blink, and laugh. There are a handful of different characters to worry about.
I would like to get some feedback on my approach. I'm hoping to simplify things as much as I can, but this is the best that I have come up with so far.
First, a texture atlas is created from a file. Then, the types from an enum are used to create a map of the types to the frames. I've removed all but one of the types just for brevity, but there is one for every single frame of animation.
PortraitType.java
LibGDXGame.java
After the map of all the frames is created, another map is created for each character that maps the type of animation to the animation its
I would like to get some feedback on my approach. I'm hoping to simplify things as much as I can, but this is the best that I have come up with so far.
First, a texture atlas is created from a file. Then, the types from an enum are used to create a map of the types to the frames. I've removed all but one of the types just for brevity, but there is one for every single frame of animation.
PortraitType.java
public enum PortraitType {
GOBLIN_TALK01("goblinTalkRight01", 106),
GOBLIN_TALK02("goblinTalkRight02", 107),
GOBLIN_TALK03("goblinTalkRight03", 108),
GOBLIN_TALK04("goblinTalkRight04", 109),
GOBLIN_TALK05("goblinTalkRight05", 110),
GOBLIN_TALK06("goblinTalkRight06", 111),
GOBLIN_TALK07("goblinTalkRight07", 112),
GOBLIN_TALK08("goblinTalkRight08", 113),
GOBLIN_TALK09("goblinTalkRight09", 114),
GOBLIN_TALK10("goblinTalkRight10", 115),
GOBLIN_TALK11("goblinTalkRight11", 116);
public final String fileName;
public final int id;
private PortraitType(String fileName, int id) {
this.fileName = fileName;
this.id = id;
}
}LibGDXGame.java
private Map loadPortraitTextures() {
Map textures = new HashMap();
TextureAtlas atlas = new TextureAtlas("rampartedPortraits01.atlas");
for (PortraitType type : PortraitType.values()) {
AtlasRegion region = atlas.findRegion(type.fileName);
TextureRegion textureRegion = region;
textures.put(type, textureRegion);
}
return textures;
}After the map of all the frames is created, another map is created for each character that maps the type of animation to the animation its
Solution
First of all, it's a pleasure watching your games evolve, keep it up!
Data management
Most of the code is about data. Creating all your objects with their behaviors programmatically is tedious, not practical. It's not easy to see all the data, as you have to jump between multiple classes to piece everything together. Probably it didn't seem that way in the beginning, but now it definitely is. I suggest to rework how the characters are built up, using a data driven approach.
As the first step, create factory and repository interfaces that will be in charge of materializing all the characters with their behaviors. The initial implementation can be the current code, transformed appropriately, still creating the characters fully programmatically.
As the second step, create an alternative implementation, creating the characters from flat files, for example, it could be CSV, or XML, it doesn't matter much. At some point later you might want to ditch that too, for example using a database backend or REST service backend, it doesn't matter, because thanks to the factory and repository interfaces, you will be able to replace the implementation without affecting the rest of the program.
Creating arrays
This is a very fragile way to populate an array:
It's fragile, because the array size must match the assigned elements, the indexes must be correct, unique and compete. There are many possible points of human error. Better to write like this:
Unused variables
The
The
Naming
The
Data management
Most of the code is about data. Creating all your objects with their behaviors programmatically is tedious, not practical. It's not easy to see all the data, as you have to jump between multiple classes to piece everything together. Probably it didn't seem that way in the beginning, but now it definitely is. I suggest to rework how the characters are built up, using a data driven approach.
As the first step, create factory and repository interfaces that will be in charge of materializing all the characters with their behaviors. The initial implementation can be the current code, transformed appropriately, still creating the characters fully programmatically.
As the second step, create an alternative implementation, creating the characters from flat files, for example, it could be CSV, or XML, it doesn't matter much. At some point later you might want to ditch that too, for example using a database backend or REST service backend, it doesn't matter, because thanks to the factory and repository interfaces, you will be able to replace the implementation without affecting the rest of the program.
Creating arrays
This is a very fragile way to populate an array:
TextureRegion[] noneRegions = new TextureRegion[6];
noneRegions[0] = textures.get(PortraitType.GOBLIN_TALK01);
noneRegions[1] = textures.get(PortraitType.GOBLIN_TALK01);
noneRegions[2] = textures.get(PortraitType.GOBLIN_TALK01);
noneRegions[3] = textures.get(PortraitType.GOBLIN_TALK01);
noneRegions[4] = textures.get(PortraitType.GOBLIN_TALK01);
noneRegions[5] = textures.get(PortraitType.GOBLIN_TALK01);
return new Animation(1/6f, noneRegions);It's fragile, because the array size must match the assigned elements, the indexes must be correct, unique and compete. There are many possible points of human error. Better to write like this:
return new TextureRegion[] {
textures.get(PortraitType.GOBLIN_TALK01),
textures.get(PortraitType.GOBLIN_TALK01),
// ..
};Unused variables
The
cycleAnimations method takes a delta parameter that is never used. The
paused field is never used.Naming
The
currentAnimation field is of type PortraitAnimationType, which is confusing considering there is also an Animation type, which is a close collaborator. Other methods that work with PortraitAnimationType also have just Animation in their names, further aggravating the confusion. It would be better if method names were more consistent with the types of objects they work with.Code Snippets
TextureRegion[] noneRegions = new TextureRegion[6];
noneRegions[0] = textures.get(PortraitType.GOBLIN_TALK01);
noneRegions[1] = textures.get(PortraitType.GOBLIN_TALK01);
noneRegions[2] = textures.get(PortraitType.GOBLIN_TALK01);
noneRegions[3] = textures.get(PortraitType.GOBLIN_TALK01);
noneRegions[4] = textures.get(PortraitType.GOBLIN_TALK01);
noneRegions[5] = textures.get(PortraitType.GOBLIN_TALK01);
return new Animation(1/6f, noneRegions);return new TextureRegion[] {
textures.get(PortraitType.GOBLIN_TALK01),
textures.get(PortraitType.GOBLIN_TALK01),
// ..
};Context
StackExchange Code Review Q#145355, answer score: 4
Revisions (0)
No revisions yet.