Dodging Component - UQcsse3200/2023-studio-3 GitHub Wiki
DodgingComponent Documentation
Overview
The DodgingComponent is a component that works cohesively with the MobDodgeTask and introduces a dodging mechanism based on the detection of another entity (such as a projectile). Ultimately, it adds a method to an event listener, dodgeIncomingEntity, and utilizes game's built-in raycast mechanism to detect another entity. If the entity is detected, the dodge task will trigger this event listener and will change the mob's vertical direction based on its location on the map.
For simplicity of explanation, the entity detected from now on will be referred to as a projectile since it was its intended functionality but note that the detected entity may be changed based on the target layer initialised.
Usage
To use this DodgingComponent, make sure to add the MobDodgeTask to the specified entity before adding the component itself with its desired configurations.
Entity entity = NPCFactory.createMeleeBaseNPC();
DodgingComponent dodgeComponent = new DodgingComponent(PhysicsLayer.PROJECTILE);
// Priority is 5 here, just ensure it is higher than the other tasks.
entity.getComponent(AITaskComponent.class).addTask(new MobDodgeTask(new Vector(2f, 2f), 2f, 5));
entity.addComponent(dodgeComponent);
Configuration
This component allows flexibility in configuration of the dodging mechanism, with only the detected target layer deemed essential for its initialisation.
targetLayer: The target layer to be detected from the raycast. i.e.PhysicsLayer.PROJECTILE.rangeDetection: A float value representing the horizontal range where the entity of thetargetLayeris detected, activating the dodge event. If not specified, it is initialised to be 0.25f.dodgeSpeed: The vertical speed of the targeted mob entity when dodging the projectile. If not specified, it is initialised to be 1.75f.
Requirements
MobDodgeTaskto be added to the AITaskComponent with a higher priority level than the otherMobWanderTask.- Although this component utilises the
MobDodgeTask, the component should still have aMobWanderTaskwith a lower priority level. The direction of this task should have an existing horizontal velocity that is > 0f. - Should have a
PhysicsMovementComponentwith a set target.
Functionality
Logic
This component's logic simply detects another target layer within a certain range proximity and moves the entity upwards or downwards by providing a vertical target and velocity.
This proximity detection is constructed through creating a Vector2 max range based on the initialised rangeDetection variable, and using the PhysicsService raycast boolean identifier.
private boolean isTargetVisible(Vector2 mobPos) {
Vector2 maxRange = new Vector2(mobPos.x - rangeDetection, mobPos.y);
// check also the upper and lower boundaries of the mob with the offset y mob
// detection.
Vector2 upperYMaxRangePos = new Vector2(mobPos.x - 3, mobPos.y - Y_OFFSET_MOB_DETECTION);
Vector2 lowerYMaxRangePos = new Vector2(mobPos.x - 3, mobPos.y + Y_OFFSET_MOB_DETECTION);
// Raycast the upper, middle and lower detection range.
return physics.raycast(mobPos, maxRange, targetLayer, hit)
|| physics.raycast(mobPos, upperYMaxRangePos, targetLayer, hit)
|| physics.raycast(mobPos, lowerYMaxRangePos, targetLayer, hit);
}
The mobPos is a Vector2 value retrieved from the center position of the mob entity.
The hit variable is a RaycastHit variable. For more info, confer the documentation.
Offset accomodation - Triple raycast
The reason for raycasting based on the upperYMaxRangePos and the lowerYMaxRangePos is to accomodate for the collider sizes of the mob and projectile entity with respect to the raycast. If this is not accomplished, the raycast from the center position of the mob entity may not be able to detect the projectile entity, even if the entity ends up colliding with the projectile due to collider sizes.
This
Y_OFFSET_MOB_DETECTIONfor the triple raycasting is initialised to be 0.35f -> Can be altered if desired.
The mob's vertical direction of dodge depends on its respective location on the map. If the mob is at the upper half quadrant, the mob will dodge downwards.
private void setVerticalAngleDirection(float y) {
entity.getComponent(PhysicsMovementComponent.class).setTarget(new Vector2(0, y));
}
setVerticalAngleDirection(mobPos.y > 3.5 ? mobPos.y - 15 : mobPos.y + 15);
In the time of writing this documentation, vertical half map size is 3.5. Please change this accordingly if the map / lane sizes changes.
As seen, the vertical target direction of the PhysicsMovementComponent is altered by 15 accordingly. This is what makes the mobs go upward or downward.
Please note: This dodging based on map location tend to make dodging mobs migrate to the middle of the map. Further extensions of this component could include a random direction identifier, encouraging sporadic dodging mechanisms instead of predictable patterns emerging.
Event triggers based on task
In this case, we utilised a MobDodgeTask to trigger the event of dodgingIncomingEntity. This detection will activate after every set interval. In this case, the set interval is 500ms. Set interval is crucial as it prevents detection to be checked after every frame of the running game.
/**
* Run a frame of the task. In this extension of the update(), the
* "dodgeIncomingEntity" event will be detected and triggered on set intervals.
*/
@Override
public void update() {
super.update();
if (timeSource.getTime() >= endTime) {
owner.getEntity().getEvents().trigger("dodgeIncomingEntity",
owner.getEntity().getCenterPosition());
endTime = timeSource.getTime() + DELAY_INTERVAL; // update time
}
}
If this component was to be used outside of dodging mobs, please make another respective task with the same logic that has a higher priority than the other tasks.
Best Practices
Map boundaries
Please ensure map boundaries with appropriate collision layers are put in place for the respective mob entity. As such, the mob entity should not be able to go of map bounds due to its dodging mechanisms. Does not particularly apply for the current mechanism but more so for the direction-randomiser extension.
Speed
If dodge speed is to be initialised normally, ensure it is an appropriate value - especially in coherence with the range detection variable. For instance, setting the dodge speed to be a very low value with a low detection range could make the mob still collide with the projectile, ultimately rendering the component useless.
The speed should always be > 0f.
Range detection
The default range detection is 0.25f and is deemed to be an appropriate value for a dodging speed of >1.25f. Feel free to change this accordingly but going below this value may result in the mob still colliding with the projectile depending on the vertical and horizontal speed and its collider sizes. On the other hand, going above 1.25f results the projectile dodging the incoming projectile at a very far distance, defeating the purpose of the dodging aspect of the component.
That being said, feel free to experiment and use values desired that are outside the recommended range.
Testing
Visually, the mob with the MobDodgeTask and DodgingComponent dodges the incoming projectile appropriately based on its respective position on the map.
JUnit confirmed the existence of this component when added and the number of invocations for the event to be triggered based on the specified distance of the two entities' locations.