How Animation Works - UQdeco2800/2022-studio-3 GitHub Wiki
Introduction
This is a guide on using the EntityDirectionComponent and direction setting logic in PhysicsMovementComponent to animate your character,
may that be animations for movement or attacks, the following animation directions can be achieved.
- North
- South
- East
- West
Entity Direction Component
This is a simple component attached to any entity that requires keeping track of which direction it's pointing in, it uses a simple enum EntityDirection to store the four compass direction; NORTH, SOUTH, EAST, WEST, DEFAULT, where DEFAULT is set upon initialising the component and changed to the appropriate direction in PhysicsMovementComponent.
UML

How it works
- Add the animation when creating your entity as follows:
AnimationRenderComponent animator =
new AnimationRenderComponent(
ServiceLocator.getResourceService().getAsset("images/blue_joker.atlas", TextureAtlas.class));
animator.addAnimation(MOVE_EAST, 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation(MOVE_WEST, 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation(MOVE_SOUTH, 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation(MOVE_NORTH, 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation("default", 1f, Animation.PlayMode.NORMAL);
animator.addAnimation(ATTACK_NORTH, 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation(ATTACK_SOUTH, 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation(ATTACK_EAST, 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation(ATTACK_WEST, 0.1f, Animation.PlayMode.LOOP);
blueJoker
.addComponent(new CombatStatsComponent(config.troops, config.health, config.baseAttack,
config.baseDefence, config.landSpeed, config.range))
.addComponent(animator)
.addComponent(new EnemyAnimationController());
blueJoker .getComponent(AnimationRenderComponent.class).scaleEntity();
- The animation controller class must be written in the following manner, UML diagram of
EnemyAnimationControlleris presented as an example of how an animation controller for movable units should be structured.

The create function must be populated as follows
@Override
public void create() {
super.create();
animator = this.entity.getComponent(AnimationRenderComponent.class);
entity.getEvents().addListener("goWest", this::animateWest);
entity.getEvents().addListener("goEast", this::animateEast);
entity.getEvents().addListener("goNorth", this::animateNorth);
entity.getEvents().addListener("goSouth", this::animateSouth);
entity.getEvents().addListener("default", this::defaultAnimation);
entity.getEvents().addListener("attackNorth", this::attackNorth);
entity.getEvents().addListener("attackSouth", this::attackSouth);
entity.getEvents().addListener("attackWest", this::attackWest);
entity.getEvents().addListener("attackEast", this::attackEast);
}
Example animation method
// Under EnemyAnimationController class
public void animateWest(){ animator.startAnimation("move-west"); }
The only mandatory animation events that need to be added are first five ("goWest" - "default"), as these are triggered in physics movement component for movement animations, the last four are specific to enemy units and can be replaced (or not) with events specific to your actions.
(Make sure that your movement events are labelled as goWest, goEast, goNorth and goSouth)
-
Once the
EntityDirectionComponentis added to an entity and animation controller has been made, thePhysiscsMovementComponentsets the direction if it has changed by triggering the following movement animation events upon setting a new direction:"goWest""goEast""goSouth""goNorth"
-
In addition we've made an attempt at implementing attack animation, this is done in
TouchAttackComponentby checking for the direction the entity is in and triggering its respective attack animation.
// Excerpt from TouchAttackComponent
// isAtacking is a private boolean set to false by default
// Should be from line 70 onwards.
if (targetStats != null) {
targetStats.hit(combatStats);
if (targetStats.getHealth() > 0) {
if (!isAttacking) {
isAttacking = true;
switch (entityDirectionComponent.getEntityDirection()) {
case DEFAULT:
break;
case WEST:
entity.getEvents().trigger("attackWest");
break;
case EAST:
entity.getEvents().trigger("attackEast");
break;
case NORTH:
entity.getEvents().trigger("attackNorth");
break;
case SOUTH:
entity.getEvents().trigger("attackSouth");
break;
}
}
} else {
isAttacking = false;
// target.dispose();
}
}
A similar sequence can be done for worker components when they're mining or building something.
Additional Notes
- Make sure your
.atlasfiles has an entry fordefaultor else this will cause runtime errors.