Skip to content

Animations

miguel edited this page Nov 25, 2019 · 14 revisions

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.

Animating GameObject types

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:

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.

Dynamically change animations on the fly

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;
            }
      }));
}

animation

Animating UI elements

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));
Clone this wiki locally