diff --git a/project.godot b/project.godot index aeea555..a96e35b 100644 --- a/project.godot +++ b/project.godot @@ -51,3 +51,16 @@ folder_colors={ "res://src/": "green", "res://src/world/": "teal" } + +[game] + +config/input/mouse_sensitivity_x=0.3 +config/input/mouse_sensitivity_y=0.3 +config/input/camera_acceleration=40.0 +config/input/invert_pitch=false + +[layer_names] + +3d_render/layer_1="Global Noise Layer" +3d_physics/layer_1="World Geometry" +3d_physics/layer_2="Player" diff --git a/src/player/camera_controller.gd b/src/player/camera_controller.gd new file mode 100644 index 0000000..4785ea9 --- /dev/null +++ b/src/player/camera_controller.gd @@ -0,0 +1,21 @@ +class_name CameraController extends Node3D +## Simple first-person camera motion controller + +const PITCH_LIMIT := deg_to_rad(85.0) + +@onready var _target := Vector2(rotation.x, rotation.y) + + +## Rotate the camera by the given motion vector. +## +## The input motion vector is the change in pitch and yaw in radians. +func camera_motion(motion: Vector2) -> void: + _target.y -= motion.x + _target.x = clampf(_target.x - motion.y, -PITCH_LIMIT, PITCH_LIMIT) + + +func _physics_process(delta: float) -> void: + var accel: float = ProjectSettings.get_setting("game/config/input/camera_acceleration") + var weight := 1.0 - exp(-accel * delta) + rotation.y = lerp_angle(rotation.y, _target.y, weight) + rotation.x = lerp_angle(rotation.x, _target.x, weight) diff --git a/src/player/camera_controller.gd.uid b/src/player/camera_controller.gd.uid new file mode 100644 index 0000000..71f7e42 --- /dev/null +++ b/src/player/camera_controller.gd.uid @@ -0,0 +1 @@ +uid://f3kssctvn2bo diff --git a/src/player/mouselook_controller.gd b/src/player/mouselook_controller.gd new file mode 100644 index 0000000..9adb895 --- /dev/null +++ b/src/player/mouselook_controller.gd @@ -0,0 +1,28 @@ +class_name MouselookController extends Node +## Camera controller component using the mouse to look around. + +@export var look_enabled := true + +@onready var camera_controller: CameraController = get_parent() + + +func _send_mouse_motion(motion: Vector2) -> void: + # Map mouse motion & send to controller + var x_sensitivity: float = ProjectSettings.get_setting("game/config/input/mouse_sensitivity_x") + var y_sensitivity: float = ProjectSettings.get_setting("game/config/input/mouse_sensitivity_y") + var invert_pitch: bool = ProjectSettings.get_setting("game/config/input/invert_pitch") + camera_controller.camera_motion( + Vector2( + deg_to_rad(motion.x * x_sensitivity), + deg_to_rad(motion.y * y_sensitivity) * (-1 if invert_pitch else 1) + ) + ) + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouseMotion: + if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED and look_enabled: + _send_mouse_motion((event as InputEventMouseMotion).relative) + elif event is InputEventMouseButton and look_enabled: + # Capture mouse when clicked + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) diff --git a/src/player/mouselook_controller.gd.uid b/src/player/mouselook_controller.gd.uid new file mode 100644 index 0000000..00875cb --- /dev/null +++ b/src/player/mouselook_controller.gd.uid @@ -0,0 +1 @@ +uid://032jyhgkb2rv diff --git a/src/player/player.tscn b/src/player/player.tscn index ccca31c..bece78f 100644 --- a/src/player/player.tscn +++ b/src/player/player.tscn @@ -1,13 +1,42 @@ -[gd_scene load_steps=3 format=3 uid="uid://dtbulshrxetes"] +[gd_scene load_steps=8 format=3 uid="uid://dtbulshrxetes"] + +[ext_resource type="Script" uid="uid://f3kssctvn2bo" path="res://src/player/camera_controller.gd" id="1_mf2ua"] +[ext_resource type="Script" uid="uid://csjccrhj5wnx7" path="res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd" id="1_rxibo"] +[ext_resource type="Script" uid="uid://8umksf8e80fw" path="res://addons/phantom_camera/scripts/resources/tween_resource.gd" id="2_mf2ua"] +[ext_resource type="Script" uid="uid://032jyhgkb2rv" path="res://src/player/mouselook_controller.gd" id="4_244u8"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_qnmj6"] [sub_resource type="CapsuleMesh" id="CapsuleMesh_4anbu"] +[sub_resource type="Resource" id="Resource_244u8"] +script = ExtResource("2_mf2ua") +duration = 0.4 +transition = 7 +ease = 0 + [node name="Player" type="CharacterBody3D"] +collision_layer = 3 [node name="CollisionShape3D" type="CollisionShape3D" parent="."] shape = SubResource("CapsuleShape3D_qnmj6") [node name="MeshInstance3D" type="MeshInstance3D" parent="."] mesh = SubResource("CapsuleMesh_4anbu") + +[node name="CameraOffset" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) + +[node name="CameraController" type="Node3D" parent="CameraOffset"] +script = ExtResource("1_mf2ua") + +[node name="PhantomCamera3D" type="Node3D" parent="CameraOffset/CameraController"] +script = ExtResource("1_rxibo") +priority = 1 +tween_resource = SubResource("Resource_244u8") +noise_emitter_layer = 1 +metadata/_custom_type_script = "uid://csjccrhj5wnx7" + +[node name="MouselookController" type="Node" parent="CameraOffset/CameraController"] +script = ExtResource("4_244u8") +metadata/_custom_type_script = "uid://032jyhgkb2rv" diff --git a/src/world/world.tscn b/src/world/world.tscn index 220894f..e58d98d 100644 --- a/src/world/world.tscn +++ b/src/world/world.tscn @@ -1,6 +1,7 @@ -[gd_scene load_steps=5 format=3 uid="uid://daxngklaqlyba"] +[gd_scene load_steps=6 format=3 uid="uid://daxngklaqlyba"] [ext_resource type="PackedScene" uid="uid://dtbulshrxetes" path="res://src/player/player.tscn" id="1_1k4gi"] +[ext_resource type="Script" uid="uid://bd046eokvcnu2" path="res://addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd" id="2_6fy3g"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_kueii"] albedo_color = Color(0.16, 0.16, 0.16, 1) @@ -23,3 +24,12 @@ mesh = SubResource("PlaneMesh_1k4gi") [node name="CollisionShape3D" type="CollisionShape3D" parent="WorldFloor/StaticBody3D"] shape = SubResource("WorldBoundaryShape3D_1k4gi") + +[node name="Camera3D" type="Camera3D" parent="."] +physics_interpolation_mode = 1 +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0) + +[node name="PhantomCameraHost" type="Node" parent="Camera3D"] +process_priority = 300 +process_physics_priority = 300 +script = ExtResource("2_6fy3g")