Format existing scripts
This commit is contained in:
parent
18a4b02c3e
commit
644df0bd80
|
@ -1,7 +1,8 @@
|
|||
class_name DampenedCamera3D extends Camera3D
|
||||
|
||||
@export var target : Node3D
|
||||
@export var damping : bool
|
||||
@export var target: Node3D
|
||||
@export var damping: bool
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
|
@ -24,8 +25,10 @@ func _process(delta: float) -> void:
|
|||
target_pos.y = lerp(global_position.y, target_pos.y, 20 * delta)
|
||||
global_position = target_pos
|
||||
|
||||
|
||||
func damp() -> void:
|
||||
damping = true
|
||||
|
||||
|
||||
func donmp() -> void:
|
||||
damping = false
|
||||
|
|
|
@ -7,7 +7,7 @@ extends PhysicsBody3D
|
|||
|
||||
## The character will be blocked from moving up slopes steeper than this angle
|
||||
## The character will be not be flagged as 'grounded' when stood on slopes steeper than this angle
|
||||
@export var slope_limit : float = 45
|
||||
@export var slope_limit: float = 45
|
||||
|
||||
## The character will automatically adjust height to step over obstacles this high
|
||||
@export var step_height := 0.2
|
||||
|
@ -17,13 +17,13 @@ extends PhysicsBody3D
|
|||
@export var snap_to_ground_distance := 0.2
|
||||
|
||||
@export_group("Connector Nodes")
|
||||
@export var head : Node3D
|
||||
@export var body : Node3D
|
||||
@export var camera : DampenedCamera3D
|
||||
@export var head: Node3D
|
||||
@export var body: Node3D
|
||||
@export var camera: DampenedCamera3D
|
||||
|
||||
## A reference to the collision shape this physics body is using
|
||||
## (It's just a bit easier rather than aquiring the reference via code)
|
||||
@export var collision_shape : CollisionShape3D
|
||||
@export var collision_shape: CollisionShape3D
|
||||
|
||||
@export_group("Advanced")
|
||||
## Stop movement under this distance, but only if the movement touches at least 2 steep slopes
|
||||
|
@ -60,37 +60,38 @@ extends PhysicsBody3D
|
|||
## accurate. 4 is a decent number for low poly terrain!
|
||||
@export var max_iteration_count := 4
|
||||
|
||||
|
||||
|
||||
var jump_pressed := false
|
||||
|
||||
var gravity := 9.8
|
||||
|
||||
var _velocity: Vector3 = Vector3()
|
||||
var at_max_speed: bool = true
|
||||
|
||||
var _velocity : Vector3 = Vector3()
|
||||
var at_max_speed : bool = true
|
||||
var grounded: bool = false
|
||||
var ground_normal: Vector3
|
||||
var steep_slope_normals: Array[Vector3] = []
|
||||
var total_stepped_height: float = 0
|
||||
|
||||
var grounded : bool = false
|
||||
var ground_normal : Vector3
|
||||
var steep_slope_normals : Array[Vector3] = []
|
||||
var total_stepped_height : float = 0
|
||||
var escape_pressed: int
|
||||
var vertical_collisions: Array[KinematicCollision3D]
|
||||
var lateral_collisions: Array[KinematicCollision3D]
|
||||
var snap_collisions: Array[KinematicCollision3D]
|
||||
|
||||
var escape_pressed : int
|
||||
var vertical_collisions : Array[KinematicCollision3D]
|
||||
var lateral_collisions : Array[KinematicCollision3D]
|
||||
var snap_collisions : Array[KinematicCollision3D]
|
||||
enum MovementType { VERTICAL, LATERAL }
|
||||
|
||||
enum MovementType {VERTICAL, LATERAL}
|
||||
|
||||
func _ready() -> void:
|
||||
lock_mouse()
|
||||
|
||||
|
||||
func lock_mouse() -> void:
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
|
||||
|
||||
func unlock_mouse() -> void:
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
|
||||
|
||||
# TODO should this have an action associated?
|
||||
# TODO should it be in unhandled?
|
||||
func _input(event: InputEvent) -> void:
|
||||
|
@ -100,6 +101,7 @@ func _input(event: InputEvent) -> void:
|
|||
head.rotate_x(-motion.relative.y * mouse_sensitivity)
|
||||
head.rotation.x = clamp(head.rotation.x, -1.4, 1.4)
|
||||
|
||||
|
||||
# TODO should this be in unhandled input?
|
||||
# Input buffering? lol lmao
|
||||
func get_input() -> Vector2:
|
||||
|
@ -117,12 +119,12 @@ func get_input() -> Vector2:
|
|||
jump_pressed = Input.is_action_just_pressed("cc_jump")
|
||||
|
||||
if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED:
|
||||
return Vector2(0,0)
|
||||
return Vector2(0, 0)
|
||||
|
||||
if Input.is_action_just_pressed("cc_sprint"):
|
||||
at_max_speed = !at_max_speed
|
||||
|
||||
var input_dir : Vector2 = Vector2()
|
||||
var input_dir: Vector2 = Vector2()
|
||||
if Input.is_action_pressed("cc_forward"):
|
||||
input_dir += Vector2.UP
|
||||
if Input.is_action_pressed("cc_backward"):
|
||||
|
@ -136,6 +138,7 @@ func get_input() -> Vector2:
|
|||
# Local rotation is fine given the parent isn't rotating ever
|
||||
return input_dir.rotated(-body.rotation.y)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
# Before Move
|
||||
var _desired_horz_velocity := get_input()
|
||||
|
@ -164,7 +167,7 @@ func _physics_process(delta: float) -> void:
|
|||
|
||||
|
||||
# Entry point to moving
|
||||
func move(intended_velocity : Vector3, delta : float) -> void:
|
||||
func move(intended_velocity: Vector3, delta: float) -> void:
|
||||
var start_position := position
|
||||
|
||||
var lateral_translation := horz(intended_velocity * delta)
|
||||
|
@ -183,29 +186,45 @@ func move(intended_velocity : Vector3, delta : float) -> void:
|
|||
# An initial grounded check is important because ground normal is used
|
||||
# to detect seams with steep slopes; which often are collided with before the ground
|
||||
if vertical_translation.y <= 0:
|
||||
var initial_grounded_collision := move_and_collide(Vector3.DOWN * ground_cast_distance, true, depenetration_margin)
|
||||
var initial_grounded_collision := move_and_collide(
|
||||
Vector3.DOWN * ground_cast_distance, true, depenetration_margin
|
||||
)
|
||||
if initial_grounded_collision:
|
||||
if initial_grounded_collision.get_normal(0).angle_to(Vector3.UP) < deg_to_rad(slope_limit):
|
||||
if (
|
||||
initial_grounded_collision.get_normal(0).angle_to(Vector3.UP)
|
||||
< deg_to_rad(slope_limit)
|
||||
):
|
||||
grounded = true
|
||||
ground_normal = initial_grounded_collision.get_normal(0)
|
||||
|
||||
# === Iterate Movement Laterally
|
||||
var lateral_iterations := 0
|
||||
while lateral_translation.length() > 0 and lateral_iterations < max_iteration_count:
|
||||
|
||||
lateral_translation = move_iteration(MovementType.LATERAL, lateral_collisions, initial_lateral_translation, lateral_translation)
|
||||
lateral_translation = move_iteration(
|
||||
MovementType.LATERAL,
|
||||
lateral_collisions,
|
||||
initial_lateral_translation,
|
||||
lateral_translation
|
||||
)
|
||||
lateral_iterations += 1
|
||||
|
||||
# De-jitter by just ignoring lateral movement
|
||||
# (multiple steep slopes have been collided, but movement is very small)
|
||||
if steep_slope_normals.size() > 1 and horz(position - start_position).length() < steep_slope_jitter_reduce:
|
||||
if (
|
||||
steep_slope_normals.size() > 1
|
||||
and horz(position - start_position).length() < steep_slope_jitter_reduce
|
||||
):
|
||||
position = start_position
|
||||
|
||||
# === Iterate Movement Vertically
|
||||
var vertical_iterations := 0
|
||||
while vertical_translation.length() > 0 and vertical_iterations < max_iteration_count:
|
||||
|
||||
vertical_translation = move_iteration(MovementType.VERTICAL, vertical_collisions, initial_vertical_translation, vertical_translation)
|
||||
vertical_translation = move_iteration(
|
||||
MovementType.VERTICAL,
|
||||
vertical_collisions,
|
||||
initial_vertical_translation,
|
||||
vertical_translation
|
||||
)
|
||||
vertical_iterations += 1
|
||||
|
||||
# Don't include step height in actual velocity
|
||||
|
@ -236,14 +255,23 @@ func move(intended_velocity : Vector3, delta : float) -> void:
|
|||
var ground_snap_iterations := 0
|
||||
var ground_snap_translation := Vector3.DOWN * snap_to_ground_distance
|
||||
while ground_snap_translation.length() > 0 and ground_snap_iterations < max_iteration_count:
|
||||
|
||||
ground_snap_translation = move_iteration(MovementType.VERTICAL, snap_collisions, Vector3.DOWN, ground_snap_translation)
|
||||
ground_snap_translation = move_iteration(
|
||||
MovementType.VERTICAL, snap_collisions, Vector3.DOWN, ground_snap_translation
|
||||
)
|
||||
ground_snap_iterations += 1
|
||||
|
||||
# Decide whether to keep the snap or not
|
||||
if snap_collisions.is_empty():
|
||||
var after_snap_ground_test := move_and_collide(Vector3.DOWN * ground_cast_distance, true, depenetration_margin)
|
||||
if after_snap_ground_test and after_snap_ground_test.get_normal(0).angle_to(Vector3.UP) < deg_to_rad(slope_limit):
|
||||
var after_snap_ground_test := move_and_collide(
|
||||
Vector3.DOWN * ground_cast_distance, true, depenetration_margin
|
||||
)
|
||||
if (
|
||||
after_snap_ground_test
|
||||
and (
|
||||
after_snap_ground_test.get_normal(0).angle_to(Vector3.UP)
|
||||
< deg_to_rad(slope_limit)
|
||||
)
|
||||
):
|
||||
# There was no snap collisions, but there is ground underneath
|
||||
# This can be due to an edge case where the snap movement falls through the ground
|
||||
# Why does this check not fall through the ground? I don't know
|
||||
|
@ -252,7 +280,10 @@ func move(intended_velocity : Vector3, delta : float) -> void:
|
|||
else:
|
||||
# No snap collisions and no floor, reset
|
||||
position = before_snap_pos
|
||||
elif !(snap_collisions[snap_collisions.size() - 1].get_normal(0).angle_to(Vector3.UP) < deg_to_rad(slope_limit)):
|
||||
elif !(
|
||||
snap_collisions[snap_collisions.size() - 1].get_normal(0).angle_to(Vector3.UP)
|
||||
< deg_to_rad(slope_limit)
|
||||
):
|
||||
# Collided with steep ground, reset
|
||||
position = before_snap_pos
|
||||
else:
|
||||
|
@ -261,9 +292,13 @@ func move(intended_velocity : Vector3, delta : float) -> void:
|
|||
|
||||
# Moves are composed of multiple iterates
|
||||
# In each iteration, move until collision, then calculate and return the next movement
|
||||
func move_iteration(movement_type: MovementType, collision_array : Array, initial_direction: Vector3, translation: Vector3) -> Vector3:
|
||||
|
||||
var collisions : KinematicCollision3D
|
||||
func move_iteration(
|
||||
movement_type: MovementType,
|
||||
collision_array: Array,
|
||||
initial_direction: Vector3,
|
||||
translation: Vector3
|
||||
) -> Vector3:
|
||||
var collisions: KinematicCollision3D
|
||||
|
||||
# If Lateral movement, try stepping
|
||||
if movement_type == MovementType.LATERAL:
|
||||
|
@ -274,7 +309,7 @@ func move_iteration(movement_type: MovementType, collision_array : Array, initia
|
|||
|
||||
var current_step_height := step_height
|
||||
var step_up_collisions := move_and_collide(Vector3.UP * step_height, false, 0)
|
||||
if (step_up_collisions):
|
||||
if step_up_collisions:
|
||||
current_step_height = step_up_collisions.get_travel().length()
|
||||
var raised_forward_collisions := move_and_collide(translation, false, 0)
|
||||
var down_collision := move_and_collide(Vector3.DOWN * current_step_height, false, 0)
|
||||
|
@ -282,17 +317,19 @@ func move_iteration(movement_type: MovementType, collision_array : Array, initia
|
|||
# Only step if the step algorithm landed on a walkable surface
|
||||
# AND the walk lands on a non-walkable surface
|
||||
# This stops stepping up ramps
|
||||
if (down_collision and
|
||||
down_collision.get_normal(0).angle_to(Vector3.UP) < deg_to_rad(slope_limit) and
|
||||
walk_test_collision and
|
||||
!walk_test_collision.get_normal(0).angle_to(Vector3.UP) < deg_to_rad(slope_limit)):
|
||||
if (
|
||||
down_collision
|
||||
and down_collision.get_normal(0).angle_to(Vector3.UP) < deg_to_rad(slope_limit)
|
||||
and walk_test_collision
|
||||
and !walk_test_collision.get_normal(0).angle_to(Vector3.UP) < deg_to_rad(slope_limit)
|
||||
):
|
||||
do_step = true
|
||||
|
||||
if do_step: # Keep track of stepepd distance to cancel it out later
|
||||
if do_step: # Keep track of stepepd distance to cancel it out later
|
||||
total_stepped_height += position.y - temp_position.y
|
||||
collisions = raised_forward_collisions
|
||||
camera.damp()
|
||||
else: # Reset and move normally
|
||||
else: # Reset and move normally
|
||||
position = temp_position
|
||||
collisions = move_and_collide(translation, false, depenetration_margin)
|
||||
|
||||
|
@ -322,8 +359,8 @@ func move_iteration(movement_type: MovementType, collision_array : Array, initia
|
|||
# These values shouldn't be calculated every frame; they only need to change
|
||||
# when the user defines the slope limit
|
||||
# But I'm lazy :)
|
||||
var min_block_angle : float
|
||||
var max_block_angle : float
|
||||
var min_block_angle: float
|
||||
var max_block_angle: float
|
||||
if movement_type == MovementType.LATERAL:
|
||||
min_block_angle = deg_to_rad(slope_limit)
|
||||
if grounded:
|
||||
|
@ -334,7 +371,6 @@ func move_iteration(movement_type: MovementType, collision_array : Array, initia
|
|||
min_block_angle = 0
|
||||
max_block_angle = deg_to_rad(slope_limit)
|
||||
|
||||
|
||||
# This algorithm for determining where to move on a collisions uses "projection plane"
|
||||
# Whatever surface the character hits, we generate a blocking "plane" that we will slide along
|
||||
#
|
||||
|
@ -351,11 +387,16 @@ func move_iteration(movement_type: MovementType, collision_array : Array, initia
|
|||
|
||||
# If collision happens on the "side" of the cylinder, treat it as a vertical
|
||||
# wall in all cases (we use the tangent of the cylinder)
|
||||
if (movement_type == MovementType.LATERAL and
|
||||
(collision_point.y > (collision_shape.global_position.y - cylinder.height / 2) + bottom_height)):
|
||||
projection_normal = collision_shape.global_position - collision_point
|
||||
projection_normal.y = 0
|
||||
projection_normal = projection_normal.normalized()
|
||||
if (
|
||||
movement_type == MovementType.LATERAL
|
||||
and (
|
||||
collision_point.y
|
||||
> (collision_shape.global_position.y - cylinder.height / 2) + bottom_height
|
||||
)
|
||||
):
|
||||
projection_normal = collision_shape.global_position - collision_point
|
||||
projection_normal.y = 0
|
||||
projection_normal = projection_normal.normalized()
|
||||
|
||||
# Otherwise, determine if the surface is a blocking surface
|
||||
elif surface_angle >= min_block_angle and surface_angle <= max_block_angle:
|
||||
|
@ -386,11 +427,13 @@ func move_iteration(movement_type: MovementType, collision_array : Array, initia
|
|||
var continued_translation := projection_plane.project(collisions.get_remainder())
|
||||
var initial_influenced_translation := projection_plane.project(initial_direction)
|
||||
|
||||
var next_translation : Vector3
|
||||
var next_translation: Vector3
|
||||
if initial_influenced_translation.dot(continued_translation) >= 0:
|
||||
next_translation = continued_translation
|
||||
else:
|
||||
next_translation = initial_influenced_translation.normalized() * continued_translation.length()
|
||||
next_translation = (
|
||||
initial_influenced_translation.normalized() * continued_translation.length()
|
||||
)
|
||||
|
||||
# See same_surface_adjust_distance
|
||||
if next_translation.normalized() == translation.normalized():
|
||||
|
@ -399,16 +442,17 @@ func move_iteration(movement_type: MovementType, collision_array : Array, initia
|
|||
return next_translation
|
||||
|
||||
|
||||
func already_touched_slope_close_match(normal : Vector3) -> bool:
|
||||
func already_touched_slope_close_match(normal: Vector3) -> bool:
|
||||
for steep_slope_normal in steep_slope_normals:
|
||||
if steep_slope_normal.distance_squared_to(normal) < 0.001:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
# I wrote this a while ago in Unity
|
||||
# I ported it here but I only have a vague grasp of how it works
|
||||
func relative_slope_normal(slope_normal : Vector3, lateral_desired_direction : Vector3) -> Vector3:
|
||||
func relative_slope_normal(slope_normal: Vector3, lateral_desired_direction: Vector3) -> Vector3:
|
||||
var slope_normal_horz := horz(slope_normal)
|
||||
var angle_to_straight := slope_normal_horz.angle_to(-lateral_desired_direction)
|
||||
var angle_to_up := slope_normal.angle_to(Vector3.UP)
|
||||
|
@ -435,8 +479,10 @@ func relative_slope_normal(slope_normal : Vector3, lateral_desired_direction : V
|
|||
|
||||
return emulated_normal.normalized()
|
||||
|
||||
|
||||
func horz(value: Vector3) -> Vector3:
|
||||
return Vector3(value.x,0,value.z)
|
||||
return Vector3(value.x, 0, value.z)
|
||||
|
||||
|
||||
func vert(value: Vector3) -> Vector3:
|
||||
return Vector3(0,value.y,0)
|
||||
return Vector3(0, value.y, 0)
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
extends Node3D
|
||||
|
||||
@export var target : Node3D
|
||||
@export var target: Node3D
|
||||
var currTransform: Transform3D
|
||||
var prevTransform: Transform3D
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
currTransform = Transform3D()
|
||||
|
@ -26,6 +27,7 @@ func _process(_delta: float) -> void:
|
|||
|
||||
transform = new_transform
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
prevTransform = currTransform
|
||||
currTransform = target.global_transform
|
||||
|
|
Loading…
Reference in New Issue