Godot Version
v4.4.1.stable.official [49a5bc7b6]
Question
I recently was having a couple of friends test a control scheme for a game I’m working on and one of them said the jumps felt floatty, so I upped the gravity and started to notice a couple of problems with falling through the floor under the conditions listed below…
- Only when the character is moving backwards, towards the camera and is landing from a backwards jump. I have yet to replicate this with a fall, but it may still be possible.
- At gravity 9.8, we have no negative effects.
- At gravity ~19.6, the character will sink part way into the ground on landing and stick for a moment before raising back up to ground level and continuing to move. If they land into a hillside, they may or may not phase through the terrain.
- At gravity ~29.4, the character will phase through the floor without fail.
- This happens regardless of whether I increase gravity directly or use a script to increase gravity only on the decent.
For the record I am using the Terrain3D plugin and a characterbody3D for the actual character. I have had it previously mentioned that this may somehow be related to the camera. If that is the case, the camera3D is attached to a Node3D centered on the character. The Node3d is at position 0, 0, 0 and rotation -15, 0, 0. The camera itself is at position 0, 75, 0 and rotation -90, -180, 0. The Node3D also includes a script for a lag in motion, smoothing, and a “look ahead” that pans in the direction the character is traveling. Script included here.
extends Node3D
@export var follow_target: Node3D
@export var follow_speed: float = 5.0
@export var look_ahead_distance: float = 60.0
@export var camera_height: float = 6.0
@export var camera_distance: float = 10.0
@export var camera_angle_deg: float = 45.0
var effective_speed := 1.0
var current_look_ahead := Vector3.ZERO
var look_ahead_velocity := Vector3.ZERO
var position_offset: Vector3 = Vector3(0, 10, 0)
var rotation_lag_speed := 3.0
var position_lag_speed := 10.0
func _physics_process(delta: float) → void:
if not follow_target:
return
# update speed for smoothing ---
if follow_target and "move_speed" in follow_target:
var move_speed = follow_target.move_speed
effective_speed = move_speed + ((move_speed + 1.0) / 2.0)
# get target velocity
var velocity := Vector3.ZERO
if follow_target.has_method("get_velocity"):
velocity = follow_target.call("get_velocity")
else:
velocity = follow_target.global_transform.basis.z * -1.0
var speed := velocity.length()
var direction := Vector3.ZERO
if speed > 0.01:
direction = velocity.normalized()
# smooth look-ahead
var desired_look_ahead = direction * look_ahead_distance * clamp(speed / effective_speed, 0.0, 1.0)
look_ahead_velocity = look_ahead_velocity.lerp(desired_look_ahead - current_look_ahead, delta * 5.0)
current_look_ahead += look_ahead_velocity * delta
# final target camera position
var target_position = follow_target.global_transform.origin + position_offset + current_look_ahead
global_transform.origin = global_transform.origin.lerp(target_position, delta * position_lag_speed)
# smooth yaw rotation
var forward = -follow_target.global_transform.basis.z
var target_yaw = atan2(forward.x, forward.z)
var current_yaw = rotation.y
var smoothed_yaw = lerp_angle(current_yaw, target_yaw, delta * rotation_lag_speed)
rotation.y = smoothed_yaw