Acceleration for a 3D fps game

Godot Version

Godot 4

Question

I want to make it so when you hold down the shift button, you start building up speed like Pizza Tower where you would build up speed and start smashing enemies. How can I make it so that you start to accelerate when you hold the shift key?

Here’s the code for the CharacterBody3D I’m using:

extends CharacterBody3D

var speed
var acceleration 
const WALK_SPEED = 10.0
const SPRINT_SPEED = 20.0
const JUMP_VELOCITY = 7.8
const max_velocity = 100.0

# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = 18.8

@onready var camera = $Camera3D
	
func _ready():
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	camera.current = true

func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
	elif event.is_action_pressed("ui_cancel"):
		Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
		
	if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
		if event is InputEventMouseMotion:
			rotate_y(-event.relative.x * 0.005)
			camera.rotate_x(-event.relative.y * 0.005)
			camera.rotation.x = clamp(camera.rotation.x, -PI/4, PI/3)
			

func _physics_process(delta):
	if not is_on_floor():
		velocity.y -= gravity * delta

	# Handle Jump.
	if Input.is_action_just_pressed("jump") and is_on_floor():
		velocity.y = JUMP_VELOCITY
	
	# Handle Sprint.
	if Input.is_action_pressed("sprint"):
		speed= SPRINT_SPEED
	else:
		speed = WALK_SPEED

	# Get the input direction and handle the movement/deceleration.
	var input_dir = Input.get_vector("left", "right", "forward", "backward")
	var direction = (camera.transform.basis * transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
	if is_on_floor():
		if direction:
			velocity.x = direction.x * speed
			velocity.z = direction.z * speed
		else:
			velocity.x = lerp(velocity.x, direction.x * speed, delta * 7.0)
			velocity.z = lerp(velocity.z, direction.z * speed, delta * 7.0)
	else:
		velocity.x = lerp(velocity.x, direction.x * speed, delta * 3.0)
		velocity.z = lerp(velocity.z, direction.z * speed, delta * 3.0)
	
	move_and_slide()```

The way I’d do it would be to accelerate by a given speed for a given time until you reached your maximum speed allowed while the SHIFT key is held. When the key is released, you might do the opposite and decelerate at a given speed.

So, acceleration of ACC_X for TIME_Y time until MAX_VELOCITY is reached.

Thank you so much. But how would I go about doing this in gdscript? I’m very new to programming and I don’t know much about it.

Some people will give you code, others won’t. I understand that you’re starting, but doing your work wouldn’t help you that much. That’s how I try to help others, when I can.

The only thing I’d add to the above I gave would be that you’d need to add a timer that lasts for the duration of the acceleration/deceleration (so, 5 seconds for example).

Also, you will need a variable that will be triggered to true while shift is held and in your moving function, you use it to accelerate. You’ll also need a var set if you’re accelerating or not because if you don’t and you release SHIFT you won’t have the data needed to tell you that you were indeed accelerating and that you now have to decelerate.

There’s also the problem of stopping mid-acceleration that has to be covered. The time spent accelerating and its accrued speed which must be taken into account when decelerating (and of how long, obviously).

Hopefully that’ll be enough to help.

1 Like

UPDATE: I finally got it to work. Here is the code if anyone else is having trouble:

if Input.is_action_pressed("sprint"):
		speed = move_toward(speed, SPRINT_SPEED, accelerationx * delta)
else:
		speed = WALK_SPEED

Here is how it works:
Basically, when you hold shift, it is taking the speed variable and accelerating it through another variable named accelerationx which is set to 3.0. The SPRINT_SPEED in the code is the max amount of speed you can build it, it is set as a constant, same with WALK_SPEED.

1 Like