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:
-
Athena's Dagger
entity.getEvents().addListener("athena", this::animateAthena);
-
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:
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