diff --git a/README.md b/README.md index d1d018f..24c3045 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,51 @@ # quality-godot-first-person-2 -An actually good first person controller for the Godot Engine (version 2) +Actually good first person controller for the Godot Engine. +MIT License (credit Colormatic Studios) + +This first person controller was made because there aren't many first person controllers for Godot, and the ones that do exist are pretty bad. +It is highly customizable and comes with many features, QOL, and clean code. + +Some parts came from StayAtHomeDev's FPS tutorial. You can find that [here](https://www.youtube.com/playlist?list=PLEHvj4yeNfeF6s-UVs5Zx5TfNYmeCiYwf). + +# Directions +Move with WASD, space to jump, shift to sprint, C to crouch. + +**FEATURES:** + - In-air momentum + - Motion smoothing + - FOV smoothing + - Head bobbing + - Crouching + - Sprinting + - 2 crosshairs/reticles, one is animated (more to come?) + +If you make a cool game with this addon, I would love to hear about it! + +# Wiki +To start out, you should probably remap all of the movement keys to your own control set. +You can make this a super basic controller by just disabling everything + +**How to change settings** +Click on the character node and there should be settings in the "Feature Settings" group + +**How to add animations for a mesh:** +In the `_physics_process` function, add a line to check whether you are walking or aren't walking. You can do this by checking whether `input_dir` is true or false. Optionally, set the animation speed to `speed / base_speed`. This will make it so when the player is walking, your animation speed is 1. If the player is sprinting, your animation goes up and if the player is crouching your animation speed goes down. + +In the `toggle_sprint` function, add a line at the end where if `is_sprinting` is true, your animation is set to sprint. + +In the `toggle_crouch` function, add a line where if `is_crouching` is true, your animation is set to crouch. + +To check if the player is in the air, add a line in the `_physics_process` function where it says `if not is_on_floor():`set your animation to falling/in the air. Add an else statement to change it to the normal state. + +**How to change reticles (crosshairs)** +- Find the folder at `res://addons/fpc/reticles` +- Pick one and add it to the `UserInterface` node in the character scene. You may need to right click on the character and enable "Editable Children". +- Set the Character value to your character node (it's under the Nodes group) +- Change the `anchors_preset` value on the reticle to Center + +**How to create a new reticle** +- Choose a reticle to base it off of +- Open that reticle and save it as a new reticle +- Edit the reticle to your needs +- Follow the "how to change reticles" directions to use it + diff --git a/addons/fpc/character.gd b/addons/fpc/character.gd new file mode 100644 index 0000000..b62fa5c --- /dev/null +++ b/addons/fpc/character.gd @@ -0,0 +1,181 @@ +extends CharacterBody3D + +# TODO: Add descriptions for each value + +@export_category("Character") +@export var base_speed : float = 3.0 +@export var sprint_speed : float = 6.0 +@export var crouch_speed : float = 1.0 + +@export var acceleration : float = 10.0 +@export var jump_velocity : float = 4.5 +@export var mouse_sensitivity : float = 0.1 + +@export_group("Nodes") +@export var HEAD : Node3D +@export var CAMERA : Camera3D +@export var CAMERA_ANIMATION : AnimationPlayer + +@export_group("Controls") +# We are using UI controls because they are built into Godot Engine so they can be used right away +@export var JUMP : String = "ui_accept" +@export var LEFT : String = "ui_left" +@export var RIGHT : String = "ui_right" +@export var FORWARD : String = "ui_up" +@export var BACKWARD : String = "ui_down" +@export var PAUSE : String = "ui_cancel" +@export var CROUCH : String +@export var SPRINT : String + +@export_group("Feature Settings") +@export var immobile : bool = false +@export var jumping_enabled : bool = true +@export var in_air_momentum : bool = true +@export var motion_smoothing : bool = true +@export var sprint_enabled : bool = true +@export var crouch_enabled : bool = true +@export_enum("Hold to Crouch", "Toggle Crouch") var crouch_mode : int = 0 +@export_enum("Hold to Sprint", "Toggle Sprint") var sprint_mode : int = 0 +@export var dynamic_fov : bool = true +@export var continuous_jumping : bool = true +@export var view_bobbing : bool = true + +# Member variables +var speed : float = base_speed +var is_crouching : bool = false +var is_sprinting : bool = false + +# Get the gravity from the project settings to be synced with RigidBody nodes +var gravity : float = ProjectSettings.get_setting("physics/3d/default_gravity") # Don't set this as a const, see the gravity section in _physics_process + + +func _ready(): + Input.mouse_mode = Input.MOUSE_MODE_CAPTURED + +func _physics_process(delta): + + # Add some debug data + $UserInterface/DebugPanel.add_property("Movement Speed", speed, 1) + $UserInterface/DebugPanel.add_property("Velocity", get_real_velocity(), 2) + + # Gravity + #gravity = ProjectSettings.get_setting("physics/3d/default_gravity") # If the gravity changes during your game, uncomment this code + if not is_on_floor(): + velocity.y -= gravity * delta + + handle_jumping() + + var input_dir = Vector2.ZERO + if !immobile: + input_dir = Input.get_vector(LEFT, RIGHT, FORWARD, BACKWARD) + + handle_movement(delta, input_dir) + + toggle_crouch() + toggle_sprint(input_dir) + + if is_crouching: + speed = crouch_speed + elif is_sprinting: + speed = sprint_speed + else: + speed = base_speed + + + if view_bobbing: + headbob_animation(input_dir) + + +func handle_jumping(): + if jumping_enabled: + if continuous_jumping: + if Input.is_action_pressed(JUMP) and is_on_floor(): + velocity.y += jump_velocity + else: + if Input.is_action_just_pressed(JUMP) and is_on_floor(): + velocity.y += jump_velocity + +func handle_movement(delta, input_dir): + + var direction = input_dir.rotated(-HEAD.rotation.y) + direction = Vector3(direction.x, 0, direction.y) + + move_and_slide() + + if in_air_momentum: + if is_on_floor(): # Don't lerp y movement + if motion_smoothing: + velocity.x = lerp(velocity.x, direction.x * speed, acceleration * delta) + velocity.z = lerp(velocity.z, direction.z * speed, acceleration * delta) + else: + velocity.x = direction.x * speed + velocity.z = direction.z * speed + else: + if motion_smoothing: + velocity.x = lerp(velocity.x, direction.x * speed, acceleration * delta) + velocity.z = lerp(velocity.z, direction.z * speed, acceleration * delta) + else: + velocity.x = direction.x * speed + velocity.z = direction.z * speed + + +func _process(delta): + + $UserInterface/DebugPanel.add_property("FPS", 1.0/delta, 0) + + if Input.is_action_just_pressed(PAUSE): + if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + elif Input.mouse_mode == Input.MOUSE_MODE_VISIBLE: + Input.mouse_mode = Input.MOUSE_MODE_CAPTURED + + +func _unhandled_input(event): + if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: + HEAD.rotation_degrees.y -= event.relative.x * mouse_sensitivity + HEAD.rotation_degrees.x -= event.relative.y * mouse_sensitivity + HEAD.rotation.x = clamp(HEAD.rotation.x, deg_to_rad(-90), deg_to_rad(90)) + + +func toggle_crouch(): + if crouch_enabled: + if crouch_mode == 0: + is_crouching = Input.is_action_pressed(CROUCH) + elif crouch_mode == 1: + if Input.is_action_just_pressed(CROUCH): + is_crouching = !is_crouching + + # Replace with your own crouch animation code + if is_crouching: + $Collision.scale.y = lerp($Collision.scale.y, 0.75, 0.2) + else: + $Collision.scale.y = lerp($Collision.scale.y, 1.0, 0.2) + + +func toggle_sprint(moving): + if sprint_enabled: + if sprint_mode == 0: + if !is_crouching: # Crouching takes priority over sprinting + is_sprinting = Input.is_action_pressed(SPRINT) + else: + is_sprinting = false # Fix a bug where if you are sprinting and then crouch then let go of the sprinting button you keep sprinting + elif sprint_mode == 1: + if Input.is_action_just_pressed(SPRINT): + if !is_crouching: + is_sprinting = !is_sprinting + else: + is_sprinting = false + + if dynamic_fov: + if is_sprinting and moving: + CAMERA.fov = lerp(CAMERA.fov, 85.0, 0.3) + else: + CAMERA.fov = lerp(CAMERA.fov, 75.0, 0.3) + + +func headbob_animation(moving): + if moving and is_on_floor(): + CAMERA_ANIMATION.play("headbob") + CAMERA_ANIMATION.speed_scale = speed / base_speed + else: + CAMERA_ANIMATION.play("RESET") diff --git a/addons/fpc/character.tscn b/addons/fpc/character.tscn new file mode 100644 index 0000000..ad784a4 --- /dev/null +++ b/addons/fpc/character.tscn @@ -0,0 +1,124 @@ +[gd_scene load_steps=12 format=3 uid="uid://cc1m2a1obsyn4"] + +[ext_resource type="Script" path="res://addons/fpc/character.gd" id="1_0t4e8"] +[ext_resource type="PackedScene" uid="uid://3mij3cjhkwsm" path="res://addons/fpc/reticles/reticle_1.tscn" id="2_uuexm"] +[ext_resource type="PackedScene" uid="uid://coqpusufa8a6k" path="res://addons/fpc/reticles/reticle_0.tscn" id="3_ce64v"] +[ext_resource type="Script" path="res://addons/fpc/debug.gd" id="3_x1wcc"] + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_kp17n"] +albedo_color = Color(0.909804, 0.596078, 0, 1) +clearcoat_enabled = true +clearcoat_roughness = 0.2 + +[sub_resource type="CapsuleMesh" id="CapsuleMesh_jw1de"] +material = SubResource("StandardMaterial3D_kp17n") + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_uy03j"] + +[sub_resource type="Animation" id="Animation_gh776"] +resource_name = "RESET" +length = 0.001 +loop_mode = 1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Camera:position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector3(0, 0, 0)] +} + +[sub_resource type="Animation" id="Animation_lrqmv"] +resource_name = "headbob" +loop_mode = 1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Camera:position") +tracks/0/interp = 2 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.25, 0.5, 0.75, 1), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1), +"update": 0, +"values": [Vector3(0, 0, 0), Vector3(-0.05, -0.05, 0), Vector3(0, 0, 0), Vector3(0.05, -0.05, 0), Vector3(0, 0, 0)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_o0unb"] +_data = { +"RESET": SubResource("Animation_gh776"), +"headbob": SubResource("Animation_lrqmv") +} + +[sub_resource type="Theme" id="Theme_wdf0f"] +MarginContainer/constants/margin_bottom = 10 +MarginContainer/constants/margin_left = 10 +MarginContainer/constants/margin_right = 10 +MarginContainer/constants/margin_top = 10 + +[node name="Character" type="CharacterBody3D" node_paths=PackedStringArray("HEAD", "CAMERA", "CAMERA_ANIMATION")] +script = ExtResource("1_0t4e8") +HEAD = NodePath("Head") +CAMERA = NodePath("Head/Camera") +CAMERA_ANIMATION = NodePath("Head/camera_animation") +CROUCH = "crouch" +SPRINT = "sprint" + +[node name="Mesh" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) +mesh = SubResource("CapsuleMesh_jw1de") + +[node name="Collision" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) +shape = SubResource("CapsuleShape3D_uy03j") + +[node name="Head" type="Node3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0) + +[node name="Camera" type="Camera3D" parent="Head"] +transform = Transform3D(0.999511, 0.000977888, -0.0312559, 0, 0.999511, 0.0312712, 0.0312712, -0.0312559, 0.999022, 0, 0, 0) + +[node name="camera_animation" type="AnimationPlayer" parent="Head"] +libraries = { +"": SubResource("AnimationLibrary_o0unb") +} +blend_times = [&"RESET", &"RESET", 0.5, &"RESET", &"headbob", 0.5, &"headbob", &"RESET", 0.5] + +[node name="UserInterface" type="Control" parent="."] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 1 + +[node name="Reticle_0" parent="UserInterface" instance=ExtResource("3_ce64v")] +visible = false +layout_mode = 1 + +[node name="Reticle_1" parent="UserInterface" node_paths=PackedStringArray("reticle_lines", "character") instance=ExtResource("2_uuexm")] +layout_mode = 1 +reticle_lines = [NodePath("top"), NodePath("left"), NodePath("right"), NodePath("bottom")] +character = NodePath("../..") + +[node name="DebugPanel" type="PanelContainer" parent="UserInterface"] +layout_mode = 0 +offset_left = 10.0 +offset_top = 10.0 +offset_right = 453.0 +offset_bottom = 50.0 +theme = SubResource("Theme_wdf0f") +script = ExtResource("3_x1wcc") + +[node name="MarginContainer" type="MarginContainer" parent="UserInterface/DebugPanel"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="UserInterface/DebugPanel/MarginContainer"] +layout_mode = 2 + +[editable path="UserInterface/Reticle_1"] diff --git a/addons/fpc/debug.gd b/addons/fpc/debug.gd new file mode 100644 index 0000000..7708cd7 --- /dev/null +++ b/addons/fpc/debug.gd @@ -0,0 +1,18 @@ +extends PanelContainer + + +func _process(delta): + if visible: + pass + +func add_property(title:String, value, order): + var target + target = $MarginContainer/VBoxContainer.find_child(title, true, false) + if !target: + target = Label.new() + $MarginContainer/VBoxContainer.add_child(target) + target.name = title + target.text = title + ": " + str(value) + elif visible: + target.text = title + ": " + str(value) + $MarginContainer/VBoxContainer.move_child(target, order) diff --git a/addons/fpc/reticles/reticle_0.tscn b/addons/fpc/reticles/reticle_0.tscn new file mode 100644 index 0000000..2828124 --- /dev/null +++ b/addons/fpc/reticles/reticle_0.tscn @@ -0,0 +1,37 @@ +[gd_scene load_steps=2 format=3 uid="uid://coqpusufa8a6k"] + +[sub_resource type="GDScript" id="GDScript_10f85"] +script/source = "extends CenterContainer + + +@export_category(\"Reticle\") +@export_group(\"Nodes\") +@export var character : CharacterBody3D + +@export_group(\"Settings\") +@export var dot_size : int = 1 +@export var dot_color : Color = Color.WHITE + + +func _process(_delta): + if visible: # If the reticle is disabled (not visible), don't bother updating it + update_reticle_settings() + +func update_reticle_settings(): + $dot.scale.x = dot_size + $dot.scale.y = dot_size + $dot.color = dot_color +" + +[node name="Reticle" type="CenterContainer"] +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +grow_horizontal = 2 +grow_vertical = 2 +script = SubResource("GDScript_10f85") + +[node name="dot" type="Polygon2D" parent="."] +polygon = PackedVector2Array(-1, -1, 1, -1, 1, 1, -1, 1) diff --git a/addons/fpc/reticles/reticle_1.tscn b/addons/fpc/reticles/reticle_1.tscn new file mode 100644 index 0000000..82081cf --- /dev/null +++ b/addons/fpc/reticles/reticle_1.tscn @@ -0,0 +1,103 @@ +[gd_scene load_steps=2 format=3 uid="uid://3mij3cjhkwsm"] + +[sub_resource type="GDScript" id="GDScript_a8kpl"] +script/source = "extends CenterContainer + + +@export_category(\"Reticle\") +@export_group(\"Nodes\") +@export var reticle_lines : Array[Line2D] +@export var character : CharacterBody3D + +@export_group(\"Animate\") +@export var animated_reticle : bool = true +@export var reticle_speed : float = 0.5 +@export var reticle_spread : float = 4.0 + +@export_group(\"Dot Settings\") +@export var dot_size : int = 1 +@export var dot_color : Color = Color.WHITE + +@export_group(\"Line Settings\") +@export var line_color : Color = Color.WHITE +@export var line_width : int = 2 +@export var line_length : int = 10 +@export var line_distance : int = 5 +@export_enum(\"None\", \"Round\") var cap_mode : int = 0 + + +func _process(_delta): + if visible: # If the reticle is disabled (not visible), don't bother updating it + update_reticle_settings() + if animated_reticle: + animate_reticle_lines() + + +func animate_reticle_lines(): + var vel = character.get_real_velocity() + var origin = Vector3(0,0,0) + var pos = Vector2(0,0) + var speed = origin.distance_to(vel) + + reticle_lines[0].position = lerp(reticle_lines[0].position, pos + Vector2(0, -speed * reticle_spread), reticle_speed) + reticle_lines[1].position = lerp(reticle_lines[1].position, pos + Vector2(-speed * reticle_spread, 0), reticle_speed) + reticle_lines[2].position = lerp(reticle_lines[2].position, pos + Vector2(speed * reticle_spread, 0), reticle_speed) + reticle_lines[3].position = lerp(reticle_lines[3].position, pos + Vector2(0, speed * reticle_spread), reticle_speed) + + +func update_reticle_settings(): + # Dot + $dot.scale.x = dot_size + $dot.scale.y = dot_size + $dot.color = dot_color + + # Lines + for line in reticle_lines: + line.default_color = line_color + line.width = line_width + if cap_mode == 0: + line.begin_cap_mode = Line2D.LINE_CAP_NONE + line.end_cap_mode = Line2D.LINE_CAP_NONE + elif cap_mode == 1: + line.begin_cap_mode = Line2D.LINE_CAP_ROUND + line.end_cap_mode = Line2D.LINE_CAP_ROUND + + # Please someone find a better way to do this + reticle_lines[0].points[0].y = -line_distance + reticle_lines[0].points[1].y = -line_length - line_distance + reticle_lines[1].points[0].x = -line_distance + reticle_lines[1].points[1].x = -line_length - line_distance + reticle_lines[2].points[0].x = line_distance + reticle_lines[2].points[1].x = line_length + line_distance + reticle_lines[3].points[0].y = line_distance + reticle_lines[3].points[1].y = line_length + line_distance +" + +[node name="Reticle" type="CenterContainer"] +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +grow_horizontal = 2 +grow_vertical = 2 +script = SubResource("GDScript_a8kpl") + +[node name="dot" type="Polygon2D" parent="."] +polygon = PackedVector2Array(-1, -1, 1, -1, 1, 1, -1, 1) + +[node name="top" type="Line2D" parent="."] +points = PackedVector2Array(0, -5, 0, -15) +width = 2.0 + +[node name="left" type="Line2D" parent="."] +points = PackedVector2Array(-5, 0, -15, 0) +width = 2.0 + +[node name="right" type="Line2D" parent="."] +points = PackedVector2Array(5, 0, 15, 0) +width = 2.0 + +[node name="bottom" type="Line2D" parent="."] +points = PackedVector2Array(0, 5, 0, 15) +width = 2.0 diff --git a/project.godot b/project.godot index 4404986..de3d6fd 100644 --- a/project.godot +++ b/project.godot @@ -11,5 +11,55 @@ config_version=5 [application] config/name="first person controller 2.0" +run/main_scene="res://test_world.tscn" config/features=PackedStringArray("4.1", "Forward Plus") config/icon="res://icon.svg" + +[display] + +window/size/mode=2 + +[input] + +ui_left={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null) +, 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,"echo":false,"script":null) +] +} +ui_right={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194321,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null) +, 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,"echo":false,"script":null) +] +} +ui_up={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194320,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null) +, 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,"echo":false,"script":null) +] +} +ui_down={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194322,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null) +, 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,"echo":false,"script":null) +] +} +crouch={ +"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":67,"key_label":0,"unicode":99,"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,"echo":false,"script":null) +] +} diff --git a/test_world.tscn b/test_world.tscn new file mode 100644 index 0000000..93dd8c1 --- /dev/null +++ b/test_world.tscn @@ -0,0 +1,49 @@ +[gd_scene load_steps=9 format=3 uid="uid://cs4drhmc1bql5"] + +[ext_resource type="PackedScene" uid="uid://cc1m2a1obsyn4" path="res://addons/fpc/character.tscn" id="1_e18vq"] + +[sub_resource type="Gradient" id="Gradient_ur0vy"] +colors = PackedColorArray(0, 0.476245, 0.0193456, 1, 0.360494, 0.612721, 0.119744, 1) + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_jd3pw"] +frequency = 0.005 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_7akuf"] +width = 1024 +height = 1024 +in_3d_space = true +color_ramp = SubResource("Gradient_ur0vy") +noise = SubResource("FastNoiseLite_jd3pw") + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_67ysu"] +albedo_texture = SubResource("NoiseTexture2D_7akuf") + +[sub_resource type="PhysicalSkyMaterial" id="PhysicalSkyMaterial_edcox"] +ground_color = Color(0.160784, 0.815686, 0.905882, 1) + +[sub_resource type="Sky" id="Sky_2iust"] +sky_material = SubResource("PhysicalSkyMaterial_edcox") + +[sub_resource type="Environment" id="Environment_20rw3"] +background_mode = 2 +sky = SubResource("Sky_2iust") +tonemap_mode = 1 +ssao_enabled = true + +[node name="test_world" type="Node3D"] + +[node name="character" parent="." instance=ExtResource("1_e18vq")] + +[node name="CSGBox3D" type="CSGBox3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0) +use_collision = true +size = Vector3(10, 1, 10) +material = SubResource("StandardMaterial3D_67ysu") + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_20rw3") + +[node name="sun" type="DirectionalLight3D" parent="."] +transform = Transform3D(0.87959, -0.436605, 0.188936, 0, 0.397148, 0.917755, -0.475732, -0.807248, 0.349328, 0, 0, 0) +light_energy = 4.0 +shadow_enabled = true