-
Notifications
You must be signed in to change notification settings - Fork 1
Animations
Animations are already supported by libgdx natively. However, this implementation is too generic to fit into the braingdx framework. Instead, braingdx implements its own Animation Utility integrated with libgdx.
Game Objects are part of the game world. All game objects are rendered into the game world via the GameObjectRenderer interface. Read here how this is done.
Given the following spritesheet:
As you can see the sprite sheet contains 8 different characters in total, each of them has 4 different animations for each direction. This is how you can animate the second character from the top left in braingdx:
/* in your AbstractScreen implementation */
// get the tileset as a texture, alternatively load it directly with libgdx
// The ID of your character
final int RPG_CHARACTER_ID = 1;
Texture texture = SharedAssetManager.getInstance().get(Assets.RPG.CHARACTER_TILESET);
// Convert the texture into a sprite sheet by providing the sprite size of 32x48 pixels
AnimationSpriteSheet sheet = new AnimationSpriteSheet(texture, 32, 48);
// Describe how GameObjects of type 'RPG_CHARACTER_ID' should be rendered
context.getRenderManager().register(RPG_CHARACTER_ID, new AnimationRenderer(sheet,
AnimationConfig.builder()
.registerFrames(AnimationDrawable.DEFAULT_FRAME_ID, AnimationFrames.builder()
// the number of frames
.frames(3)
// 4th tile from the left (3=index)
.origin(3, 0)
// change frame every 200m
.duration(0.2f)
// Animate directional
.direction(Direction.HORIZONTAL)
// Animate to the end and then backwards and repeat
.playMode(Animation.PlayMode.LOOP_PINGPONG)
.build())
.build());
The result will be a moving character which walks down without moving.
The API supports dynamic animations. For example, in the example above we want to render character movement into different directions depending on its orientation. Given the tileset above, let's define a new NPC
enum:
public enum NPC {
PRIEST_MALE(6, 0),
SAGE_FEMALE(3, 0),
CLERIC_MALE(0, 0),
DANCER_FEMALE(9, 0),
CITIZEN_MALE(0, 4),
DANCER_FEMALE_ALT(4, 3),
EXPLORER_MALE(6, 4),
EXPLORER_FEMALE(9, 4);
private final int indexX, indexY;
NPC(int indexX, int indexY) {
this.indexX = indexX;
this.indexY = indexY;
}
public int getIndexX() {
return indexX;
}
public int getIndexY() {
return indexY;
}
}
After that we can iterate over the enum to register our renderers to the context:
final Texture texture = SharedAssetManager.getInstance().get(Assets.RPG.CHARACTER_TILESET);
spriteSheet = new AnimationSpriteSheet(texture, 32, 48);
// Iterate over all NPC types
for (NPC npc : NPC.values()) {
AnimationConfig config = AnimationConfig.builder()
// register frames for each direction
.registerFrames(Orientation.DOWN, AnimationFrames.builder()
.frames(3)
.playMode(Animation.PlayMode.LOOP_PINGPONG)
.direction(AnimationFrames.Direction.HORIZONTAL)
.origin(npc.getIndexX(), npc.getIndexY())
.duration(0.2f)
.resetIndex(1)
.build())
.registerFrames(Orientation.LEFT, AnimationFrames.builder()
.frames(3)
.playMode(Animation.PlayMode.LOOP_PINGPONG)
.direction(AnimationFrames.Direction.HORIZONTAL)
.origin(npc.getIndexX(), npc.getIndexY() + 1)
.duration(0.2f)
.resetIndex(1)
.build())
.registerFrames(Orientation.RIGHT, AnimationFrames.builder()
.frames(3)
.playMode(Animation.PlayMode.LOOP_PINGPONG)
.direction(AnimationFrames.Direction.HORIZONTAL)
.origin(npc.getIndexX(), npc.getIndexY() + 2)
.duration(0.2f)
.resetIndex(1)
.build())
.registerFrames(Orientation.UP, AnimationFrames.builder()
.frames(3)
.playMode(Animation.PlayMode.LOOP_PINGPONG)
.direction(AnimationFrames.Direction.HORIZONTAL)
.origin(npc.getIndexX(), npc.getIndexY() + 3)
.duration(0.2f)
.resetIndex(1)
.build())
.build();
// register each NPC config to the render manager by using the ENUM name as a key
context.getRenderManager().register(npc.name(), new AnimationRenderer(spriteSheet, config,
// We have to define a new animation type resolver. Instead of using the
// type of the `GameObject` class
// we now use the orientation attribute of a game object which is
// automatically configured when using RasteredMovementBehavior class
new AnimationTypeResolver<GameObject>() {
@Override
public Object getAnimationType(GameObject object) {
return object.getAttribute(Orientation.class);
}
},
// NPCs should not walk when they are not moving
new Enabler<GameObject>() {
@Override
public boolean isEnabledFor(GameObject target) {
return target.getOffsetX() != 0 || target.getOffsetY() != 0;
}
}));
}
For animating UI elements we can use the same API based on the Drawable class in libgdx:
Texture texture = SharedAssetManager.getInstance().get(Assets.UI_LOGO);
// Convert the texture into a sprite sheet and describe how many tiles exist
AnimationSpriteSheet sheet = new AnimationSpriteSheet(texture, 128, 32);
AnimationDrawable drawable = new AnimationDrawable(sheet,
AnimationConfig.builder()
.registerFrames(AnimationDrawable.DEFAULT_FRAME_ID, AnimationFrames.builder()
// the number of frames
.frames(3)
// 1th tile from the left (3=index)
.origin(0, 0)
// change frame every 100m
.duration(0.1f)
// Animate directional
.direction(Direction.HORIZONTAL)
// Animate to the end and repeat
.playMode(Animation.PlayMode.LOOP)
.build())
.build());
// add a new UI element to animate
context.getStage().addActor(new Image(drawable));