Deflecting Component - UQcsse3200/2023-studio-3 GitHub Wiki

DeflectingComponent Documentation

Overview

The DeflectingComponent is a component that may be added to any Entity type object, and "deflect" another incoming entity by reversing its horizontal direction. The deflection occurs upon collision and is mainly used for mob entities to deflect incoming projectiles, changing not only the horizontal movement direction, but also the damage layer of the said projectile.

However, its implementation and configuration were flexibly created such that any entity may implement this feature. E.g. A wall entity deflecting mobs/mob balls.

Usage

To use the DeflectingComponent, simply initialize the component with the desired target and damaging layers, and maximum deflect amount. Finally, add it to the specified game entity.

Entity entity = NPCFactory.createMeleeBaseNPC();
int maxDeflectAmount = 10;
DeflectingComponent deflectComponent = new DeflectingComponent(PhysicsLayer.PROJECTILE, PhysicsLayer.TOWER, maxDeflectAmount);
entity.addComponent(deflectComponent);

Configuration

As established, the component was originally made for mob entities deflecting projectiles. However, the design made it suitable for any entity to utilize this component with the right layers and configurations provided.

  • targetLayer: The incoming target layer to determine if said entity should be deflected. All other layers will be ignored for this component's functionality. i.e. if target layer is PhysicsLayer.PROJECTILE, only projectiles will be deflected.
  • dmgLayer: This reverts the damaging target layer of the deflected entity. i.e. If the value is PhysicsLayer.TOWER, the deflected projectile will now target towers instead of its original target.
  • deflectLimitAmount: This specifies the maximum number of deflections to occur before the indefinite disabling of this component.

Please note that there are no validation checks for this amount. Thus, the amount < 0 is permitted but the component will simply be indefinitely disabled.

Requirements

Please ensure these requirements are fulfilled for the DeflectingComponent so that its intended functionality may be in full effect.

  1. Projectile should have an AITaskComponent and a TrajectTask added with a set target. More specifically, there should be a viable x-coordinate target. This x-value should be large enough so that the projectile is always moving horizontally.
  2. Projectile should have a PhysicsMovementComponent with a set target.
  3. collisionStart event listener exists and is triggered accordingly.
  4. Projectile must have a TouchAttackComponent that has a target layer of attack.
  5. Mob has a CombatStatsComponent with a health > 0.

Functionality

The component adds a method to the collisionStart event called deflectProj, holding the logic of the deflection. The way it works is that it disposes all of the deflected entity's tasks and adds a new TrajectTask with the specified target's x-coordinate made negative. This is why it's important for the x direction to be substantial for the constant movement of the projectile. i.e. a negative direction.x of 0 will simply be 0, resulting in no movement of the projectile.

projectile.getComponent(AITaskComponent.class).disposeAll();

// Obtain current direction of projectile
Vector2 direction = projectile.getComponent(PhysicsMovementComponent.class).getTarget();

projectile.getComponent(AITaskComponent.class)
        .addTask(new TrajectTask(new Vector2(-direction.x, direction.y)));

Component will also change the projectile's scale-x to negative for the a reverse visual image and alter the damaging layer of its TouchAttackComponent to the initialised configuration.

// Change target layer of projectile.
projectile.getComponent(TouchAttackComponent.class)
        .setTargetLayer(dmgLayer);
entity.getEvents().trigger("shootStart");

// Make sure projectile is not deleted in the next frame. 
projectile.setFlagForDelete(false);

A resetHealth() method will also be called upon event activation, that simply resets the health of the mob entity to full health to ensure that it doesn't die when it can still deflect.

Component will keep decrementing the deflectLimitAmount every time a collision happens. When it reaches 0 or below, the component will be disabled. Projectile's deletion flag is set to false no matter its initial self-disposing configuration. This is to ensure the deflection occurs in each frame. However, the projectile may still be disposed of when it hits the damaging layer, with its disposeOnHit attribtue defined in the TouchAttackComponent.

Best Practices

  • Any other tasks the projectile possessed (or target entity) will be disposed of. As a result, if the projectile's functionality depends on tasks other than the TrajectTask, it will be ignored.
  • However, the projectile's components will still be in full effect after the deletion. Thus, components like SplitFireWorksComponent and RicochetComponent will still apply. If these components depends on certain configurations that will affect its functionality, certain conflicts may arise. i.e. RicochetComponent only bounces off certain target layers like mob entities. Thus, further modifications to these components, or self, may be required.

Testing

The deflection of projectiles has been confirmed visually, with its the projectile damaging towers instead of mobs. JUnit testing has confirmed these cases:

  1. Component's existence when added to entity.
  2. Projectile is not disposed of on collision despite its initial configuration of the TouchAttackComponent's disposeOnHit being set to true.
  3. deflectProj logic invoked upon collisionStart event.
  • For one time.
  • For multiple amount of times.
  1. Reverse image scale.
  2. Health remains the same when component is enabled.
  3. Reverse effects of all aforementioned logic when component is disabled. i.e. deflectLimitAmount reaches 0.