Skip to content

Demon Boss Task

gregchan550 edited this page Oct 20, 2023 · 7 revisions

Overview

The DemonBossTask class is responsible for executing the AI logic for the Demon Boss entity within the game. This class handles the actions that the Demon Boss executes. The class is designed to be added to an AiTaskComponent, which should be attached to a Demon Boss entity.

Usage

To utilize DemonBossTask, execute the following steps:

  1. Create an instance of DemonBossTask.
  2. Add it to an AiTaskComponent instance that is connected to a Demon Boss entity.
// Create a Demon Boss Entity
demon = MobBossFactory.createDemonBoss();

// Create an AiTaskComponent instance
AITaskComponent aiTaskComponent = new AITaskComponent();

// Add the DemonBossTask to the AiTaskComponent
aiTaskComponent.addTask(new DemonBossTask());

// Add AiTaskComponent to Droid entity
demon.addComponent(aiTaskComponent);

IMG_0075

State Management: update() and changeState(DemonState state)

The update() and changeState(DemonState state) methods manage the Demon Boss's states and transitions. These methods toggle between multiple states described by the DemonState enum: TRANSFORM, IDLE, SMASH, BREATH, CLEAVE, TAKE_HIT, CAST, WALK, and DEATH.

State Descriptions

TRANSFORM
  • Description: Starting state, where the Demon Boss comes into existence on the screen.
  • Behavior: Triggers the starting transform animation.
  • Transition: After the starting animation is finished, it will automatically change to the IDLE state, but if health drops to 0 before the transformation is complete then it'll transition to the DEATH state.
IDLE
  • Description: Default state, initiates the jump(Vector2 finalPos) method.
  • Behavior: Moves the Demon Boss to a new position 3 units away from the current position.
  • Transition: Changes state to SMASH.
SMASH
  • Description: Demon Boss landing onto an area and dealing damage to the surrounding area.
  • Behavior: All human entities within the SMASH_RADIUS will receive SMASH_DAMAGE from using jumpComplete() method.
  • Transition: Calls either the fireBreath() or the cleave() method for transition. Changes to BREATH state if there aren't any human entities nearby. Otherwise, it will transition to the CLEAVE state.
BREATH
  • Description: Demon Boss breaths fireballs towards the human entities.
  • Behavior: Launches an given amount of projectiles with a given effect at the human entities.
  • Transition: Transitions to IDLE once sequence is complete.
CLEAVE
  • Description: Demon Boss attacks the nearest human entity (target).
  • Behavior: Deals CLEAVE_DAMAGE to the target.
  • Transition: Transitions to IDLE once sequence is complete.
TAKE_HIT
  • Description: This state is activated when health drops to half or lower.
  • Behavior: When Demon Boss's health drops to half, a different animation will be played and halfHealth() is called to activate CAST state afterwards.
  • Transition: Transitions to CAST once animation is complete.
CAST
  • Description: When Demon Boss's health drops to half it starts healing by HEALTH_TO_ADD every HEAL_TIMES seconds.
  • Behavior: Demon Boss's health will increase by HEALTH_TO_ADD every HEAL_TIMES seconds.
  • Transition: Transitions to IDLE once sequence is complete.
WALK
  • Description: The walking state with animation.
  • Behavior: Triggers WALK.
DEATH
  • Description: This state is activated when the Demon Boss's health drops to zero.
  • Behavior: Flags Demon Boss for deletion once the death animation is finished and spawns Slimey Boy.
Constants and variables to be taken into consideration:
private static final int SMASH_DAMAGE = 30;
private static final int SMASH_RADIUS = 3;
private static final int CLEAVE_DAMAGE = 50;
private static final int HEALTH_TO_ADD = 10;
private static final int HEAL_TIMES = 10;

private int numBalls = 3; // numbers of projectiles to be fired
private boolean aoe = true; // effect the projectile will apply
private ProjectileEffects effect = ProjectileEffects.BURN; // whether the effect will be applied in a radius or not

Method that calls the event that corresponds with the state:

private void animate() {
    // Check if same animation is being called
    if (prevState.equals(state)) {
        return; // skip rest of function
    }

    switch (state) {
        case CAST -> demon.getEvents().trigger("demon_cast_spell");
        case IDLE -> demon.getEvents().trigger("demon_idle");
        case WALK -> demon.getEvents().trigger("demon_walk");
        case DEATH -> demon.getEvents().trigger("demon_death");
        case BREATH -> demon.getEvents().trigger("demon_fire_breath");
        case SMASH -> demon.getEvents().trigger("demon_smash");
        case CLEAVE -> demon.getEvents().trigger("demon_cleave");
        case TAKE_HIT -> demon.getEvents().trigger("demon_take_hit");
        case TRANSFORM -> demon.getEvents().trigger("transform");
        default -> logger.debug("Demon animation {state} not found");
    }
    prevState = state;
}

NOTE: All the events triggered in this class are captured by event listeners in DemonAnimationController.

Changing Positions: jump(Vector2 finalPos)

This method takes a parameter that uses the value returned by getJumpPos(). This method moves the Demon Boss from the original position to a new position specified by the param with a new MovementTask(). jump(Vector2 finalPos) also triggers the relevant sound events and switches the state to SMASH.

jumpTask = new MovementTask(finalPos);
jumpTask.create(owner);
jumpTask.start();

Selecting New Position: getJumpPos()

This method returns a value of type Vector2 for the jump(Vector2 finalPos) to use. getJumpPos() returns a valid position 3 units away from the current position.

private Vector2 currentPos;
currentPos = demon.getPosition();

Verifying Whether Jump Sequence is Completed: jumpComplete()

This method checks whether the Demon Boss has completed the jump i.e. moved from the current position to the finalPos and stops the jumpTask. It also deals AOE damage to the surrounding Human Entities by using the applyAoeDamage(Array<Entity> targets, int damage) and getNearbyHumans(int radius) methods.

applyAoeDamage(getNearbyHumans(SMASH_RADIUS), SMASH_DAMAGE);

Appling AOE damage to targets: applyAoeDamage(Array<Entity> targets, int damage)

This method applies SMASH_DAMAGE to all the targets provided by getNearbyHumans(int radius).

Returning List of Nearby Humans: getNearbyHumans(int radius)

This method returns a list of nearby entities with PhysicsLayer.HUMAN. Using existing functionality from the system, the method filters through the nearby entities to get a list of entities with the PhysicsLayer of HUMAN.

Array<Entity> nearbyEntities = ServiceLocator.getEntityService().getNearbyEntities(demon, radius);
Array<Entity> nearbyHumans = new Array<>();
// iterate through nearby entities checking if they have desired properties
for (int i = 0; i < nearbyEntities.size; i++) {
    Entity targetEntity = nearbyEntities.get(i);
    HitboxComponent targetHitbox = targetEntity.getComponent(HitboxComponent.class);
    if (targetHitbox == null) {
        break;
    }

    // check target layer
    if (!PhysicsLayer.contains(PhysicsLayer.HUMANS, targetHitbox.
            getLayer())) {
        break;
    }
    nearbyHumans.add(targetEntity);
}
return nearbyHumans;

Starting Fire Breath State: fireBreath()

This method changes the state to BREATH and handles the fire breath attack. This method creates projectiles based on the values specified by the following variables: effect, aoe and numBalls. Using changeBreathAttack(int numBalls, ProjectileEffects effect, boolean aoe), these variables can also be changed for fireBreath() to create the desired outcome. fireBreath()

Changing Fire Breath Variables: changeBreathAttack(int numBalls, ProjectileEffects effect, boolean aoe)

This method is for changing the fire breath variables: effect, aoe and numBalls.

Starting Cleave State: cleave()

This method changes the state to CLEAVE and handles the cleave attack. This method will only be called if there is a HUMAN target near the Demon Boss. Using existing functionality from the system, this method get the closest entity with the PhysicsLayer of HUMAN and deals CLEAVE_DAMAGE to that target.

Entity target = ServiceLocator.getEntityService().getClosestEntityOfLayer(demon, PhysicsLayer.HUMANS);

Healing: halfHealth()

This method changes the state to CAST and starts healing the Demon Boss. It is called when health drops below half. The Demon Boss's health increases by HEALTH_TO_ADD every HEAL_TIMES seconds.

Clone this wiki locally