-
Notifications
You must be signed in to change notification settings - Fork 1
[Deprecated] Attack function
This wiki page will explain the implementation of the Attack()
function which allows the player to deal damage to enemies.
Press SPACE
to attack, this will play the attack animation for the single dagger and show the weapon in the player's hand, as well as deal damage to the closest enemy. For now, this is hard coded. In Sprint 3, attack damage and animation will be dependent on the equipped weapon.
Press N
to play the animation for the double dagger (note, does not deal damage). Implemented this way temporarily as a player cannot yet equip a weapon.
Located in: source/core/src/main/com/deco2800/game/components/player/PlayerTouchAttackComponent.java
We created a new class PlayerTouchAttackComponent
which extends TouchAttackComponent
to create a player-specifc attack function.
First, the attack listeners are created which actively check for any attacks and collisions.
entity.getEvents().addListener("attack", this::attack);
entity.getEvents().addListener("collisionStart", this::playerCollidesEnemyStart);
combatStats = entity.getComponent(CombatStatsComponent.class);
entity.getEvents().addListener("collisionEnd", this::playerCollidesEnemyEnd);
Upon recording a collision, the code below will check that when the Entity the Player is colliding with is an ENEMY
.
If the collision is with an ENEMY
, then the variable enemyCollide
will be set to TRUE.
private void onCollisionStart(Fixture me, Fixture other) {
if (((BodyUserData) other.getBody().getUserData()).entity.checkEntityType(EntityTypes.ENEMY)) {
target = ((BodyUserData) other.getBody().getUserData()).entity;
enemyCollide = true;
}
}
Fixture me
: The fixture of the object which is colliding (player)
Fixture other
: The fixture of the object which is being collided with (enemy)
Then, when the collision is over, the playerCollidesEnemyEnd
function is called which sets the enemyCollide
variable to FALSE
private void playerCollidesEnemyEnd(Fixture me, Fixture other) {
enemyCollide = false;
}
The attack function is relatively simple and relies on other functions to complete the work.
When enemyCollide
is set to TRUE, then applyDamageToTarget
is called.
if (enemyCollide) {
applyDamageToTarget(target);
Additionally, a death condition has been implemented where if the enemy's health reaches 0, that the entity is disposed of and the animation is stopped.
if (target.getComponent(CombatStatsComponent.class).getHealth() == 0) {
target.dispose();
if (target.getComponent(AnimationRenderComponent.class) != null) {
target.getComponent(AnimationRenderComponent.class).stopAnimation();
}
}
Modifications had to be made to the dispose() method in the Entity class to not dispose the AnimationRenderComponent (TextureAtlas) shared by all enemies when a enemy entity is disposed.
public void dispose() {
for (Component component : createdComponents) {
if (!(component instanceof AnimationRenderComponent)) {
component.dispose();
} //this prevents the other entities using the same animation from having their atlases disposed (black box)
}
ServiceLocator.getEntityService().unregister(this);
}
This function gets the CombatStatsComponent
and calls the CombatStatsComponent's hit
function.
private void applyDamage(Entity target) {
CombatStatsComponent targetStats = target.getComponent(CombatStatsComponent.class);
targetStats.hit(combatStats);
}
Located in: source/core/src/main/com/deco2800/game/components/player/CombatStatsComponent.java
In the hit
function, if there is a weapon currently equipped by the player, the attackDmg
variable is set to be the damage of the weapon that is currently equipped, by using the getEquipable()
function of InventoryComponent and checking index 0, which is the slot dedicated to the weapons.
public void hit(CombatStatsComponent attacker) {
if (attacker.getEntity().checkEntityType(EntityTypes.PLAYER) &&
(playerWeapon = attacker.getEntity().getComponent(InventoryComponent.class).getEquipable(0)) != null) {
attackDmg = (int) playerWeapon.getComponent(MeleeStatsComponent.class).getDamage();
int newHealth = getHealth() - (int)((1 - damageReduction) * attackDmg);
setHealth(newHealth);
}
else { //if it's not a player, or if it is a player without a weapon
int newHealth = getHealth() - (int)((1 - damageReduction) * attacker.getBaseAttack());
setHealth(newHealth);
}
}
However, if the player does not currently have a weapon equipped, the base attack of the player is pulled from the player config file (source/core/assets/configs/player.json) and this is used to make the attack. Or, if the attacker is an enemy (presumably attacking the player), the base attack of the enemy is used.
At the moment, there is no ability for a player to equip a weapon. This functionality is still being developed by Team 03 (Inventory). As such, to test that our code works, we used the below lines of code and added them to the hit function:
//this is how we would equip a weapon manually, given that the equip function has not yet been coded by the inventory team
Entity wep = WeaponFactory.createPlunger();
attacker.getEntity().getComponent(InventoryComponent.class).addItem(wep); //adding weapon to inventory
attacker.getEntity().getComponent(InventoryComponent.class).equipItem(wep); //equipping the weapon
This demonstrates that the change to weapon and player stats written in this function works. Try it out if you want. It's pretty fun! :)
- Lachlan Benson
- GitHub: @LachlanBenson
- Discord: Lachlan.Benson#4926
- Slack: Lachlan Benson