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 isPhysicsLayer.PROJECTILE, only projectiles will be deflected.dmgLayer: This reverts the damaging target layer of the deflected entity. i.e. If the value isPhysicsLayer.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.
- Projectile should have an AITaskComponent and a
TrajectTaskadded 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. - Projectile should have a
PhysicsMovementComponentwith a set target. collisionStartevent listener exists and is triggered accordingly.- Projectile must have a
TouchAttackComponentthat has a target layer of attack. - Mob has a
CombatStatsComponentwith 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
deflectLimitAmountevery 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 itsdisposeOnHitattribtue defined in theTouchAttackComponent.
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
SplitFireWorksComponentandRicochetComponentwill still apply. If these components depends on certain configurations that will affect its functionality, certain conflicts may arise. i.e.RicochetComponentonly 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:
- Component's existence when added to entity.
- Projectile is not disposed of on collision despite its initial configuration of the
TouchAttackComponent'sdisposeOnHitbeing set to true. deflectProjlogic invoked uponcollisionStartevent.
- For one time.
- For multiple amount of times.
- Reverse image scale.
- Health remains the same when component is enabled.
- Reverse effects of all aforementioned logic when component is disabled. i.e. deflectLimitAmount reaches 0.