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

image

How it works

  1. 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();
  1. The animation controller class must be written in the following manner, UML diagram of EnemyAnimationController is presented as an example of how an animation controller for movable units should be structured.

image

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)

  1. Once the EntityDirectionComponent is added to an entity and animation controller has been made, the PhysiscsMovementComponent sets the direction if it has changed by triggering the following movement animation events upon setting a new direction:

    • "goWest"
    • "goEast"
    • "goSouth"
    • "goNorth"
  2. In addition we've made an attempt at implementing attack animation, this is done in TouchAttackComponent by 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 .atlas files has an entry for default or else this will cause runtime errors.