114 lines
4.4 KiB
GDScript
114 lines
4.4 KiB
GDScript
extends Camera3D
|
|
class_name GameCamera
|
|
|
|
@export var keyboard_movement_speed: float = 10
|
|
@export var maximum_movement_speed: float = 30
|
|
@export var mouse_orbit_sensitivity: float = 0.003
|
|
@export var zoom_sensitivity: float = 0.1
|
|
@export var focus_follows_terrain: bool = true
|
|
|
|
var focus_offset: Vector3 = Vector3(10, 10, 10)
|
|
var focus_object: Node3D = null
|
|
@export var focus_position: Vector3
|
|
var mouse_movement: Vector2
|
|
var mouse_wheel_delta: int = 0
|
|
|
|
@onready var focus_marker: Node3D = $"Camera Focus"
|
|
@onready var viewport: Viewport = get_viewport()
|
|
|
|
func _process(delta: float) -> void:
|
|
if Input.is_action_just_released("camera_set_target"):
|
|
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 = 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 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)
|
|
process_camera_zoom(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, maximum_movement_speed*delta)
|
|
#else:
|
|
|
|
basis = basis.slerp(Basis.looking_at(focus_position - target_position), 0.05)
|
|
|
|
#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 * keyboard_movement_speed * delta
|
|
global_position += movement
|
|
focus_position += movement
|
|
|
|
# handle moving on/off ramps
|
|
if focus_follows_terrain:
|
|
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new()
|
|
params.from = focus_position + Vector3(0,2,0)
|
|
params.to = focus_position - Vector3(0,2,0)
|
|
params.collision_mask = 1
|
|
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
|
|
if result.has("position"):
|
|
focus_position = result["position"]
|
|
|
|
func process_camera_rotation(delta: float) -> void:
|
|
#var mouse_position: Vector2 = viewport.get_mouse_position()
|
|
#var mouse_position: Vector2 = Vector2()
|
|
#var mouse_movement: Vector2 = (mouse_position - last_mouse_position) * delta
|
|
#last_mouse_position = mouse_position
|
|
if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT):
|
|
focus_offset = focus_offset.rotated(Vector3.UP, -mouse_movement.x * mouse_orbit_sensitivity)
|
|
var vertical_axis: Vector3 = focus_offset.cross(Vector3.UP).normalized()
|
|
focus_offset = focus_offset.rotated(vertical_axis, mouse_movement.y * mouse_orbit_sensitivity)
|
|
global_position = focus_position + focus_offset
|
|
look_at(focus_position)
|
|
mouse_movement = Vector2()
|
|
|
|
func process_camera_zoom(_delta: float) -> void:
|
|
#var wheel_input: float = Input.get_axis("camera_zoom_in", "camera_zoom_out")
|
|
var change: float = 1.0 + (-mouse_wheel_delta * zoom_sensitivity)
|
|
focus_offset *= change
|
|
mouse_wheel_delta = 0
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if event is InputEventMouseButton:
|
|
var button_event: InputEventMouseButton = event
|
|
if button_event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
|
mouse_wheel_delta += 1
|
|
elif button_event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
|
mouse_wheel_delta -= 1
|
|
elif event is InputEventMouseMotion:
|
|
var motion_event: InputEventMouseMotion = event
|
|
mouse_movement += motion_event.relative
|