diff --git a/levels/sandbox/sandbox.tscn b/levels/sandbox/sandbox.tscn new file mode 100644 index 0000000..d203de5 --- /dev/null +++ b/levels/sandbox/sandbox.tscn @@ -0,0 +1,71 @@ +[gd_scene load_steps=9 format=3 uid="uid://16ds4fvv72xk"] + +[ext_resource type="PackedScene" uid="uid://bwe2jdmvinhqd" path="res://src/player/player.tscn" id="1_h436a"] + +[sub_resource type="Environment" id="Environment_cc548"] +background_mode = 1 +tonemap_mode = 3 +fog_enabled = true +fog_light_color = Color(0, 0, 0, 1) +fog_density = 0.2 + +[sub_resource type="PlaneMesh" id="PlaneMesh_4afx3"] +size = Vector2(50, 50) + +[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_c8g65"] + +[sub_resource type="BoxMesh" id="BoxMesh_mer5b"] + +[sub_resource type="BoxShape3D" id="BoxShape3D_hx5n6"] + +[sub_resource type="CylinderMesh" id="CylinderMesh_a1koa"] +top_radius = 1.0 +bottom_radius = 1.0 +height = 4.0 + +[sub_resource type="CylinderShape3D" id="CylinderShape3D_uo57d"] +height = 4.0 +radius = 1.0 + +[node name="Sandbox" type="Node3D"] + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_cc548") + +[node name="SpotLight3D" type="SpotLight3D" parent="."] +transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 10, 0) +light_energy = 16.0 +shadow_enabled = true +spot_range = 20.0 +spot_angle_attenuation = 0.05 + +[node name="Geometry" type="Node3D" parent="."] + +[node name="Floor" type="StaticBody3D" parent="Geometry"] + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Geometry/Floor"] +mesh = SubResource("PlaneMesh_4afx3") +skeleton = NodePath("../..") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Geometry/Floor"] +shape = SubResource("WorldBoundaryShape3D_c8g65") + +[node name="Box" type="StaticBody3D" parent="Geometry"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0.5, 4) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Geometry/Box"] +mesh = SubResource("BoxMesh_mer5b") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Geometry/Box"] +shape = SubResource("BoxShape3D_hx5n6") + +[node name="Cylinder" type="StaticBody3D" parent="Geometry"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 2, -2) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Geometry/Cylinder"] +mesh = SubResource("CylinderMesh_a1koa") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Geometry/Cylinder"] +shape = SubResource("CylinderShape3D_uo57d") + +[node name="Player" parent="." instance=ExtResource("1_h436a")] diff --git a/project.godot b/project.godot index b1a739a..5f43ccf 100644 --- a/project.godot +++ b/project.godot @@ -11,9 +11,9 @@ config_version=5 [application] config/name="Grunk" -config/features=PackedStringArray("4.2", "Forward Plus") +run/main_scene="res://levels/sandbox/sandbox.tscn" +config/features=PackedStringArray("4.3", "Forward Plus") run/max_fps=60 -config/icon="res://icon.svg" [debug] @@ -25,6 +25,8 @@ gdscript/warnings/unsafe_call_argument=2 [display] +window/size/viewport_width=1920 +window/size/viewport_height=1080 window/stretch/mode="canvas_items" [dotnet] @@ -38,3 +40,53 @@ movie_writer/movie_file="demos/demo.avi" [editor_plugins] enabled=PackedStringArray("res://addons/format_on_save/plugin.cfg", "res://addons/gdlint_plugin/plugin.cfg") + +[game] + +config/input/mouse_sensitivity_x=0.45 +config/input/mouse_sensitivity_y=0.45 +config/input/invert_pitch=false +config/input/mouse_acceleration=30.0 + +[input] + +move_forward={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null) +] +} +move_left={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null) +] +} +move_back={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null) +] +} +move_right={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null) +] +} +jump={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null) +] +} +sneak={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194326,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +sprint={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194325,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +fire={ +"deadzone": 0.5, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null) +] +} diff --git a/src/player/camera_controller.gd b/src/player/camera_controller.gd new file mode 100644 index 0000000..2bef35b --- /dev/null +++ b/src/player/camera_controller.gd @@ -0,0 +1,34 @@ +class_name CameraController extends Node3D + +const PITCH_LIMIT := deg_to_rad(85.0) + +@onready var _target := Vector2(rotation.x, rotation.y) + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouseMotion: + if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: + camera_motion((event as InputEventMouseMotion).relative) + elif event is InputEventMouseButton: + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + + +func camera_motion(motion: Vector2) -> void: + 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") + + _target.y -= deg_to_rad(motion.x * x_sensitivity) + _target.x = clampf( + _target.x - deg_to_rad(motion.y * y_sensitivity) * (-1 if invert_pitch else 1), + -PITCH_LIMIT, + PITCH_LIMIT + ) + + +func _physics_process(_delta: float) -> void: + var mouse_accel: float = ( + ProjectSettings.get_setting("game/config/input/mouse_acceleration") / 60.0 + ) + rotation.y = lerp_angle(rotation.y, _target.y, mouse_accel) + rotation.x = lerp_angle(rotation.x, _target.x, mouse_accel) diff --git a/src/player/player.gd b/src/player/player.gd new file mode 100644 index 0000000..a7532e5 --- /dev/null +++ b/src/player/player.gd @@ -0,0 +1,54 @@ +class_name Player extends CharacterBody3D + +const RUN_SPEED := 80.0 +const SPRINT_SPEED := 160.0 +const AIR_SPEED := 30.0 +const JUMP_FORCE := 4.5 +const GROUND_FRICTION := 0.3 +const AIR_FRICTION := 0.03 + +var gravity: Vector3 = ( + ProjectSettings.get_setting("physics/3d/default_gravity") + * ProjectSettings.get_setting("physics/3d/default_gravity_vector") +) + +@onready var camera_pivot: Node3D = %CameraPivot + + +func get_speed() -> float: + if is_on_floor(): + if Input.is_action_pressed("sprint"): + return SPRINT_SPEED + return RUN_SPEED + return AIR_SPEED + + +func get_friction() -> float: + if is_on_floor(): + return GROUND_FRICTION + return AIR_FRICTION + + +func _physics_process(delta: float) -> void: + # Gravity + if not is_on_floor(): + velocity += gravity * delta + + # Input movement + var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_back") + var direction := ( + (camera_pivot.global_basis * Vector3(input_dir.x, 0, input_dir.y) * Vector3(1, 0, 1)) + . normalized() + ) + var movement := direction * get_speed() * delta + velocity.x += movement.x + velocity.z += movement.z + if Input.is_action_just_pressed("jump") and is_on_floor(): + velocity.y = JUMP_FORCE + + # Friction + var friction := get_friction() + velocity.x = lerpf(velocity.x, 0, friction) + velocity.z = lerpf(velocity.z, 0, friction) + + move_and_slide() diff --git a/src/player/player.tscn b/src/player/player.tscn new file mode 100644 index 0000000..a68dedb --- /dev/null +++ b/src/player/player.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=4 format=3 uid="uid://bwe2jdmvinhqd"] + +[ext_resource type="Script" path="res://src/player/player.gd" id="1_npueo"] +[ext_resource type="Script" path="res://src/player/camera_controller.gd" id="2_veeqv"] + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_s7f0r"] + +[node name="Player" type="CharacterBody3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) +script = ExtResource("1_npueo") + +[node name="CameraPivot" type="Node3D" parent="."] +unique_name_in_owner = true +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) +script = ExtResource("2_veeqv") + +[node name="Camera3D" type="Camera3D" parent="CameraPivot"] +current = true + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("CapsuleShape3D_s7f0r")