diff --git a/main/main.tscn b/main/main.tscn new file mode 100644 index 0000000..2b62ed9 --- /dev/null +++ b/main/main.tscn @@ -0,0 +1,13 @@ +[gd_scene load_steps=3 format=3] + +[ext_resource type="PackedScene" path="res://world/test_world.tscn" id="1_world"] +[ext_resource type="PackedScene" path="res://player/player.tscn" id="2_player"] + +[node name="Main" type="Node3D"] + +[node name="TestWorld" parent="." instance=ExtResource("1_world")] + +[node name="Players" type="Node3D" parent="."] + +[node name="Player" parent="Players" instance=ExtResource("2_player")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 5) diff --git a/player/player.gd b/player/player.gd new file mode 100644 index 0000000..3389b8a --- /dev/null +++ b/player/player.gd @@ -0,0 +1,129 @@ +class_name Player +extends CharacterBody3D + +@export_category("Movement") +@export var walk_speed: float = 5.0 +@export var sprint_speed: float = 8.0 +@export var sneak_speed: float = 2.0 +@export var slow_walk_speed: float = 3.25 +@export var jump_velocity: float = 6.0 +@export var body_rotation_speed: float = 12.0 + +@export_category("Camera") +@export var mouse_sensitivity: float = 0.005 +@export var controller_camera_speed: float = 2.5 +@export_range(0.0, 1.0, 0.01) var controller_camera_deadzone: float = 0.2 +@export_range(-89.0, 0.0, 0.5) var minimum_pitch_degrees: float = -65.0 +@export_range(0.0, 89.0, 0.5) var maximum_pitch_degrees: float = 45.0 +@export var minimum_zoom: float = 2.0 +@export var maximum_zoom: float = 8.0 +@export var zoom_step: float = 0.75 +@export var zoom_smoothing: float = 12.0 + +@onready var _visuals: Node3D = %Visuals +@onready var _camera_yaw: Node3D = %CameraYaw +@onready var _camera_pitch: Node3D = %CameraPitch +@onready var _spring_arm: SpringArm3D = %SpringArm3D + +var _gravity: float = float(ProjectSettings.get_setting("physics/3d/default_gravity")) +var _camera_dragging: bool = false +var _target_zoom: float = 5.0 + + +func _ready() -> void: + _target_zoom = clampf(_spring_arm.spring_length, minimum_zoom, maximum_zoom) + _spring_arm.spring_length = _target_zoom + + +func _physics_process(delta: float) -> void: + if not is_on_floor(): + velocity.y -= _gravity * delta + elif Input.is_action_just_pressed("jump"): + velocity.y = jump_velocity + + var input_vector: Vector2 = Input.get_vector( + "move_left", + "move_right", + "move_forward", + "move_backward" + ) + var camera_basis: Basis = _camera_yaw.global_basis + var move_direction: Vector3 = camera_basis.x * input_vector.x + camera_basis.z * input_vector.y + move_direction.y = 0.0 + var input_strength: float = minf(input_vector.length(), 1.0) + move_direction = move_direction.normalized() + + var speed: float = _get_current_speed() + velocity.x = move_direction.x * speed * input_strength + velocity.z = move_direction.z * speed * input_strength + + if not move_direction.is_zero_approx(): + var target_rotation: float = atan2(-move_direction.x, -move_direction.z) + _visuals.rotation.y = lerp_angle( + _visuals.rotation.y, + target_rotation, + 1.0 - exp(-body_rotation_speed * delta) + ) + + move_and_slide() + + +func _process(delta: float) -> void: + if _camera_dragging and not Input.is_action_pressed("camera_drag"): + _camera_dragging = false + + var stick: Vector2 = Vector2( + Input.get_joy_axis(0, JOY_AXIS_RIGHT_X), + Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y) + ) + if stick.length() > controller_camera_deadzone: + var adjusted_strength: float = ( + (stick.length() - controller_camera_deadzone) + / (1.0 - controller_camera_deadzone) + ) + _rotate_camera(stick.normalized() * adjusted_strength * controller_camera_speed * delta) + + var zoom_weight: float = 1.0 - exp(-zoom_smoothing * delta) + _spring_arm.spring_length = lerpf(_spring_arm.spring_length, _target_zoom, zoom_weight) + + +func _unhandled_input(event: InputEvent) -> void: + if event.is_action("camera_drag"): + _camera_dragging = event.is_pressed() + get_viewport().set_input_as_handled() + return + + if event is InputEventMouseMotion and _camera_dragging: + _rotate_camera(event.relative * mouse_sensitivity) + get_viewport().set_input_as_handled() + return + + if event.is_action_pressed("camera_zoom_in"): + _set_target_zoom(_target_zoom - zoom_step) + get_viewport().set_input_as_handled() + elif event.is_action_pressed("camera_zoom_out"): + _set_target_zoom(_target_zoom + zoom_step) + get_viewport().set_input_as_handled() + + +func _get_current_speed() -> float: + if Input.is_action_pressed("sneak"): + return sneak_speed + if Input.is_action_pressed("slow_walk"): + return slow_walk_speed + if Input.is_action_pressed("sprint"): + return sprint_speed + return walk_speed + + +func _rotate_camera(delta_rotation: Vector2) -> void: + _camera_yaw.rotation.y -= delta_rotation.x + _camera_pitch.rotation.x = clampf( + _camera_pitch.rotation.x - delta_rotation.y, + deg_to_rad(minimum_pitch_degrees), + deg_to_rad(maximum_pitch_degrees) + ) + + +func _set_target_zoom(value: float) -> void: + _target_zoom = clampf(value, minimum_zoom, maximum_zoom) diff --git a/player/player.gd.uid b/player/player.gd.uid new file mode 100644 index 0000000..d3d7bcd --- /dev/null +++ b/player/player.gd.uid @@ -0,0 +1 @@ +uid://bq7sx58c1ata2 diff --git a/player/player.tscn b/player/player.tscn new file mode 100644 index 0000000..7b9259a --- /dev/null +++ b/player/player.tscn @@ -0,0 +1,59 @@ +[gd_scene load_steps=7 format=3] + +[ext_resource type="Script" path="res://player/player.gd" id="1_script"] + +[sub_resource type="CapsuleShape3D" id="PlayerShape"] +radius = 0.45 +height = 1.8 + +[sub_resource type="CapsuleMesh" id="PlayerMesh"] +radius = 0.45 +height = 1.8 + +[sub_resource type="StandardMaterial3D" id="PlayerMaterial"] +albedo_color = Color(0.95, 0.48, 0.18, 1) + +[sub_resource type="BoxMesh" id="FacingMarkerMesh"] +size = Vector3(0.24, 0.2, 0.4) + +[sub_resource type="StandardMaterial3D" id="FacingMarkerMaterial"] +albedo_color = Color(0.12, 0.18, 0.28, 1) + +[node name="Player" type="CharacterBody3D"] +collision_layer = 2 +collision_mask = 1 +script = ExtResource("1_script") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +position = Vector3(0, 0.9, 0) +shape = SubResource("PlayerShape") + +[node name="Visuals" type="Node3D" parent="."] +unique_name_in_owner = true + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Visuals"] +position = Vector3(0, 0.9, 0) +mesh = SubResource("PlayerMesh") +material_override = SubResource("PlayerMaterial") + +[node name="FacingMarker" type="MeshInstance3D" parent="Visuals"] +position = Vector3(0, 1.0, -0.55) +mesh = SubResource("FacingMarkerMesh") +material_override = SubResource("FacingMarkerMaterial") + +[node name="CameraYaw" type="Node3D" parent="."] +unique_name_in_owner = true +position = Vector3(0, 1.35, 0) + +[node name="CameraPitch" type="Node3D" parent="CameraYaw"] +unique_name_in_owner = true +rotation = Vector3(-0.261799, 0, 0) + +[node name="SpringArm3D" type="SpringArm3D" parent="CameraYaw/CameraPitch"] +unique_name_in_owner = true +spring_length = 5.0 +margin = 0.15 +collision_mask = 1 + +[node name="Camera3D" type="Camera3D" parent="CameraYaw/CameraPitch/SpringArm3D"] +current = true diff --git a/project.godot b/project.godot index 465f561..ac06154 100644 --- a/project.godot +++ b/project.godot @@ -11,6 +11,7 @@ config_version=5 [application] config/name="netfishing" +run/main_scene="res://main/main.tscn" config/features=PackedStringArray("4.7", "GL Compatibility") config/icon="res://icon.svg" @@ -19,6 +20,123 @@ config/icon="res://icon.svg" window/stretch/mode="canvas_items" window/stretch/aspect="expand" +[input] + +move_forward={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"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":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null) +] +} +move_backward={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"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":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null) +] +} +move_left={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"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":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null) +] +} +move_right={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"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":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null) +] +} +sprint={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"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) +] +} +jump={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"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":0,"location":0,"echo":false,"script":null) +] +} +sneak={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"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) +] +} +slow_walk={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194328,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +interact={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +fish_primary={ +"deadzone": 0.2, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":32,"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) +] +} +camera_drag={ +"deadzone": 0.2, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":32,"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":2,"canceled":false,"pressed":false,"double_click":false,"script":null) +] +} +camera_zoom_in={ +"deadzone": 0.2, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":32,"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":4,"canceled":false,"pressed":false,"double_click":false,"script":null) +] +} +camera_zoom_out={ +"deadzone": 0.2, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":32,"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":5,"canceled":false,"pressed":false,"double_click":false,"script":null) +] +} +open_backpack={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194308,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +open_emotes={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":67,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +open_tacklebox={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":66,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +open_props={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":86,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +toggle_free_camera={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":78,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +toggle_hud={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":72,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +bark_meow={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":71,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +kiss={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":75,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +alternate_fishing={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":92,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} + [physics] 3d/physics_engine="Jolt Physics" diff --git a/world/test_world.tscn b/world/test_world.tscn new file mode 100644 index 0000000..80c4a51 --- /dev/null +++ b/world/test_world.tscn @@ -0,0 +1,67 @@ +[gd_scene load_steps=10 format=3] + +[sub_resource type="BoxShape3D" id="GroundShape"] +size = Vector3(30, 1, 30) + +[sub_resource type="BoxMesh" id="GroundMesh"] +size = Vector3(30, 1, 30) + +[sub_resource type="StandardMaterial3D" id="GroundMaterial"] +albedo_color = Color(0.25, 0.52, 0.24, 1) + +[sub_resource type="BoxShape3D" id="DockShape"] +size = Vector3(5, 0.5, 10) + +[sub_resource type="BoxMesh" id="DockMesh"] +size = Vector3(5, 0.5, 10) + +[sub_resource type="StandardMaterial3D" id="DockMaterial"] +albedo_color = Color(0.42, 0.25, 0.12, 1) + +[sub_resource type="PlaneMesh" id="WaterMesh"] +size = Vector2(40, 25) + +[sub_resource type="StandardMaterial3D" id="WaterMaterial"] +transparency = 1 +albedo_color = Color(0.1, 0.45, 0.7, 0.72) +roughness = 0.25 + +[sub_resource type="Environment" id="Environment"] +background_mode = 1 +background_color = Color(0.48, 0.72, 0.9, 1) +ambient_light_source = 3 +ambient_light_color = Color(0.65, 0.72, 0.8, 1) +ambient_light_energy = 0.65 + +[node name="TestWorld" type="Node3D"] + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment") + +[node name="Sun" type="DirectionalLight3D" parent="."] +rotation_degrees = Vector3(-55, -35, 0) +shadow_enabled = true + +[node name="Ground" type="StaticBody3D" parent="."] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"] +shape = SubResource("GroundShape") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Ground"] +mesh = SubResource("GroundMesh") +material_override = SubResource("GroundMaterial") + +[node name="Dock" type="StaticBody3D" parent="."] +position = Vector3(0, 0.75, -15) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Dock"] +shape = SubResource("DockShape") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Dock"] +mesh = SubResource("DockMesh") +material_override = SubResource("DockMaterial") + +[node name="Water" type="MeshInstance3D" parent="."] +position = Vector3(0, 0.2, -27) +mesh = SubResource("WaterMesh") +material_override = SubResource("WaterMaterial")