stick-the-quick/characters/thinkers/FollowerThinker.gd

69 lines
1.9 KiB
GDScript

class_name FollowerThinker extends NPCRunnerThinker
@export var target: Node3D
@export var target_distance: float = 0.0
var raycast: PhysicsRayQueryParameters3D
func _ready() -> void:
raycast = PhysicsRayQueryParameters3D.new()
func impetus() -> Vector3:
var displacement := (
target.global_position - runner.global_position
).slide(runner.up_normal)
if displacement.length() <= target_distance:
return Vector3.ZERO
else:
return displacement.limit_length()
func should_jump() -> bool:
if (
runner.state == &'jump' or
runner.state == &'wall_jump' or
runner.state == &'ability'
):
return false
var displacement := (
target.global_position - runner.global_position
)
var vertical_displacement := displacement.project(runner.up_normal)
var horizontal_displacement := displacement - vertical_displacement
if vertical_displacement.normalized().dot(runner.up_normal) <= 0.0:
vertical_displacement = Vector3.ZERO
if displacement.length() <= target_distance:
return false
if vertical_displacement.length() > target_distance:
return true
if runner.state == &'wall_slide':
return (
runner.wall_normal.dot(
horizontal_displacement.normalized()
) > 0.25 or
runner.linear_velocity.normalized().dot(Vector3.UP) < -0.25
)
if not runner.wall_normal.is_zero_approx():
return true
if target is PhysicsBody3D:
raycast.exclude = [self, target]
else:
raycast.exclude = [self]
raycast.from = runner.global_position
raycast.to = runner.global_position + horizontal_displacement
var raycast_result := (
runner.get_world_3d().direct_space_state.intersect_ray(raycast)
)
if raycast_result.is_empty():
return false
if (
raycast_result[&'normal'].dot(-horizontal_displacement.normalized()) >
0.25
):
return true
return false
func should_do_ability() -> bool:
return runner.state == &'ability' and (
target.global_position - runner.global_position
).normalized().dot(runner.up_normal) < -0.25