Combat Animation System - UQdeco2800/2022-studio-2 GitHub Wiki

Summary

This wiki page will explain the implementation of the Combat Animation System which causes animations to be played dependent on the weapon and current aura effect. The visual weapon and complementary animations are overlayed over the top of the player, following a similar approach to how skills are implemented on the player.

Key Binds

Press SPACE to attack, this will trigger an attack animation (as well as the attack function) if the player is currently holding a weapon. This is checked in source/core/src/main/com/deco2800/game/components/player/KeyboardPlayerInputComponent.java

Where do I find the atlas file and .png file?

All combat animation related image and atlas files are located in: source/core/assets/images/CombatItems/animations Currently, all melee animations are stored in combatItemsAnimation.atlas and combatItemsAnimation.png

Weapon Animation Event Naming Convention

Note that currently, each weapon has 10 listeners each. The event names follow the following convention: weapon + Aura + (whether attacking or not attacking) If the animation is an attack animation, the event name is simply weapon If the animation is while holding the weapon still, the event name is weaponStatic If the animation is attacking with a buff applied, the event name is weaponAura If the animation is holding weapon still with a buff applied, the event name is weaponAuraStatic

For example: The sword attack animation is called: sword The sword while standing still is called swordStatic The sword with the fire aura effect and attacking is called swordFire The sword with the fire aura effect and not attacking is called swordFireStatic

Combat Animation System Logic

createCombatAnimator

Located in: _source/core/src/main/com/deco2800/game/entities/factories/PlayerFactory.java

We created a new function that takes the atlas file to create the animations of the items. The atlas file gives the properties of the animations that are linked to the sprite file that contains the .png images of all the frames of the combat items.

public static Entity createCombatAnimator(Entity playerEntity) {
    AnimationRenderComponent animator =
            new AnimationRenderComponent(
                    ServiceLocator.getResourceService().getAsset("images/CombatItems/animations/combatItemsAnimation.atlas", TextureAtlas.class));

The animations are added using the below code format:

    animator.addAnimation("athena", 0.1f);
    animator.addAnimation("athenaDamage", 0.1f);

We then created a new entity of this animation that overlays it on the player entity.

    Entity combatAnimator =
            new Entity().addComponent(animator)
                    .addComponent(new PlayerCombatAnimationController(playerEntity));

    combatAnimator.getComponent(AnimationRenderComponent.class).scaleEntity();
    return combatAnimator;

InventoryComponent

The InventoryComponent class is used to set the combatAnimator for the game in the registerAnimation() function, which is triggered upon equipping a weapon.

This function also triggers the event of the "static" weapon animations which will immediately make the weapon appear in the player's hand, using:

String description = weapon.getComponent(PhysicalWeaponStatsComponent.class).getDescription();
String staticAnimation = description+"Static";
combatAnimator.getEvents().trigger(staticAnimation);

The combatAnimator is unregistered using the cancelAnimation() function upon unequipping the weapon.

PlayerTouchAttackComponent

In the attack() function written under PlayerTouchAttackComponent, there is code written which will trigger the appropriate Attack Animation Listeners.

The logic is that it will check the currently equipped weapon and also if there is an aura applied:

Entity weaponEquipped = entity.getComponent(InventoryComponent.class).getEquipable(0);
Entity auraEquipped = ServiceLocator.getGameArea().getPlayer().getComponent(WeaponAuraManager.class).auraApplied;

If there is an equipped weapon, the description of the weapon will be checked using the getDescription() functions written in WeaponStatsComponent.Java and WeaponAuraComponent.Java respectively.

For weapon:

String description = weaponEquipped.getComponent(PhysicalWeaponStatsComponent.class).getDescription();

For aura:

String current_aura = auraEquipped.getComponent(WeaponAuraComponent.class).getDescription();

On the condition there is an Aura applied, the event will be triggered with a combination of the description and the current_aura.

String animationToApply = description+current_aura;
combatAnimator.getEvents().trigger(animationToApply);

An example of this would be the sword weapon and the player having stepped on the 'attack damage' aura. This would trigger the event: swordDamage.

If no aura is in effect, the animation played will simply be based on the description. e.g.

else {
      animationDesc = description;
}
combatAnimator.getEvents().trigger(animationDesc);

PlayerCombatAnimationContoller

Located in: _source/core/src/main/com/deco2800/game/components/player/PlayerCombatAnimationController.java

We created a new class that uses the event trigger to 'secure' the weapon to overlay the player. The securement is done by the following line of code:

 public void update() {
        this.entity.setPosition(playerEntity.getPosition().x, playerEntity.getPosition().y);
    }

This is also the same place where the attack listeners and event functions are written.

Attack Animation Event Listeners

Above we have explained how attack animations are triggered. Now, we will look at what happens upon an event being triggered.

The display animation listeners are created the create() function in PlayerCombatAnimationController which actively checks if the respective animation events have been called.

For example:

  1. Athena's Dagger

entity.getEvents().addListener("athena", this::animateAthena);
  1. Hera and Athena Dagger

entity.getEvents().addListener("heraAthena", this::animateHeraAthena);

When the listeners receive the event passed to it by the attack or registerAnimation functions, the start animate functions are called.

Start Animation Functions

These functions are what starts the animation we have previously created in in the createCombatAnimator functions.

void animateSword() {
    animator.startAnimation("sword");
}

Feature Extensions

How to add a new combat animation to the game

Add your new images

Firstly, take the combatItemsAnimation.atlas and .png files and re-generate the files to contain your additional images that you wish to add as combat animations.

Create the new animation

Go to PlayerFactory.java and find the createCombatAnimator() function. In the section where the animations are listed, add in your animation. Your chosen animation name must match up with the entry within the .atlas file. For example, the below animation:

animator.addAnimation("sword", 0.1f);

Will trigger the "sword" animation within the .atlas file, such as below:

image

There can be multiple images with the same animation name. When this is the case, when the "sword" animation started, it will play all frames in the atlas file named "sword"

Note that for static animations where there is no attack event but there are particle effects we use a LOOP. e.g.

animator.addAnimation("swordSpeedStatic", 0.1f, Animation.PlayMode.LOOP);

Add the event listener

Then, go to PlayerCombatAnimationController and add an event listener for the name of the animation you have just created. For example:

entity.getEvents().addListener("sword", this::animateSword);

Add the start animation function

Scroll down to the section below the listeners where the animate functions are written. Add your animation start event.

void animateSword() {
    animator.startAnimation("sword");
}

Note that you can name the animate function whatever you would like. However, for consistency, we follow the convention of calling the function animateEventName.

Edit the description of a weapon

To change the description of a weapon, navigate to WeaponFactory.Java and AuraFactory.Java and note the "description" attribute of each create() function for the auras and the weapons.

Back to Combat Items Contents Page

Author

  • Lachlan Benson
  • GitHub: @LachlanBenson
  • Discord: Lachlan.Benson#4926
  • Slack: Lachlan Benson