extends Camera3D @export var pan_speed: float = 10 var focus_offset: Vector3 = Vector3(10, 10, 10) var focus_object: Node3D = null var focus_position: Vector3 var last_mouse_position: Vector2 @onready var focus_marker: Node3D = $"Camera Focus" func _physics_process(delta: float) -> void: var mouse_position: Vector2 = get_viewport().get_mouse_position() var ray_origin: Vector3 = project_ray_origin(mouse_position) var ray_normal: Vector3 = ray_origin + project_ray_normal(mouse_position) * 200 var params = PhysicsRayQueryParameters3D.create(ray_origin, ray_normal) var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params) if result.has("position"): DebugDraw3D.draw_sphere(result["position"], 0.5, Color.REBECCA_PURPLE) if Input.is_action_just_released("camera_set_target"): if result.has("collider") and !(result["collider"] is GridMap): focus_object = result["collider"] else: focus_object = null focus_position = result["position"] if focus_object != null: focus_position = focus_object.global_position process_focus_movement(delta) process_camera_rotation(delta) var target_position: Vector3 = focus_position + focus_offset if target_position.distance_squared_to(global_position) > 0: global_position = global_position.move_toward(target_position, 30*(1/60.0)) else: look_at(focus_position) #global_position = global_position.lerp(target_position, 0.05) #basis = basis.slerp(Basis.looking_at(focus_position - global_position), 0.05) focus_marker.global_position = focus_position #look_at(focus_position) func process_focus_movement(delta: float) -> void: var camera_forwards: Vector3 = -global_basis.z camera_forwards = camera_forwards.slide(Vector3.UP).normalized() var input_basis: Basis = Basis.looking_at(camera_forwards) var x_input: float = Input.get_axis("camera_left", "camera_right") var y_input: float = Input.get_axis("camera_backward", "camera_forward") var input: Vector3 = Vector3(x_input, 0, -y_input).limit_length(1) if input.is_zero_approx(): return if focus_object != null: focus_object = null input = input_basis * input var movement: Vector3 = input * pan_speed * delta global_position += movement focus_position += movement # handle moving on/off ramps var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new() params.from = focus_position + Vector3(0,2,0) params.to = focus_position - Vector3(0,2,0) var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params) if result.has("position"): focus_position = result["position"] DebugDraw3D.draw_gizmo(Transform3D(input_basis, focus_position)) func process_camera_rotation(delta: float) -> void: var mouse_position: Vector2 = get_viewport().get_mouse_position() var mouse_movement: Vector2 = mouse_position - last_mouse_position last_mouse_position = mouse_position if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT): focus_offset = focus_offset.rotated(Vector3.UP, -mouse_movement.x * 0.006) var vertical_axis: Vector3 = focus_offset.cross(Vector3.UP).normalized() focus_offset = focus_offset.rotated(vertical_axis, mouse_movement.y * 0.006) global_position = focus_position + focus_offset look_at(focus_position)