diff --git a/overworld/camera/OverworldCamera.gd b/overworld/camera/OverworldCamera.gd index f32fb18..7417ec2 100644 --- a/overworld/camera/OverworldCamera.gd +++ b/overworld/camera/OverworldCamera.gd @@ -8,7 +8,7 @@ const COLLISION_MARGIN:float = 0.3 @export_category("Orbit") @export var distance:float = 7.0 -@export var minDistance:float = 5.0 +@export var minDistance:float = 2.0 @export var orbitSensitivity:float = 144.0 @export var orbitAcceleration:float = 600.0 @export var pitchMin:float = -80.0 @@ -106,10 +106,15 @@ func _process(delta:float) -> void: global_transform.origin = finalPos look_at(pivot, Vector3.UP) - # Feed actual position back so camera input resumes from where it really is + # Lerp _yaw/_pitch toward the actual constrained position so input resumes + # smoothly, and small per-frame raycast variations don't oscillate. var actualDir:Vector3 = (finalPos - pivot).normalized() - _pitch = rad_to_deg(asin(clamp(actualDir.y, -1.0, 1.0))) - _yaw = rad_to_deg(atan2(actualDir.x, actualDir.z)) + var targetPitch:float = rad_to_deg(asin(clamp(actualDir.y, -1.0, 1.0))) + var targetYaw:float = rad_to_deg(atan2(actualDir.x, actualDir.z)) + var feedbackRate:float = minf(20.0 * delta, 1.0) + _pitch = lerpf(_pitch, targetPitch, feedbackRate) + var yawDiff:float = fposmod(targetYaw - _yaw + 180.0, 360.0) - 180.0 + _yaw += lerpf(0.0, yawDiff, feedbackRate) # Returns the camera world position, respecting both minDistance and terrain. func _resolvePosition(pivot:Vector3, dir:Vector3) -> Vector3: @@ -125,17 +130,14 @@ func _resolvePosition(pivot:Vector3, dir:Vector3) -> Vector3: var hitNormal:Vector3 = hit["normal"] var hitDist:float = (hit["position"] - pivot).length() - COLLISION_MARGIN - if hitDist >= minDistance: - # Terrain is beyond minDistance — simple pull-back along the ray - return pivot + dir * hitDist - - # Terrain is closer than minDistance. # Find the closest point on the circle formed by intersecting: - # • the minDistance sphere centred on pivot + # • a sphere of radius max(hitDist, minDistance) centred on pivot # • the terrain surface plane (inset by COLLISION_MARGIN along its normal) - # That point is exactly minDistance from the pivot and flush with the surface. + # Using max() makes both cases meet exactly at hitDist == minDistance, + # eliminating the branch discontinuity that causes jitter at the boundary. + var targetDist:float = maxf(hitDist, minDistance) var d:float = hitNormal.dot(pivot - hit["position"]) - COLLISION_MARGIN - var rSq:float = minDistance * minDistance - d * d + var rSq:float = targetDist * targetDist - d * d if rSq <= 0.0: # Pivot is itself nearly on the terrain — sit at the tangent point return pivot - hitNormal * d diff --git a/overworld/entity/Entity.tscn b/overworld/entity/Entity.tscn index f20620f..eed15fd 100644 --- a/overworld/entity/Entity.tscn +++ b/overworld/entity/Entity.tscn @@ -26,6 +26,7 @@ size = Vector3(0.689728, 0.52002, 0.796997) size = Vector3(1.3, 1.3, 1.3) [node name="Entity" type="CharacterBody3D"] +collision_layer = 2 script = ExtResource("1_8e8ef") entityId = "35ce980f-3df9-4e09-b365-1a228948cf78" metadata/_custom_type_script = "uid://c8146flooxeue"