Can my FPS controller be improved?
Asked Answered
B

1

0

I want to see if my first person controller (with headbobbing, footstep sounds, movement smoothing and mouse smoothing) could be improved, fixed or cleaned up in any way or if it is okay as it is now. Input and critique are appreciated.

Here's the code:

extends CharacterBody3D

@onready var neck = $AnimHolder/neck
#Neck: a Node3d which acts as a pivot to rotate the camera.
@onready var animHolder = $AnimHolder
#AnimHolder: a parent Node3D which applies animations without directly rotating the children inside.
@onready var hAnimTree = $AnimHolder/hAnimTree
#hAnimTree: The animation tree which controls the movements of the AnimHolder and other transforms.
@onready var colliderStanding = $collider_standing
#ColliderStanding: The collider that is active, currently. A 'crouching' collider will be added soon.
@onready var raycast_to_ground = $RaycastToGround
#RaycastToGround: A raycast pointing towards the ground.
@onready var pauseMenu = $"../pauseMenu"
#PauseMenu: The game's pause menu.

@onready var fstp_walk_tile = $footstepSound_walk
#FstpWalkTile: A footstep sound which plays when the headbobbing animations call it. More of these will be added soon.
@onready var fstp_jump_generic = $footstepSound_jump
#FstpJumpGeneric: A sound that plays when the player jumps. More will probably be added soon.


@export var captureMouseInsideWindow = true
#Determines if the mouse should be captured inside the window when everything loads into the scene tree.
@export var playerDizziness:float
#A for-fun variable that makes the player feel 'dizzy' if set to 1.
@export var walkSpeed = 5
#The player's walk speed.
@export var walkHeadbobSpeed = 1
#The player's headbobbing and footsteps speed when walking.
@export var runningSpeed = 10
#The player's running speed.
@export var runningHeadbobSpeed = 1.5
#The player's headbobbing and footsteps speed when running.
@export var friction = 10;
#The player's friction whilst on the ground. Lower = smoother, higher = more precise.
@export var midAirFriction = 0
#The player's relative friction whilst in the air.
@export var mouseFriction = 10;
#The player's mouse smoothing. Lower = smoother, higher = more precise.
@export var crouchedWalkSpeed = 3;
#The player's movement speed when crouched. This is unused, for now.
@export var jumpForce = 4.5
#The force that the player has while jumping.
@export var gravity = 9
#The intensity of the effect of gravity on the player.
@export var mouseSensitivity = 0.4;
#The player's mouse sensitivity. Higher = faster movement.
@export var mouseClampingDegrees = Vector2(-90, 90)
#A Vector2 which stores the minimum and maximum clamping degrees that the camera's pitch should be limited to.

var currentSpeed: float;
#The player's current movement speed. Switches between walking and running on-command.
var currentHeadbobSpeed: float;
#The player's current headbob and footstep speed.
var currentFriction: float;
#The player's current friction.
var cameraInput : Vector2
#Raw camera input from the player.
var movementDirection: Vector3
#The movement direction of the player.
var playerDirection: float;
#The yaw rotation of the player.
var cameraPitch: float;
#The pitch rotation of the camera.
var combinedRotation: Vector2
#Combines the camera pitch and player yaw into a Vector2.
var rotationVelocity: Vector2;
#A smoothed version of combinedRotation.
var movementVelocity: float
#A variable that roughly tracks the amount of movement the player is doing.

var isInAir: bool
var isMoving: float;
var isRunning: bool
var time: float

func leftFootstep():
	fstp_walk_tile.play()
func rightFootstep():
	fstp_walk_tile.play()
#Happens when the game has started and is ready to play.
func _ready():
	if(captureMouseInsideWindow):
		Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
	if(hAnimTree.active == false):
		hAnimTree.active = true

func _input(event):
	if event is InputEventMouseMotion:
		cameraInput = event.relative
	if event.is_action_pressed("escape"):
		pauseMenu.pause()

func _process(delta):
	
	time += delta
	#Rough approximation of time since game started.
	
	#Defining player direction and camera pitch
	playerDirection -= cameraInput.x * mouseSensitivity
	cameraPitch -= cameraInput.y * mouseSensitivity
	cameraPitch = clamp(cameraPitch, mouseClampingDegrees.x, mouseClampingDegrees.y)
	combinedRotation = Vector2(playerDirection, cameraPitch)
	#Rough approximation of movement velocity.
	movementVelocity = abs(movementDirection).length() * currentHeadbobSpeed
	
	#Rotating camera and smoothing rotation
	rotationVelocity = rotationVelocity.lerp(combinedRotation, delta * mouseFriction)
	rotation.y = deg_to_rad(rotationVelocity.x)
	neck.rotation.x = deg_to_rad(rotationVelocity.y)
	cameraInput *= playerDizziness
	
	#Camera animation
	if(movementVelocity > 0.5):
		hAnimTree.set("parameters/isMoving/transition_request", "move")
		isMoving = true
	else:
		hAnimTree.set("parameters/isMoving/transition_request", "idle")
		isMoving = false
	if(is_on_floor()):
		hAnimTree.set("parameters/inAir/transition_request", "ground")
	else:
		hAnimTree.set("parameters/inAir/transition_request", "air")
	
	#The length of every headbob animation is set to 1 second. This will change the headbob and footstep speed.
	hAnimTree.set("parameters/HeadbobTimeScale/scale", clamp(movementVelocity, walkHeadbobSpeed, INF)) 

#Happens in the physics timestep.
func _physics_process(delta):
	if Input.is_action_pressed("run"):
		isRunning = true
		currentSpeed = runningSpeed
		currentHeadbobSpeed = runningHeadbobSpeed
		hAnimTree.set("parameters/isRunning/transition_request", "run")
	else:
		isRunning = false
		currentSpeed = walkSpeed
		currentHeadbobSpeed = walkHeadbobSpeed
		hAnimTree.set("parameters/isRunning/transition_request", "walk")
	
	if not is_on_floor():
		velocity.y -= gravity * delta
		currentFriction = friction*midAirFriction
	else:
		currentFriction = friction

	if Input.is_action_just_pressed("jump") and is_on_floor():
		velocity.y = jumpForce
		fstp_jump_generic.play()

	var input_dir = Input.get_vector("left", "right", "forwards", "backwards")
	movementDirection = lerp(movementDirection, (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized(), delta * currentFriction)
	
	if movementDirection:
		velocity.x = movementDirection.x * currentSpeed
		velocity.z = movementDirection.z * currentSpeed
	else:
		velocity.x = move_toward(velocity.x, 0, currentSpeed)
		velocity.z = move_toward(velocity.z, 0, currentSpeed)

	move_and_slide()

Now, the scene:

And then the animation tree:

I'm planing to add more features such as leaning (with Q or E), crouching and picking up objects.
Thanks, Alte

Bingaman answered 26/9, 2023 at 2:35 Comment(0)
A
1

Literally a couple of formatting suggestions:

  1. Place above and below the code ```.
    ```
    code
    ```
  1. #Annotation should probably be placed above what it refers to.
    #annotation
    @export [or var]...
Agglutinogen answered 26/9, 2023 at 11:3 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.