Mostly done camera
This commit is contained in:
@@ -8,10 +8,10 @@ const COLLISION_MARGIN:float = 0.3
|
|||||||
|
|
||||||
@export_category("Orbit")
|
@export_category("Orbit")
|
||||||
@export var distance:float = 7.0
|
@export var distance:float = 7.0
|
||||||
@export var minDistance:float = 1.5
|
@export var minDistance:float = 5.0
|
||||||
@export var orbitSensitivity:float = 144.0
|
@export var orbitSensitivity:float = 144.0
|
||||||
@export var orbitAcceleration:float = 600.0
|
@export var orbitAcceleration:float = 600.0
|
||||||
@export var pitchMin:float = -10.0
|
@export var pitchMin:float = -80.0
|
||||||
@export var pitchMax:float = 70.0
|
@export var pitchMax:float = 70.0
|
||||||
|
|
||||||
@export_category("Mouse")
|
@export_category("Mouse")
|
||||||
@@ -24,19 +24,14 @@ const COLLISION_MARGIN:float = 0.3
|
|||||||
|
|
||||||
@export_category("Collision")
|
@export_category("Collision")
|
||||||
@export_flags_3d_physics var collisionMask:int = 1
|
@export_flags_3d_physics var collisionMask:int = 1
|
||||||
@export var distanceReturnSpeed:float = 5.0
|
|
||||||
|
|
||||||
var _yaw:float = 0.0
|
var _yaw:float = 0.0
|
||||||
var _pitch:float = 30.0
|
var _pitch:float = 30.0
|
||||||
var _currentDistance:float = 0.0
|
|
||||||
var _camVelocity:Vector2 = Vector2.ZERO
|
var _camVelocity:Vector2 = Vector2.ZERO
|
||||||
var _idleTimer:float = 0.0
|
var _idleTimer:float = 0.0
|
||||||
var _mouseDelta:Vector2 = Vector2.ZERO
|
var _mouseDelta:Vector2 = Vector2.ZERO
|
||||||
var _rightMouseHeld:bool = false
|
var _rightMouseHeld:bool = false
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
_currentDistance = distance
|
|
||||||
|
|
||||||
func _input(event:InputEvent) -> void:
|
func _input(event:InputEvent) -> void:
|
||||||
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT:
|
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT:
|
||||||
_rightMouseHeld = event.pressed
|
_rightMouseHeld = event.pressed
|
||||||
@@ -107,25 +102,52 @@ func _process(delta:float) -> void:
|
|||||||
cos(yawRad) * cos(pitchRad)
|
cos(yawRad) * cos(pitchRad)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Snap in instantly when terrain blocks; restore smoothly when clear
|
var finalPos:Vector3 = _resolvePosition(pivot, dir)
|
||||||
var collisionDist:float = _resolveDistance(pivot, dir)
|
global_transform.origin = finalPos
|
||||||
if collisionDist < _currentDistance:
|
|
||||||
_currentDistance = collisionDist
|
|
||||||
else:
|
|
||||||
_currentDistance = move_toward(_currentDistance, distance, distanceReturnSpeed * delta)
|
|
||||||
|
|
||||||
global_transform.origin = pivot + dir * _currentDistance
|
|
||||||
look_at(pivot, Vector3.UP)
|
look_at(pivot, Vector3.UP)
|
||||||
|
|
||||||
# Ray from pivot outward; returns the safe camera distance along dir.
|
# Feed actual position back so camera input resumes from where it really is
|
||||||
func _resolveDistance(pivot:Vector3, dir:Vector3) -> float:
|
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))
|
||||||
|
|
||||||
|
# Returns the camera world position, respecting both minDistance and terrain.
|
||||||
|
func _resolvePosition(pivot:Vector3, dir:Vector3) -> Vector3:
|
||||||
|
var desired:Vector3 = pivot + dir * distance
|
||||||
var space:PhysicsDirectSpaceState3D = get_world_3d().direct_space_state
|
var space:PhysicsDirectSpaceState3D = get_world_3d().direct_space_state
|
||||||
var query:PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(pivot, pivot + dir * distance)
|
var query:PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(pivot, desired)
|
||||||
query.collision_mask = collisionMask
|
query.collision_mask = collisionMask
|
||||||
|
|
||||||
var hit:Dictionary = space.intersect_ray(query)
|
var hit:Dictionary = space.intersect_ray(query)
|
||||||
if hit.is_empty():
|
|
||||||
return distance
|
|
||||||
|
|
||||||
|
if hit.is_empty():
|
||||||
|
return desired
|
||||||
|
|
||||||
|
var hitNormal:Vector3 = hit["normal"]
|
||||||
var hitDist:float = (hit["position"] - pivot).length() - COLLISION_MARGIN
|
var hitDist:float = (hit["position"] - pivot).length() - COLLISION_MARGIN
|
||||||
return maxf(hitDist, minDistance)
|
|
||||||
|
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
|
||||||
|
# • the terrain surface plane (inset by COLLISION_MARGIN along its normal)
|
||||||
|
# That point is exactly minDistance from the pivot and flush with the surface.
|
||||||
|
var d:float = hitNormal.dot(pivot - hit["position"]) - COLLISION_MARGIN
|
||||||
|
var rSq:float = minDistance * minDistance - d * d
|
||||||
|
if rSq <= 0.0:
|
||||||
|
# Pivot is itself nearly on the terrain — sit at the tangent point
|
||||||
|
return pivot - hitNormal * d
|
||||||
|
|
||||||
|
var circleCenter:Vector3 = pivot - hitNormal * d
|
||||||
|
var circleRadius:float = sqrt(rSq)
|
||||||
|
|
||||||
|
# Project desired onto the terrain plane to get the on-plane direction
|
||||||
|
var toDesired:Vector3 = desired - circleCenter
|
||||||
|
toDesired -= hitNormal * hitNormal.dot(toDesired)
|
||||||
|
if toDesired.length_squared() < 0.0001:
|
||||||
|
# Desired is directly along the normal — any circle point is equally good
|
||||||
|
return circleCenter
|
||||||
|
|
||||||
|
return circleCenter + toDesired.normalized() * circleRadius
|
||||||
|
|||||||
Reference in New Issue
Block a user