class_name FlyAbility extends RunnerAbility const LIFT_SCALE: float = 10000.0 const TILT_LIFT_SCALE: float = 13.0 const MAX_BACKWARD_IMPETUS: float = 0.5 @export var tilt: float = 0.375 @export var thrust: float = 0.5 @export var lift: float = 1.0 var saved_gravity_scale: float = -1.0 var saved_deceleration: float = -1.0 var saved_speed_cap: float = -1.0 func begin(runner: Runner) -> void: if runner.floor_normal.is_zero_approx(): saved_gravity_scale = runner.gravity_scale saved_deceleration = runner.run_deceleration saved_speed_cap = runner.top_run_speed runner.gravity_scale /= 4.0 runner.run_deceleration = 0.0 runner.top_run_speed = INF else: runner.change_state(&'jump') func integrate_forces( runner: Runner, body_state: PhysicsDirectBodyState3D ) -> void: if not runner.floor_normal.is_zero_approx(): runner.change_state(&'fall') elif not runner.wall_normal.is_zero_approx(): runner.change_state(&'wall_slide') else: body_state.linear_velocity -= ( impetus_multiplier * runner.impetus.project(runner.basis.z) * runner.run_acceleration * body_state.step ) var speed_factor = ( body_state.linear_velocity.slide( Vector3.UP ).length() / saved_speed_cap ) var local_impetus := runner.impetus*runner.basis var real_tilt: float = local_impetus.z*tilt/( 1.0 + lift*TILT_LIFT_SCALE*(speed_factor**2.0) ) if real_tilt < 0.0: runner.up_normal = runner.up_normal.lerp( Vector3.UP - runner.basis.z, -real_tilt ).normalized() else: runner.up_normal = runner.up_normal.lerp( Vector3.UP + runner.basis.z, real_tilt ).normalized() body_state.linear_velocity = ( body_state.linear_velocity.slide(Vector3.UP) ) body_state.linear_velocity += ( runner.basis.z * thrust * runner.run_acceleration * max(local_impetus.z, -MAX_BACKWARD_IMPETUS) * body_state.step ) body_state.linear_velocity -= ( Vector3.UP * lift*LIFT_SCALE * real_tilt * (speed_factor**2.0) * body_state.step ) func orientation(runner: Runner) -> Vector3: return runner.linear_velocity func animation_speed(runner: Runner) -> float: return 1.0 + runner.linear_velocity.length()/10.0 func end(runner: Runner) -> void: if saved_gravity_scale > 0.0: runner.gravity_scale = saved_gravity_scale saved_gravity_scale = -1.0 if saved_deceleration > 0.0: runner.run_deceleration = saved_deceleration saved_deceleration = -1.0 if saved_speed_cap > 0.0: runner.top_run_speed = saved_speed_cap saved_speed_cap = -1.0 func on_repeated_input(runner: Runner) -> void: runner.change_state(&'fall')