102 lines
2.8 KiB
GDScript3
102 lines
2.8 KiB
GDScript3
|
class_name SpinGlideAbility extends RunnerAbility
|
||
|
|
||
|
const PUNT_ACCELERATION: float = 30.0
|
||
|
const DROP_KICK_FACTOR: float = 3.0
|
||
|
const KNOCKBACK_ATTENUATION: float = 0.125
|
||
|
|
||
|
@export var animation_in_water: StringName
|
||
|
@export var timeout: float = 1.0
|
||
|
@export var drop_factor: float = 1.0
|
||
|
|
||
|
var saved_gravity_scale: float
|
||
|
var ending: bool
|
||
|
var timer: float
|
||
|
var in_water: bool
|
||
|
|
||
|
func begin(runner: Runner) -> void:
|
||
|
saved_gravity_scale = runner.gravity_scale
|
||
|
runner.gravity_scale = 0.01
|
||
|
runner.linear_velocity = runner.linear_velocity.slide(runner.up_normal)
|
||
|
ending = false
|
||
|
timer = timeout
|
||
|
in_water = false
|
||
|
|
||
|
func integrate_forces(
|
||
|
runner: Runner,
|
||
|
body_state: PhysicsDirectBodyState3D
|
||
|
) -> void:
|
||
|
if (
|
||
|
in_water or body_state.total_gravity.dot(Vector3.UP) > 0.0
|
||
|
) and not ending:
|
||
|
in_water = true
|
||
|
if runner.animation_player.current_animation != animation_in_water:
|
||
|
runner.animation_player.play(animation_in_water)
|
||
|
body_state.linear_velocity += drop_factor*runner.basis.z/2.0
|
||
|
body_state.linear_velocity -= (
|
||
|
runner.up_normal *
|
||
|
(runner.impetus*runner.basis).z *
|
||
|
runner.run_acceleration *
|
||
|
body_state.step
|
||
|
)
|
||
|
timer -= body_state.step
|
||
|
if timer <= 0.0 or (
|
||
|
body_state.total_gravity.dot(Vector3.UP) < 0.0
|
||
|
):
|
||
|
on_repeated_input(runner)
|
||
|
elif not runner.wall_normal.is_zero_approx():
|
||
|
runner.change_state(&'wall_slide')
|
||
|
elif ending:
|
||
|
if not runner.floor_normal.is_zero_approx():
|
||
|
runner.audio_player.stream = runner.land_sound
|
||
|
runner.audio_player.play()
|
||
|
runner.change_state(&'run')
|
||
|
else:
|
||
|
timer -= body_state.step
|
||
|
if timer <= 0.0:
|
||
|
on_repeated_input(runner)
|
||
|
for i in body_state.get_contact_count():
|
||
|
var other := body_state.get_contact_collider_object(i)
|
||
|
if other is Runner:
|
||
|
var rother := other as Runner
|
||
|
rother.knockback(
|
||
|
runner.global_position,
|
||
|
runner.mass*PUNT_ACCELERATION*(
|
||
|
DROP_KICK_FACTOR if ending else 1.0
|
||
|
)*KNOCKBACK_ATTENUATION
|
||
|
)
|
||
|
elif other is RigidBody3D:
|
||
|
var rother := other as RigidBody3D
|
||
|
rother.apply_force(
|
||
|
runner.mass*(
|
||
|
runner.impetus + runner.up_normal
|
||
|
).normalized()*PUNT_ACCELERATION*(
|
||
|
DROP_KICK_FACTOR if ending else 1.0
|
||
|
),
|
||
|
body_state.get_contact_collider_position(i) -
|
||
|
rother.global_position
|
||
|
)
|
||
|
|
||
|
func orientation(runner: Runner) -> Vector3:
|
||
|
if in_water:
|
||
|
return runner.linear_velocity
|
||
|
else:
|
||
|
return runner.basis.z
|
||
|
|
||
|
func animation_speed(runner: Runner) -> float:
|
||
|
return 1.0 + runner.linear_velocity.length()/20.0
|
||
|
|
||
|
func end(runner: Runner) -> void:
|
||
|
runner.gravity_scale = saved_gravity_scale
|
||
|
|
||
|
func on_repeated_input(runner: Runner) -> void:
|
||
|
if in_water:
|
||
|
runner.change_state(&'swim')
|
||
|
elif not ending:
|
||
|
runner.audio_player.stream = runner.jump_sound
|
||
|
runner.audio_player.play()
|
||
|
runner.gravity_scale = saved_gravity_scale
|
||
|
runner.linear_velocity -= (
|
||
|
drop_factor*runner.top_run_speed*runner.up_normal
|
||
|
)
|
||
|
ending = true
|