Human Enemies and HumanAnimationController - UQdeco2800/2021-studio-2 GitHub Wiki
Human Enemies
The implementation of Human Enemies into the game has required a new Animation Controller as the Elf Animation Controller is very specialised to those enemies. Some differences between these Controllers is that the HumanAnimationController is generalised and can be used without requiring the type of enemy. This allows for much cleaner code and implementation that does not vary within the Atlas files.
HumanAnimationController
The animations types that are required in the Atlas file are shown below. The Atlas file can include extra animations if necessary but there are the minimum animations required to be a functioning enemy within the game.
This component will be added to the existing enemies to define the animations that they will be using. Further information about adding components to the enemy can be found at the page: AI.
default
All of the enemies require this Atlas image, if this is missing, then the a NullPointerException will be thrown and the game will crash.
moveLeft, moveRight, moveUp, moveDown,
These are the movement animations that will be used when the any movement task is called.
EnemyAttackUp, EnemyAttackDown, EnemyAttackLeft, EnemyAttackRight,
These are the movement animations that will be used when an attack is called from an attack task.
backDeath, frontDeath, leftDeath, rightDeath,
The animations that will be played once the enemy has been killed.
These animations will need to be added to the AnimationRenderComponent along with the animation will be looped, determined by Animation.PlayMode.NORMAL or Animation.PlayMode.LOOP as well as the duration of each frame.
A private function has been created in the NPC factory for a default animation settings. The function setHumanAnimations is shown below. The function will require an AnimationRenderComponent and will return itself once the animations have been added to the Component. This component will also need to be added to the Enemy entity.
private static AnimationRenderComponent setHumanAnimations(AnimationRenderComponent animator) {
animator.addAnimation("default", 0.2f, Animation.PlayMode.NORMAL);
animator.addAnimation("moveLeft", 0.2f, Animation.PlayMode.LOOP);
animator.addAnimation("moveRight", 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation("moveUp", 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation("moveDown", 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation("frontDeath", 0.5f, Animation.PlayMode.NORMAL);
animator.addAnimation("backDeath", 0.5f, Animation.PlayMode.NORMAL);
animator.addAnimation("leftDeath", 0.5f, Animation.PlayMode.NORMAL);
animator.addAnimation("rightDeath", 0.5f, Animation.PlayMode.NORMAL);
animator.addAnimation("EnemyAttackDown", 0.05f, Animation.PlayMode.NORMAL);
animator.addAnimation("EnemyAttackUp", 0.05f, Animation.PlayMode.NORMAL);
animator.addAnimation("EnemyAttackLeft", 0.05f, Animation.PlayMode.NORMAL);
animator.addAnimation("EnemyAttackRight", 0.05f, Animation.PlayMode.NORMAL);
return animator;
}
UML Diagram
Due to the different tasks that the NPCs have, it was difficult to determine the architecture to be used to call the animations, The architecture that was decided on was the use of an EventHandler to implement the Observer pattern. The individual tasks will trigger events within the entity and this entity will receive the events and call the appropriate methods in the HumanAnimationController class. The HumanAnimationController class stores the animator class and will call the appropriate animation changes depending on what has been triggered. Although the tasks do not directly use the HumanAnimationController class as shown in the diagram, in reality, the Task will trigger an event which will be received by the entity and the HumanAnimationController will call the function due to this trigger.
Unlike what is shown in the diagram, the Architecture prevents the coupling between the tasks and the animations so each task does not need to call functions from it directly but through the event system. This means that tasks only needs to trigger the event when an animation is needed and each task class will not require direct access.

Sequence Diagram
The Sequence Diagram below has also been created to determine the set of events that should take place to call the animations. This has been used to code what has currently been implemented. The overall diagram shows that the highest priority task will trigger an event to cause the HumanAnimationController to call a method on the animator to animate the movement that is required by the Task.
The sequence diagram below has been used to visualise the events that take place when an NPC entity has ChaseTask as their highest priority and will start to chase the Target Entity in the right direction.
- The chase entity will call the movement with
start()on the generic MovementClass which will begin the movement - The MovementTask will use the
PhysicsMovementComponentand this will handle the event trigger back to the entity. - The
HumanAnimationControllerclass has listeners for the "RightStart" string event which will call the functionanimateRight()from within the class. - The function
animateRight()will cause theAnimationRenderComponentclass to animate the movement to the right.
