Godot Version
4.6
Question
New to Godot and game making in general.
I’m trying to make a spaceship character that can move forward and steer left and right.
I watched a couple of videos to understand how this works, and i put together something that I’m pretty happy about.
The only problem is that if velocity is low or the character is stationary and steer left or right is attempted, the character rotates v quickly and starts slowly making an expanding spiral until in reaches max_speed.
If forward movement is done before or during steering, steering works great.
I understand why this happens but i have no idea how to fix.
Could i get some help on fixing this and also some thoughts on how the movement code is written and if i should change something.
extends CharacterBody2D
# Connected sprites
@onready var character_sprite = $sprite_main_ship
@onready var debug_node = $CharacterDebugNode
# delta time
var global_delta = null
# acceleration parameter
@export var acceleration_normal: float = 300.0
@export var acceleration_boosted: float = 500.0
# max speed reachble by acceleration in normal and boosted navigation
@export var max_speed_normal: float = 500.0
@export var max_speed_boosted: float = 1000.0
# value for direction calculation of steer based on current position
@export var steer_angle: float = 85
var adjust_roation_angle: float = + PI / 2
var adjust_facing_angle: float = -90.0
# current navigation mode max speed
# changes between max_speed_normal and max_speed_boosted
var current_acceleration: float = acceleration_normal
var current_max_speed: float = max_speed_normal
# helps transition from boosted to normal and normal to boosted
# otherwise looks to sudden
var transition_rate: float = 0.1
func set_movement():
_adjust_movement_parameters()
var directional_data: PackedVector2Array = _get_directional_data()
var direction = directional_data.get(0)
var front = directional_data.get(1)
if direction != Vector2.ZERO:
velocity += (direction) * _adjusted_delta_acceleration()
elif direction == Vector2.ZERO:
# reduce lenght of our velocity vector by a linear amount each frame
# have to to this because a scalar value
# can not be subtracted from vector
var new_velocity_length = max(0,velocity.length() - _adjusted_delta_acceleration())
# reduces speed after letting go of direction
velocity = ( velocity.normalized() * new_velocity_length )
_adjuct_velocity(direction)
velocity = velocity.limit_length(current_max_speed)
if velocity != Vector2.ZERO:
character_sprite.rotation = velocity.angle() + (adjust_roation_angle)
# velocity_line, direction and forward facing point
debug_node.debug_process(velocity, front, direction, false, true, true)
# adjust steer angle for steeper or tighter turns
# try not to above 90deg as it starts rotating inwards
func _get_directional_data() -> PackedVector2Array:
# front declaration strictly for debugging
# direction for movement and velocity
var direction: Vector2 = Vector2.ZERO
var front: Vector2 = Vector2.ZERO
# fetch direction based on angle of current position
if Input.get_action_strength("forward"):
direction += Vector2.from_angle(character_sprite.rotation + deg_to_rad(adjust_facing_angle))
if Input.get_action_strength("steer-left"):
direction += Vector2.from_angle(character_sprite.rotation + deg_to_rad(adjust_facing_angle - steer_angle))
if Input.get_action_strength("steer-right"):
direction += Vector2.from_angle(character_sprite.rotation + deg_to_rad(adjust_facing_angle + steer_angle))
front = Vector2.from_angle(character_sprite.rotation + deg_to_rad(adjust_facing_angle))
return [direction, front]
# change acceleration and max_speed based on mode of navigation
func _adjust_movement_parameters():
if Input.get_action_strength("boost") != 1:
current_acceleration = lerp(current_acceleration, acceleration_normal, transition_rate)
current_max_speed = lerp(current_max_speed, max_speed_normal, transition_rate)
if Input.get_action_strength("boost"):
current_acceleration = lerp(current_acceleration, acceleration_boosted, transition_rate)
current_max_speed = lerp(current_max_speed, max_speed_boosted, transition_rate)
# used to add delta to acceleratation
# for easier usage so that this multiplication
# doesnt have to be written over and over
func _adjusted_delta_acceleration() -> float:
return current_acceleration * global_delta
# ! check speed for results, not velocity
# speed = sqrt(x^2, y^2)
func _adjuct_velocity(direction: Vector2) -> void:
# if we accelerate, add 0.1 to the velocity so that we hit max speed
# instead of always being just below it
if direction != Vector2.ZERO:
velocity += velocity.normalized() * .1
# if we decelerate, subtract 0.1 from current velocity to get us to Vector2.ZERO
elif velocity != Vector2.ZERO:
velocity = velocity.normalized() * max(0, velocity.length() - .1)
# ! interesting idea adding + 5.0 instead of - 0.1 causes a friction like effect
# where speed is semi maintained and velocity will be decreased by steering
func _physics_process(delta: float) -> void:
# for easier use, careful monitorization of consequences needed
global_delta = delta
# checks for right acceleration and speed configuration
if current_max_speed < current_acceleration:
print("current_max_speed must be higher or equal to current_acceleration!")
# initialize our movement function the the process
set_movement()
move_and_slide()