37 Commits
2.4.1 ... main

Author SHA1 Message Date
Austin Dennis
2885aadf4e Various enhancements, fixes, and tweaks focused on improving the inspector (#34)
* Added Dynamic Gravity Toggle

Added an editor toggle for dynamic gravity so users don't need to uncomment code in character.gd.

* Refactor controls export variables

Changed controls export variables to be a single dictionary so they can be edited completely in the editor without having to open the script. I also refactored the controller support section to allow similar functionality for controller specific controls and removed the need to uncomment/comment out lines of code to turn on/off controller support.

* Add more editor descriptions and implement camera axis inversion options

Added/tweaked export variable descriptions so everything has one. Also slightly refactored the camera input inversion code and added the ability to invert the camera x axis.

* Added direction based landing animations

Added some logic to determine which landing animation to play so it's not random anymore. Also added a land_center animation for the case of neutral landings. This can be expanded if desired, but it's pretty convincing as is and is ulitmately a small detail.

* Correct various grammar and spelling errors

A final pass to clean up any grammatical or spelling errors in the comments

* Re-organized Character.gd

Hope I'm not overstepping here, but I re-organized Character.gd to make it a bit easier to read and work with. Added editor bookmarks and collapsible code regions. It's hard to parse in the diff so I recommend you look at it in Godot proper.

* Commented out debug print statement

I assume this was left uncommented by mistake. I was wondering what was printing that to my console.

* Fixed Landing Animation Logic

I guess I was up too late on my first attempt because it straight up didn't work. This new version works as far as my testing can tell.

* Removed some unused variables
2024-10-25 13:30:03 -07:00
288618e6a3 Update to Godot 4.3 2024-09-27 19:47:50 -07:00
Zakarya
5d45e48931 Merge pull request #29 from austinrdennis/main
Update character.gd for base_speed fix
2024-09-26 12:06:04 -07:00
Austin Dennis
b59bbb3673 Update character.gd for base_speed fix
base_speed is assigned to speed before the default is updated to what is set in the export variable causing it to be the incorrect value. Calling enter_normal_state() on ready sets speed to the correct value before the player gains control. From my testing, this has no side effects.
2024-09-21 17:31:43 -04:00
Zakarya
b57da3669c fix README 3 2024-08-20 18:27:22 -07:00
Zakarya
e45406d35c fix README 2 2024-08-20 18:26:05 -07:00
Zakarya
7ace3c48b8 fix README 2024-08-20 18:24:39 -07:00
Zakarya
54a07cc6cf Slope/staircase guide 2024-08-20 18:23:22 -07:00
0e2a12ce5c Fix head rotation 2024-07-24 11:35:05 -07:00
aef3c9c0f9 Fixup #25
Make the PR code more readable and match the style of the codebase
2024-07-24 11:29:38 -07:00
3567b157c0 Improve editor module 2024-07-23 20:18:20 -07:00
6c719b52cc Add a toggle button for the debug panel and clean up some comments 2024-07-23 20:18:20 -07:00
Zakarya
7009032757 Merge pull request #25 from DanielKinsman/invert_pitch
Option to invert mouse/joystick y axis (pitch)
2024-07-23 19:03:48 -07:00
Daniel Kinsman
40f5d21452 Option to invert mouse/joystick y axis (pitch) 2024-07-24 11:31:18 +10:00
14a3fb15f0 Remove hardcoded controller sensitivity 2024-07-17 17:25:17 -07:00
bd603973d0 Add descriptions for exported values 2024-07-17 17:21:27 -07:00
a8d151d568 Add controller support to PR #22 2024-07-15 15:10:44 -07:00
b458cba1a1 Rename handle_rotation to handle_head_rotation 2024-07-15 15:10:20 -07:00
Zakarya
4782f80ec2 Merge pull request #22 from Knockturnal/main
Fixed camera jitter
2024-07-15 14:52:49 -07:00
Knockturnal
8a398bade0 Fixed camera jitter 2024-07-15 17:24:58 +02:00
28becd88c2 Set default values for crouch and sprint in the script 2024-07-02 08:56:27 -07:00
Zakarya
1f9bbd73b3 Merge pull request #20 from Phlegmlee/main
Removed hardcoded lines (causing the sprint and crouch bug) from Character.tscn
2024-07-02 08:55:18 -07:00
Tanner
4c0152e688 Merge branch 'ColormaticStudios:main' into main 2024-07-01 22:04:16 -06:00
Tanner
2d654f7600 Remove hard coded lines
Removed the hard coded lines that were causing the sprint and crouch variables to initialize to lowercase "crouch" and "sprint" instead of user specified values in the script.
2024-07-01 22:03:30 -06:00
6257f07766 Add a comment for check_controls 2024-07-01 19:52:49 -07:00
Zakarya
6a6de243dd Merge pull request #19 from Phlegmlee/main
Removed a stray word in the pause error message.
2024-07-01 19:47:09 -07:00
Tanner
669c951a81 Remove stray word in error message
Removed the word "move" from the error statement referring to the action PAUSE.
2024-07-01 19:55:15 -06:00
c64deaa27a Remove an accidental printf debug
I had added this here to find out why the  headbob animation reset
without any smoothing, but didn't realize it was there in the latest
commit.
2024-07-01 17:15:56 -07:00
be0001e554 Reset a RESET value, attempt to fix a camera bug 2024-06-21 00:11:36 -07:00
2879337ad2 In-editor tools module 2024-05-28 20:28:37 -07:00
80476b2757 An empty line 2024-05-28 20:27:52 -07:00
53935057cd Change if to match in mouse capture code 2024-05-28 20:27:12 -07:00
02018a0105 Only reset headbob animation if it is playing when it is not supposed to 2024-05-28 20:26:27 -07:00
c44be3fbfb Only reset vertical head rotation 2024-05-28 20:24:53 -07:00
b928d6c76b Add a lot of comments 2024-05-28 20:23:39 -07:00
468ff36f4d Gravity is now toggleable 2024-05-28 20:21:53 -07:00
12cf4d63ab Add copyright 2024-05-28 20:20:10 -07:00
6 changed files with 425 additions and 209 deletions

View File

@ -11,14 +11,16 @@ Some parts came from StayAtHomeDev's FPS tutorial. You can find that [here](http
Move with WASD, space to jump, shift to sprint, C to crouch. Move with WASD, space to jump, shift to sprint, C to crouch.
**FEATURES:** **FEATURES:**
- In-air momentum - Extremely configurable
- Motion smoothing - In-air momentum
- FOV smoothing - Motion smoothing
- Movement animations - FOV smoothing
- Crouching - Movement animations
- Sprinting - Crouching
- 2 crosshairs/reticles, one is animated (more to come?) - Sprinting
- Controller/GamePad support (enabled through code, see wiki) - 2 crosshairs/reticles, one is animated (more to come?)
- Controller/GamePad support (enabled through code, see wiki)
- In-editor tools (enable editable children to use)
If you make a cool game with this addon, I would love to hear about it! If you make a cool game with this addon, I would love to hear about it!
@ -31,9 +33,13 @@ You can make this a super basic controller by just disabling everything.
- In the controls export group, there is a commented section at the end that says "Uncomment this if you want full controller support". Uncomment that block. - In the controls export group, there is a commented section at the end that says "Uncomment this if you want full controller support". Uncomment that block.
- Make a key map for each direction (left, right, up, down) and map them to your joystick. - Make a key map for each direction (left, right, up, down) and map them to your joystick.
- Write in these keymaps in the controls section of the player settings. - Write in these keymaps in the controls section of the player settings.
- In the `_process` function, there is another block of commented code at the end that says the same thing. Uncomment that too. - In the `handle_head_rotation` function, there is another block of commented code that says the same thing. Uncomment that too.
- You should now be able to look around with the joystick. Make sure you add the other controls to the input map. (movement, jumping, crouching, sprinting, etc.) - You should now be able to look around with the joystick. Make sure you add the other controls to the input map. (movement, jumping, crouching, sprinting, etc.)
**Slope/staircase:**
Credit to @roberto-urbani23
In the character inspector, you can uncheck Stop on Slope and set the max angle to 89 (for some reason, 90 will make the player stuck). Also Snap Length to 1 otherwise your character will not remain attached to stairs if you sprint while going downstairs.
**How to change settings:** **How to change settings:**
Click on the character node and there should be settings in the "Feature Settings" group. Click on the character node and there should be settings in the "Feature Settings" group.
@ -54,3 +60,8 @@ Use the `change_reticle` function on the character.
- Remove the script from the reticle and create a new one. (for some reason you have to do this) - Remove the script from the reticle and create a new one. (for some reason you have to do this)
- Edit the reticle to your needs. - Edit the reticle to your needs.
- Follow the "how to change reticles" directions to use it. - Follow the "how to change reticles" directions to use it.
**How to use the editor tools:**
- Enable editable children on the `CharacterBody` node
- Use the options in the Properties tab to change things
- These changes apply in runtime as well

View File

@ -0,0 +1,49 @@
@tool
extends Node
# This does not effect runtime yet but will in the future.
@export_category("Controller Editor Module")
@export_range(-360.0, 360.0, 0.01, "or_greater", "or_less") var head_y_rotation : float = 0.0:
set(new_rotation):
if HEAD:
head_y_rotation = new_rotation
HEAD.rotation.y = deg_to_rad(head_y_rotation)
update_configuration_warnings()
@export_range(-90.0, 90.0, 0.01, "or_greater", "or_less") var head_x_rotation : float = 0.0:
set(new_rotation):
if HEAD:
head_x_rotation = new_rotation
HEAD.rotation.x = deg_to_rad(head_x_rotation)
update_configuration_warnings()
@export_group("Nodes")
@export var CHARACTER : CharacterBody3D
@export var head_path : String = "Head" # Relative to the parent node
#@export var CAMERA : Camera3D
#@export var HEADBOB_ANIMATION : AnimationPlayer
#@export var JUMP_ANIMATION : AnimationPlayer
#@export var CROUCH_ANIMATION : AnimationPlayer
#@export var COLLISION_MESH : CollisionShape3D
@onready var HEAD = get_node("../" + head_path)
func _ready():
if !Engine.is_editor_hint():
#print("not editor")
HEAD.rotation.y = deg_to_rad(head_y_rotation)
HEAD.rotation.x = deg_to_rad(head_x_rotation)
func _get_configuration_warnings():
var warnings = []
if head_y_rotation > 360:
warnings.append("The head rotation is greater than 360")
if head_y_rotation < -360:
warnings.append("The head rotation is less than -360")
# Returning an empty array gives no warnings
return warnings

View File

@ -1,177 +1,217 @@
# COPYRIGHT Colormatic Studios
# MIT license
# Quality Godot First Person Controller v2
extends CharacterBody3D extends CharacterBody3D
# TODO: Add descriptions for each value
#region Character Export Group
## The settings for the character's movement and feel.
@export_category("Character") @export_category("Character")
## The speed that the character moves at without crouching or sprinting.
@export var base_speed : float = 3.0 @export var base_speed : float = 3.0
## The speed that the character moves at when sprinting.
@export var sprint_speed : float = 6.0 @export var sprint_speed : float = 6.0
## The speed that the character moves at when crouching.
@export var crouch_speed : float = 1.0 @export var crouch_speed : float = 1.0
## How fast the character speeds up and slows down when Motion Smoothing is on.
@export var acceleration : float = 10.0 @export var acceleration : float = 10.0
## How high the player jumps.
@export var jump_velocity : float = 4.5 @export var jump_velocity : float = 4.5
## How far the player turns when the mouse is moved.
@export var mouse_sensitivity : float = 0.1 @export var mouse_sensitivity : float = 0.1
## Invert the X axis input for the camera.
@export var invert_camera_x_axis : bool = false
## Invert the Y axis input for the camera.
@export var invert_camera_y_axis : bool = false
## Whether the player can use movement inputs. Does not stop outside forces or jumping. See Jumping Enabled.
@export var immobile : bool = false @export var immobile : bool = false
## The reticle file to import at runtime. By default are in res://addons/fpc/reticles/. Set to an empty string to remove.
@export_file var default_reticle @export_file var default_reticle
#endregion
#region Nodes Export Group
@export_group("Nodes") @export_group("Nodes")
## A reference to the camera for use in the character script. This is the parent node to the camera and is rotated instead of the camera for mouse input.
@export var HEAD : Node3D @export var HEAD : Node3D
## A reference to the camera for use in the character script.
@export var CAMERA : Camera3D @export var CAMERA : Camera3D
## A reference to the headbob animation for use in the character script.
@export var HEADBOB_ANIMATION : AnimationPlayer @export var HEADBOB_ANIMATION : AnimationPlayer
## A reference to the jump animation for use in the character script.
@export var JUMP_ANIMATION : AnimationPlayer @export var JUMP_ANIMATION : AnimationPlayer
## A reference to the crouch animation for use in the character script.
@export var CROUCH_ANIMATION : AnimationPlayer @export var CROUCH_ANIMATION : AnimationPlayer
## A reference to the the player's collision shape for use in the character script.
@export var COLLISION_MESH : CollisionShape3D @export var COLLISION_MESH : CollisionShape3D
@export_group("Controls") #endregion
# 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
# Uncomment if you want full controller support #region Controls Export Group
#@export var LOOK_LEFT : String
#@export var LOOK_RIGHT : String # We are using UI controls because they are built into Godot Engine so they can be used right away
#@export var LOOK_UP : String @export_group("Controls")
#@export var LOOK_DOWN : String ## Use the Input Map to map a mouse/keyboard input to an action and add a reference to it to this dictionary to be used in the script.
@export var controls : Dictionary = {
LEFT = "ui_left",
RIGHT = "ui_right",
FORWARD = "ui_up",
BACKWARD = "ui_down",
JUMP = "ui_accept",
CROUCH = "crouch",
SPRINT = "sprint",
PAUSE = "ui_cancel"
}
@export_subgroup("Controller Specific")
## This only affects how the camera is handled, the rest should be covered by adding controller inputs to the existing actions in the Input Map.
@export var controller_support : bool = false
## Use the Input Map to map a controller input to an action and add a reference to it to this dictionary to be used in the script.
@export var controller_controls : Dictionary = {
LOOK_LEFT = "look_left",
LOOK_RIGHT = "look_right",
LOOK_UP = "look_up",
LOOK_DOWN = "look_down"
}
## The sensitivity of the analog stick that controls camera rotation. Lower is less sensitive and higher is more sensitive.
@export_range(0.001, 1, 0.001) var look_sensitivity : float = 0.035
#endregion
#region Feature Settings Export Group
@export_group("Feature Settings") @export_group("Feature Settings")
## Enable or disable jumping. Useful for restrictive storytelling environments.
@export var jumping_enabled : bool = true @export var jumping_enabled : bool = true
## Whether the player can move in the air or not.
@export var in_air_momentum : bool = true @export var in_air_momentum : bool = true
## Smooths the feel of walking.
@export var motion_smoothing : bool = true @export var motion_smoothing : bool = true
## Enables or disables sprinting.
@export var sprint_enabled : bool = true @export var sprint_enabled : bool = true
@export var crouch_enabled : bool = true ## Toggles the sprinting state when button is pressed or requires the player to hold the button down to remain sprinting.
@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_enum("Hold to Sprint", "Toggle Sprint") var sprint_mode : int = 0
## Enables or disables crouching.
@export var crouch_enabled : bool = true
## Toggles the crouch state when button is pressed or requires the player to hold the button down to remain crouched.
@export_enum("Hold to Crouch", "Toggle Crouch") var crouch_mode : int = 0
## Wether sprinting should effect FOV.
@export var dynamic_fov : bool = true @export var dynamic_fov : bool = true
## If the player holds down the jump button, should the player keep hopping.
@export var continuous_jumping : bool = true @export var continuous_jumping : bool = true
## Enables the view bobbing animation.
@export var view_bobbing : bool = true @export var view_bobbing : bool = true
## Enables an immersive animation when the player jumps and hits the ground.
@export var jump_animation : bool = true @export var jump_animation : bool = true
## This determines wether the player can use the pause button, not wether the game will actually pause.
@export var pausing_enabled : bool = true @export var pausing_enabled : bool = true
## Use with caution.
@export var gravity_enabled : bool = true
## If your game changes the gravity value during gameplay, check this property to allow the player to experience the change in gravity.
@export var dynamic_gravity : bool = false
# Member variables #endregion
#region Member Variable Initialization
# These are variables used in this script that don't need to be exposed in the editor.
var speed : float = base_speed var speed : float = base_speed
var current_speed : float = 0.0 var current_speed : float = 0.0
# States: normal, crouching, sprinting # States: normal, crouching, sprinting
var state : String = "normal" var state : String = "normal"
var low_ceiling : bool = false # This is for when the cieling is too low and the player needs to crouch. var low_ceiling : bool = false # This is for when the ceiling is too low and the player needs to crouch.
var was_on_floor : bool = true var was_on_floor : bool = true # Was the player on the floor last frame (for landing animation)
# The reticle should always have a Control node as the root
var RETICLE : Control var RETICLE : Control
# Get the gravity from the project settings to be synced with RigidBody nodes # 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 var gravity : float = ProjectSettings.get_setting("physics/3d/default_gravity") # Don't set this as a const, see the gravity section in _physics_process
# Stores mouse input for rotating the camera in the physics process
var mouseInput : Vector2 = Vector2(0,0)
#endregion
#region Main Control Flow
func _ready(): func _ready():
#It is safe to comment this line if your game doesn't start with the mouse captured
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
HEAD.rotation = rotation # If the controller is rotated in a certain direction for game design purposes, redirect this rotation into the head.
rotation = Vector3.ZERO HEAD.rotation.y = rotation.y
rotation.y = 0
if default_reticle: if default_reticle:
change_reticle(default_reticle) change_reticle(default_reticle)
# Reset the camera position initialize_animations()
HEADBOB_ANIMATION.play("RESET")
JUMP_ANIMATION.play("RESET")
CROUCH_ANIMATION.play("RESET")
check_controls() check_controls()
enter_normal_state()
func check_controls(): # If you add a control, you might want to add a check for it here.
if !InputMap.has_action(JUMP):
push_error("No control mapped for jumping. Please add an input map control. Disabling jump.")
jumping_enabled = false
if !InputMap.has_action(LEFT):
push_error("No control mapped for move left. Please add an input map control. Disabling movement.")
immobile = true
if !InputMap.has_action(RIGHT):
push_error("No control mapped for move right. Please add an input map control. Disabling movement.")
immobile = true
if !InputMap.has_action(FORWARD):
push_error("No control mapped for move forward. Please add an input map control. Disabling movement.")
immobile = true
if !InputMap.has_action(BACKWARD):
push_error("No control mapped for move backward. Please add an input map control. Disabling movement.")
immobile = true
if !InputMap.has_action(PAUSE):
push_error("No control mapped for move pause. Please add an input map control. Disabling pausing.")
pausing_enabled = false
if !InputMap.has_action(CROUCH):
push_error("No control mapped for crouch. Please add an input map control. Disabling crouching.")
crouch_enabled = false
if !InputMap.has_action(SPRINT):
push_error("No control mapped for sprint. Please add an input map control. Disabling sprinting.")
sprint_enabled = false
func change_reticle(reticle): func _process(_delta):
if RETICLE: if pausing_enabled:
RETICLE.queue_free() handle_pausing()
RETICLE = load(reticle).instantiate() update_debug_menu_per_frame()
RETICLE.character = self
$UserInterface.add_child(RETICLE)
func _physics_process(delta): func _physics_process(delta): # Most things happen here.
current_speed = Vector3.ZERO.distance_to(get_real_velocity())
$UserInterface/DebugPanel.add_property("Speed", snappedf(current_speed, 0.001), 1)
$UserInterface/DebugPanel.add_property("Target speed", speed, 2)
var cv : Vector3 = get_real_velocity()
var vd : Array[float] = [
snappedf(cv.x, 0.001),
snappedf(cv.y, 0.001),
snappedf(cv.z, 0.001)
]
var readable_velocity : String = "X: " + str(vd[0]) + " Y: " + str(vd[1]) + " Z: " + str(vd[2])
$UserInterface/DebugPanel.add_property("Velocity", readable_velocity, 3)
# Gravity # Gravity
#gravity = ProjectSettings.get_setting("physics/3d/default_gravity") # If the gravity changes during your game, uncomment this code if dynamic_gravity:
if not is_on_floor(): gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
if not is_on_floor() and gravity and gravity_enabled:
velocity.y -= gravity * delta 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)
low_ceiling = $CrouchCeilingDetection.is_colliding()
handle_state(input_dir)
if dynamic_fov:
update_camera_fov()
if view_bobbing:
headbob_animation(input_dir)
if jump_animation:
if !was_on_floor and is_on_floor(): # Just landed
match randi() % 2:
0:
JUMP_ANIMATION.play("land_left", 0.25)
1:
JUMP_ANIMATION.play("land_right", 0.25)
was_on_floor = is_on_floor() # This must always be at the end of physics_process
handle_jumping()
var input_dir = Vector2.ZERO
if not immobile: # Immobility works by interrupting user input, so other forces can still be applied to the player
input_dir = Input.get_vector(controls.LEFT, controls.RIGHT, controls.FORWARD, controls.BACKWARD)
handle_movement(delta, input_dir)
handle_head_rotation()
# The player is not able to stand up if the ceiling is too low
low_ceiling = $CrouchCeilingDetection.is_colliding()
handle_state(input_dir)
if dynamic_fov: # This may be changed to an AnimationPlayer
update_camera_fov()
if view_bobbing:
play_headbob_animation(input_dir)
if jump_animation:
play_jump_animation()
update_debug_menu_per_tick()
was_on_floor = is_on_floor() # This must always be at the end of physics_process
#endregion
#region Input Handling
func handle_jumping(): func handle_jumping():
if jumping_enabled: if jumping_enabled:
if continuous_jumping: if continuous_jumping: # Hold down the jump button
if Input.is_action_pressed(JUMP) and is_on_floor() and !low_ceiling: if Input.is_action_pressed(controls.JUMP) and is_on_floor() and !low_ceiling:
if jump_animation: if jump_animation:
JUMP_ANIMATION.play("jump", 0.25) JUMP_ANIMATION.play("jump", 0.25)
velocity.y += jump_velocity velocity.y += jump_velocity # Adding instead of setting so jumping on slopes works properly
else: else:
if Input.is_action_just_pressed(JUMP) and is_on_floor() and !low_ceiling: if Input.is_action_just_pressed(controls.JUMP) and is_on_floor() and !low_ceiling:
if jump_animation: if jump_animation:
JUMP_ANIMATION.play("jump", 0.25) JUMP_ANIMATION.play("jump", 0.25)
velocity.y += jump_velocity velocity.y += jump_velocity
@ -181,7 +221,7 @@ func handle_movement(delta, input_dir):
var direction = input_dir.rotated(-HEAD.rotation.y) var direction = input_dir.rotated(-HEAD.rotation.y)
direction = Vector3(direction.x, 0, direction.y) direction = Vector3(direction.x, 0, direction.y)
move_and_slide() move_and_slide()
if in_air_momentum: if in_air_momentum:
if is_on_floor(): if is_on_floor():
if motion_smoothing: if motion_smoothing:
@ -199,10 +239,68 @@ func handle_movement(delta, input_dir):
velocity.z = direction.z * speed velocity.z = direction.z * speed
func handle_head_rotation():
if invert_camera_x_axis:
HEAD.rotation_degrees.y -= mouseInput.x * mouse_sensitivity * -1
else:
HEAD.rotation_degrees.y -= mouseInput.x * mouse_sensitivity
if invert_camera_y_axis:
HEAD.rotation_degrees.x -= mouseInput.y * mouse_sensitivity * -1
else:
HEAD.rotation_degrees.x -= mouseInput.y * mouse_sensitivity
if controller_support:
var controller_view_rotation = Input.get_vector(controller_controls.LOOK_DOWN, controller_controls.LOOK_UP, controller_controls.LOOK_RIGHT, controller_controls.LOOK_LEFT) * look_sensitivity # These are inverted because of the nature of 3D rotation.
if invert_camera_x_axis:
HEAD.rotation.x += controller_view_rotation.x * -1
else:
HEAD.rotation.x += controller_view_rotation.x
if invert_camera_y_axis:
HEAD.rotation.y += controller_view_rotation.y * -1
else:
HEAD.rotation.y += controller_view_rotation.y
mouseInput = Vector2(0,0)
HEAD.rotation.x = clamp(HEAD.rotation.x, deg_to_rad(-90), deg_to_rad(90))
func check_controls(): # If you add a control, you might want to add a check for it here.
# The actions are being disabled so the engine doesn't halt the entire project in debug mode
if !InputMap.has_action(controls.JUMP):
push_error("No control mapped for jumping. Please add an input map control. Disabling jump.")
jumping_enabled = false
if !InputMap.has_action(controls.LEFT):
push_error("No control mapped for move left. Please add an input map control. Disabling movement.")
immobile = true
if !InputMap.has_action(controls.RIGHT):
push_error("No control mapped for move right. Please add an input map control. Disabling movement.")
immobile = true
if !InputMap.has_action(controls.FORWARD):
push_error("No control mapped for move forward. Please add an input map control. Disabling movement.")
immobile = true
if !InputMap.has_action(controls.BACKWARD):
push_error("No control mapped for move backward. Please add an input map control. Disabling movement.")
immobile = true
if !InputMap.has_action(controls.PAUSE):
push_error("No control mapped for pause. Please add an input map control. Disabling pausing.")
pausing_enabled = false
if !InputMap.has_action(controls.CROUCH):
push_error("No control mapped for crouch. Please add an input map control. Disabling crouching.")
crouch_enabled = false
if !InputMap.has_action(controls.SPRINT):
push_error("No control mapped for sprint. Please add an input map control. Disabling sprinting.")
sprint_enabled = false
#endregion
#region State Handling
func handle_state(moving): func handle_state(moving):
if sprint_enabled: if sprint_enabled:
if sprint_mode == 0: if sprint_mode == 0:
if Input.is_action_pressed(SPRINT) and state != "crouching": if Input.is_action_pressed(controls.SPRINT) and state != "crouching":
if moving: if moving:
if state != "sprinting": if state != "sprinting":
enter_sprint_state() enter_sprint_state()
@ -213,10 +311,10 @@ func handle_state(moving):
enter_normal_state() enter_normal_state()
elif sprint_mode == 1: elif sprint_mode == 1:
if moving: if moving:
# If the player is holding sprint before moving, handle that cenerio # If the player is holding sprint before moving, handle that scenario
if Input.is_action_pressed(SPRINT) and state == "normal": if Input.is_action_pressed(controls.SPRINT) and state == "normal":
enter_sprint_state() enter_sprint_state()
if Input.is_action_just_pressed(SPRINT): if Input.is_action_just_pressed(controls.SPRINT):
match state: match state:
"normal": "normal":
enter_sprint_state() enter_sprint_state()
@ -224,16 +322,16 @@ func handle_state(moving):
enter_normal_state() enter_normal_state()
elif state == "sprinting": elif state == "sprinting":
enter_normal_state() enter_normal_state()
if crouch_enabled: if crouch_enabled:
if crouch_mode == 0: if crouch_mode == 0:
if Input.is_action_pressed(CROUCH) and state != "sprinting": if Input.is_action_pressed(controls.CROUCH) and state != "sprinting":
if state != "crouching": if state != "crouching":
enter_crouch_state() enter_crouch_state()
elif state == "crouching" and !$CrouchCeilingDetection.is_colliding(): elif state == "crouching" and !$CrouchCeilingDetection.is_colliding():
enter_normal_state() enter_normal_state()
elif crouch_mode == 1: elif crouch_mode == 1:
if Input.is_action_just_pressed(CROUCH): if Input.is_action_just_pressed(controls.CROUCH):
match state: match state:
"normal": "normal":
enter_crouch_state() enter_crouch_state()
@ -243,7 +341,6 @@ func handle_state(moving):
# Any enter state function should only be called once when you want to enter that state, not every frame. # Any enter state function should only be called once when you want to enter that state, not every frame.
func enter_normal_state(): func enter_normal_state():
#print("entering normal state") #print("entering normal state")
var prev_state = state var prev_state = state
@ -254,7 +351,6 @@ func enter_normal_state():
func enter_crouch_state(): func enter_crouch_state():
#print("entering crouch state") #print("entering crouch state")
var prev_state = state
state = "crouching" state = "crouching"
speed = crouch_speed speed = crouch_speed
CROUCH_ANIMATION.play("crouch") CROUCH_ANIMATION.play("crouch")
@ -267,15 +363,18 @@ func enter_sprint_state():
state = "sprinting" state = "sprinting"
speed = sprint_speed speed = sprint_speed
#endregion
func update_camera_fov(): #region Animation Handling
if state == "sprinting":
CAMERA.fov = lerp(CAMERA.fov, 85.0, 0.3)
else:
CAMERA.fov = lerp(CAMERA.fov, 75.0, 0.3)
func initialize_animations():
# Reset the camera position
# If you want to change the default head height, change these animations.
HEADBOB_ANIMATION.play("RESET")
JUMP_ANIMATION.play("RESET")
CROUCH_ANIMATION.play("RESET")
func headbob_animation(moving): func play_headbob_animation(moving):
if moving and is_on_floor(): if moving and is_on_floor():
var use_headbob_animation : String var use_headbob_animation : String
match state: match state:
@ -283,11 +382,11 @@ func headbob_animation(moving):
use_headbob_animation = "walk" use_headbob_animation = "walk"
"sprinting": "sprinting":
use_headbob_animation = "sprint" use_headbob_animation = "sprint"
var was_playing : bool = false var was_playing : bool = false
if HEADBOB_ANIMATION.current_animation == use_headbob_animation: if HEADBOB_ANIMATION.current_animation == use_headbob_animation:
was_playing = true was_playing = true
HEADBOB_ANIMATION.play(use_headbob_animation, 0.25) HEADBOB_ANIMATION.play(use_headbob_animation, 0.25)
HEADBOB_ANIMATION.speed_scale = (current_speed / base_speed) * 1.75 HEADBOB_ANIMATION.speed_scale = (current_speed / base_speed) * 1.75
if !was_playing: if !was_playing:
@ -296,35 +395,94 @@ func headbob_animation(moving):
# The headbob animation has two starting positions. One is at 0 and the other is at 1. # The headbob animation has two starting positions. One is at 0 and the other is at 1.
# randi() % 2 returns either 0 or 1, and so the animation randomly starts at one of the starting positions. # randi() % 2 returns either 0 or 1, and so the animation randomly starts at one of the starting positions.
# This code is extremely performant but it makes no sense. # This code is extremely performant but it makes no sense.
else: else:
HEADBOB_ANIMATION.play("RESET", 0.25) if HEADBOB_ANIMATION.current_animation == "sprint" or HEADBOB_ANIMATION.current_animation == "walk":
HEADBOB_ANIMATION.speed_scale = 1 HEADBOB_ANIMATION.speed_scale = 1
HEADBOB_ANIMATION.play("RESET", 1)
func play_jump_animation():
if !was_on_floor and is_on_floor(): # The player just landed
var facing_direction : Vector3 = CAMERA.get_global_transform().basis.x
var facing_direction_2D : Vector2 = Vector2(facing_direction.x, facing_direction.z).normalized()
var velocity_2D : Vector2 = Vector2(velocity.x, velocity.z).normalized()
func _process(delta): # Compares velocity direction against the camera direction (via dot product) to determine which landing animation to play.
var side_landed : int = round(velocity_2D.dot(facing_direction_2D))
if side_landed > 0:
JUMP_ANIMATION.play("land_right", 0.25)
elif side_landed < 0:
JUMP_ANIMATION.play("land_left", 0.25)
else:
JUMP_ANIMATION.play("land_center", 0.25)
#endregion
#region Debug Menu
func update_debug_menu_per_frame():
$UserInterface/DebugPanel.add_property("FPS", Performance.get_monitor(Performance.TIME_FPS), 0) $UserInterface/DebugPanel.add_property("FPS", Performance.get_monitor(Performance.TIME_FPS), 0)
var status : String = state var status : String = state
if !is_on_floor(): if !is_on_floor():
status += " in the air" status += " in the air"
$UserInterface/DebugPanel.add_property("State", status, 4) $UserInterface/DebugPanel.add_property("State", status, 4)
if pausing_enabled:
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
HEAD.rotation.x = clamp(HEAD.rotation.x, deg_to_rad(-90), deg_to_rad(90))
# Uncomment if you want full controller support
#var controller_view_rotation = Input.get_vector(LOOK_LEFT, LOOK_RIGHT, LOOK_UP, LOOK_DOWN)
#HEAD.rotation_degrees.y -= controller_view_rotation.x * 1.5
#HEAD.rotation_degrees.x -= controller_view_rotation.y * 1.5
func _unhandled_input(event): func update_debug_menu_per_tick():
# Big thanks to github.com/LorenzoAncora for the concept of the improved debug values
current_speed = Vector3.ZERO.distance_to(get_real_velocity())
$UserInterface/DebugPanel.add_property("Speed", snappedf(current_speed, 0.001), 1)
$UserInterface/DebugPanel.add_property("Target speed", speed, 2)
var cv : Vector3 = get_real_velocity()
var vd : Array[float] = [
snappedf(cv.x, 0.001),
snappedf(cv.y, 0.001),
snappedf(cv.z, 0.001)
]
var readable_velocity : String = "X: " + str(vd[0]) + " Y: " + str(vd[1]) + " Z: " + str(vd[2])
$UserInterface/DebugPanel.add_property("Velocity", readable_velocity, 3)
func _unhandled_input(event : InputEvent):
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
HEAD.rotation_degrees.y -= event.relative.x * mouse_sensitivity mouseInput.x += event.relative.x
HEAD.rotation_degrees.x -= event.relative.y * mouse_sensitivity mouseInput.y += event.relative.y
# Toggle debug menu
elif event is InputEventKey:
if event.is_released():
# Where we're going, we don't need InputMap
if event.keycode == 4194338: # F7
$UserInterface/DebugPanel.visible = !$UserInterface/DebugPanel.visible
#endregion
#region Misc Functions
func change_reticle(reticle): # Yup, this function is kinda strange
if RETICLE:
RETICLE.queue_free()
RETICLE = load(reticle).instantiate()
RETICLE.character = self
$UserInterface.add_child(RETICLE)
func update_camera_fov():
if state == "sprinting":
CAMERA.fov = lerp(CAMERA.fov, 85.0, 0.3)
else:
CAMERA.fov = lerp(CAMERA.fov, 75.0, 0.3)
func handle_pausing():
if Input.is_action_just_pressed(controls.PAUSE):
# You may want another node to handle pausing, because this player may get paused too.
match Input.mouse_mode:
Input.MOUSE_MODE_CAPTURED:
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
#get_tree().paused = false
Input.MOUSE_MODE_VISIBLE:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
#get_tree().paused = false
#endregion

View File

@ -1,6 +1,7 @@
[gd_scene load_steps=20 format=3 uid="uid://cc1m2a1obsyn4"] [gd_scene load_steps=22 format=3 uid="uid://cc1m2a1obsyn4"]
[ext_resource type="Script" path="res://addons/fpc/character.gd" id="1_0t4e8"] [ext_resource type="Script" path="res://addons/fpc/character.gd" id="1_0t4e8"]
[ext_resource type="Script" path="res://addons/fpc/EditorModule.gd" id="3_v3ckk"]
[ext_resource type="Script" path="res://addons/fpc/debug.gd" id="3_x1wcc"] [ext_resource type="Script" path="res://addons/fpc/debug.gd" id="3_x1wcc"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_kp17n"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_kp17n"]
@ -173,17 +174,6 @@ tracks/1/keys = {
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0), "points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
"times": PackedFloat32Array(0) "times": PackedFloat32Array(0)
} }
tracks/2/type = "bezier"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Camera:position:z")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"handle_modes": PackedInt32Array(0),
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0),
"times": PackedFloat32Array(0)
}
[sub_resource type="Animation" id="Animation_8ku67"] [sub_resource type="Animation" id="Animation_8ku67"]
resource_name = "sprint" resource_name = "sprint"
@ -211,17 +201,6 @@ tracks/1/keys = {
"points": PackedFloat32Array(0.05, -0.25, 0, 0.2, -0.01, 0, -0.2, 0.000186046, 0.2, 0.000186046, 0.05, -0.2, -0.01, 0.2, -0.01, 0, -0.2, 0, 0.2, 0, 0.05, -0.2, -0.01, 0.25, 0), "points": PackedFloat32Array(0.05, -0.25, 0, 0.2, -0.01, 0, -0.2, 0.000186046, 0.2, 0.000186046, 0.05, -0.2, -0.01, 0.2, -0.01, 0, -0.2, 0, 0.2, 0, 0.05, -0.2, -0.01, 0.25, 0),
"times": PackedFloat32Array(0, 0.5, 1, 1.5, 2) "times": PackedFloat32Array(0, 0.5, 1, 1.5, 2)
} }
tracks/2/type = "bezier"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Camera:position:z")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"handle_modes": PackedInt32Array(0, 0, 0, 0, 0),
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0),
"times": PackedFloat32Array(0, 0.5, 1, 1.5, 2)
}
[sub_resource type="Animation" id="Animation_lrqmv"] [sub_resource type="Animation" id="Animation_lrqmv"]
resource_name = "walk" resource_name = "walk"
@ -249,17 +228,6 @@ tracks/1/keys = {
"points": PackedFloat32Array(-0.05, -0.25, 0, 0.2, 0.005, 0, -0.2, 0.000186046, 0.2, 0.000186046, -0.05, -0.2, 0.005, 0.2, 0.005, 0, -0.2, 0, 0.2, 0, -0.05, -0.2, 0.005, 0.25, 0), "points": PackedFloat32Array(-0.05, -0.25, 0, 0.2, 0.005, 0, -0.2, 0.000186046, 0.2, 0.000186046, -0.05, -0.2, 0.005, 0.2, 0.005, 0, -0.2, 0, 0.2, 0, -0.05, -0.2, 0.005, 0.25, 0),
"times": PackedFloat32Array(0, 0.5, 1, 1.5, 2) "times": PackedFloat32Array(0, 0.5, 1, 1.5, 2)
} }
tracks/2/type = "bezier"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Camera:position:z")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"handle_modes": PackedInt32Array(0, 0, 0, 0, 0),
"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0),
"times": PackedFloat32Array(0, 0.5, 1, 1.5, 2)
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_o0unb"] [sub_resource type="AnimationLibrary" id="AnimationLibrary_o0unb"]
_data = { _data = {
@ -280,7 +248,7 @@ tracks/0/keys = {
"times": PackedFloat32Array(0), "times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1), "transitions": PackedFloat32Array(1),
"update": 0, "update": 0,
"values": [Vector3(0.0349066, 0, 0)] "values": [Vector3(0, 0, 0)]
} }
tracks/1/type = "value" tracks/1/type = "value"
tracks/1/imported = false tracks/1/imported = false
@ -367,10 +335,39 @@ tracks/1/keys = {
"values": [Vector3(0, 0, 0), Vector3(0, -0.1, 0), Vector3(0, 0, 0)] "values": [Vector3(0, 0, 0), Vector3(0, -0.1, 0), Vector3(0, 0, 0)]
} }
[sub_resource type="Animation" id="Animation_3eyjl"]
resource_name = "land_center"
length = 1.5
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Camera:rotation")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.5, 1.5),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(-0.0349066, 0, 0), Vector3(0, 0, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Camera:position")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.5, 1.5),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, -0.1, 0), Vector3(0, 0, 0)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_qeg5r"] [sub_resource type="AnimationLibrary" id="AnimationLibrary_qeg5r"]
_data = { _data = {
"RESET": SubResource("Animation_fvvjq"), "RESET": SubResource("Animation_fvvjq"),
"jump": SubResource("Animation_s07ye"), "jump": SubResource("Animation_s07ye"),
"land_center": SubResource("Animation_3eyjl"),
"land_left": SubResource("Animation_l1rph"), "land_left": SubResource("Animation_l1rph"),
"land_right": SubResource("Animation_vsknp") "land_right": SubResource("Animation_vsknp")
} }
@ -384,6 +381,7 @@ MarginContainer/constants/margin_top = 10
[sub_resource type="SphereShape3D" id="SphereShape3D_k4wwl"] [sub_resource type="SphereShape3D" id="SphereShape3D_k4wwl"]
[node name="Character" type="CharacterBody3D" node_paths=PackedStringArray("HEAD", "CAMERA", "HEADBOB_ANIMATION", "JUMP_ANIMATION", "CROUCH_ANIMATION", "COLLISION_MESH")] [node name="Character" type="CharacterBody3D" node_paths=PackedStringArray("HEAD", "CAMERA", "HEADBOB_ANIMATION", "JUMP_ANIMATION", "CROUCH_ANIMATION", "COLLISION_MESH")]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0, 0, 0)
script = ExtResource("1_0t4e8") script = ExtResource("1_0t4e8")
default_reticle = "res://addons/fpc/reticles/reticle_1.tscn" default_reticle = "res://addons/fpc/reticles/reticle_1.tscn"
HEAD = NodePath("Head") HEAD = NodePath("Head")
@ -392,8 +390,6 @@ HEADBOB_ANIMATION = NodePath("Head/HeadbobAnimation")
JUMP_ANIMATION = NodePath("Head/JumpAnimation") JUMP_ANIMATION = NodePath("Head/JumpAnimation")
CROUCH_ANIMATION = NodePath("CrouchAnimation") CROUCH_ANIMATION = NodePath("CrouchAnimation")
COLLISION_MESH = NodePath("Collision") COLLISION_MESH = NodePath("Collision")
CROUCH = "crouch"
SPRINT = "sprint"
[node name="Mesh" type="MeshInstance3D" parent="."] [node name="Mesh" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
@ -412,7 +408,6 @@ libraries = {
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0)
[node name="Camera" type="Camera3D" parent="Head"] [node name="Camera" type="Camera3D" parent="Head"]
transform = Transform3D(1, 0, 0, 0, 0.999391, -0.0348995, 0, 0.0348995, 0.999391, 0, 0, 0)
[node name="HeadbobAnimation" type="AnimationPlayer" parent="Head"] [node name="HeadbobAnimation" type="AnimationPlayer" parent="Head"]
libraries = { libraries = {
@ -455,3 +450,6 @@ layout_mode = 2
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
shape = SubResource("SphereShape3D_k4wwl") shape = SubResource("SphereShape3D_k4wwl")
target_position = Vector3(0, 0.5, 0) target_position = Vector3(0, 0.5, 0)
[node name="EditorModule" type="Node" parent="."]
script = ExtResource("3_v3ckk")

View File

@ -5,11 +5,11 @@ func _process(delta):
if visible: if visible:
pass pass
func add_property(title : String, value, order : int): func add_property(title : String, value, order : int): # This can either be called once for a static property or called every frame for a dynamic property
var target var target
target = $MarginContainer/VBoxContainer.find_child(title, true, false) target = $MarginContainer/VBoxContainer.find_child(title, true, false) # I have no idea what true and false does here, the function should be more specific
if !target: if !target:
target = Label.new() target = Label.new() # Debug lines are of type Label
$MarginContainer/VBoxContainer.add_child(target) $MarginContainer/VBoxContainer.add_child(target)
target.name = title target.name = title
target.text = title + ": " + str(value) target.text = title + ": " + str(value)

View File

@ -12,7 +12,7 @@ config_version=5
config/name="first person controller 2.0" config/name="first person controller 2.0"
run/main_scene="res://test_world.tscn" run/main_scene="res://test_world.tscn"
config/features=PackedStringArray("4.2", "Forward Plus") config/features=PackedStringArray("4.3", "Forward Plus")
config/icon="res://icon.svg" config/icon="res://icon.svg"
[display] [display]
@ -23,43 +23,43 @@ window/size/mode=2
ui_left={ ui_left={
"deadzone": 0.5, "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) "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,"location":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(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(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) , 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)
] ]
} }
ui_right={ ui_right={
"deadzone": 0.5, "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) "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,"location":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(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(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) , 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)
] ]
} }
ui_up={ ui_up={
"deadzone": 0.5, "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) "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,"location":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(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(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) , 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)
] ]
} }
ui_down={ ui_down={
"deadzone": 0.5, "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) "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,"location":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(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(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) , 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)
] ]
} }
crouch={ crouch={
"deadzone": 0.5, "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) "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,"location":0,"echo":false,"script":null)
] ]
} }
sprint={ sprint={
"deadzone": 0.5, "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) "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)
] ]
} }