I wrote a script where I move my 2D character after once pressing a button one step. But it moves only 1 pixels instead of 32 and also jumps up for 1 pixel.
There is a function that measures the distance the character has walked and supposed to stop the character when reaching this distance. Now I am struggling to implement the logic, as this script seems correct, but the character walks only 1 pixel, but the debug says it did 32. Somehow problem expands even on velocity.y value, because character jumps only 1 pixel (roughly 1 frame). I know I am missing something but can't understand where exactly.
I am relatively new in this Godot 4 engine, please help me as I already spent days troubleshooting this issue and watching tutorials. If you see other minor issues I don't see or things that can be optimized please also let me know. If you know a good tutorial on this topic, I will appreciate the sharing.
Here is the function that do the step:
func step(dir, delta):
#if 32 or -32 pixels move character, if not stop character
if dir != 0:
velocity.x = dir * speed * delta #move player 32 pixels left or right
measured_distance += abs(velocity.x) #add walked value to a measurer (and make it always positive)
measured_distance = min(measured_distance, abs(dir)) #if measurer exceeds 32 pixels make it 32
print ("measured_distance: ", measured_distance) #debug , always works
#if measurer equals to 32 pixels or exceeds it
if measured_distance >= abs(dir):
print(measured_distance, " px passed") #debug, always works
dir_distance = 0 #reset universal directory distance to 0
stepping = false #announcing the end of stepping process
else:
stop_step()
Here is the full script:
extends CharacterBody2D
#MOVEMENT
@export var speed: int = 100
@export var step_distance: int = 32 #distance of 32 pixels
@export var jump_velocity: int = -230
var measured_distance: int = 0 #variable used to measure walked distance each step
var stepping: bool = false
var dir_distance: int = 0 #variable that inherits step_distance but changes direction to negative or positive
#PHYSICS
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
#function called from the _physics_process one, it resets the measured_distance and announce stepping process
func start_measure ():
stepping = true
measured_distance = 0
#stops player movement along x value (horizontal)
func stop_step ():
velocity.x = move_toward(velocity.x, 0, speed)
func step(dir, delta):
#if 32 or -32 pixels move character, if not stop character
if dir != 0:
velocity.x = dir * speed * delta #move player 32 pixels left or right
measured_distance += abs(velocity.x) #add walked value to a measurer (and make it always positive)
measured_distance = min(measured_distance, abs(dir)) #if measurer exceeds 32 pixels make it 32
print ("measured_distance: ", measured_distance) #debug , always works
#if measurer equals to 32 pixels or exceeds it
if measured_distance >= abs(dir):
print(measured_distance, " px passed") #debug, always works
dir_distance = 0 #reset universal directory distance to 0
stepping = false #announcing the end of stepping process
else:
stop_step()
#script starts here
func _physics_process(delta):
#if not standing on floor add gravity
if !is_on_floor():
velocity.y += gravity * delta
#if jump pressed once...
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = jump_velocity * delta
#if not doing any step currently allow to press left or right buttons
if !stepping:
if Input.is_action_just_pressed("right"):
dir_distance = step_distance #inherit value with positive value (right)
start_measure()
elif Input.is_action_just_pressed("left"):
dir_distance = -step_distance #inherit value with negative value (left)
start_measure()
#constantly update movement
step(dir_distance, delta) #passes direction (32 pixels left or right) and delta value
move_and_slide()
I am not 100% sure, but I think move_and_slide already adds delta to the velocity, so your actually moved distance differs from the measured_distance.
I am not 100% sure, but I thought move_and_slide already applies delta, which would explain, why you are just moving 1 pixel. But removing delta from velocity.x did not do it, so I have another solution for you. Instead of adding a distance, you are not sure of, you could save the start position, when you are starting to move and check on each iteration, if the player moved 32 px to the left or right. That way you can actually hard set the position of the player, when he reached the 32 px.
your step part would look like this:
func step(dir, delta):
#if 32 or -32 pixels move character, if not stop character
if dir != 0:
velocity.x = dir * speed * delta #move player 32 pixels left or right
if abs(position.x - start_pos.x) >= abs(dir):
print(measured_distance, " px passed") #debug, always works
dir_distance = 0 #reset universal directory distance to 0
stepping = false #announcing the end of stepping process
position.x = start_pos.x + dir #hard set the position to start+32
velocity.x = 0 #destination reached, so no need to move further
else:
stop_step()
start_pos will be set in the pysics_process part which checks for stepping:
if !stepping:
if Input.is_action_just_pressed("right"):
start_pos = position
dir_distance = step_distance #inherit value with positive value (right)
start_measure()
elif Input.is_action_just_pressed("left"):
start_pos = position
dir_distance = -step_distance #inherit value with negative value (left)
start_measure()
Note: you should check if move_and_slide collided with something and end the movement, if so. Otherwise manupulating the position directy could lead to unwanted behaviour (getting stuck in a wall for example).
Edit: Including my whole script, because it does not seem to work for Mimo
extends CharacterBody2D
#MOVEMENT
@export var speed: int = 100
@export var step_distance: int = 32 #distance of 32 pixels
@export var jump_velocity: int = -230
var measured_distance: int = 0 #variable used to measure walked distance each step
var stepping: bool = false
var dir_distance: int = 0 #variable that inherits step_distance but changes direction to negative or positive
#PHYSICS
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
#function called from the _physics_process one, it resets the measured_distance and announce stepping process
func start_measure ():
stepping = true
measured_distance = 0
#stops player movement along x value (horizontal)
func stop_step ():
velocity.x = move_toward(velocity.x, 0, speed)
var start_pos
func step(dir, delta):
#if 32 or -32 pixels move character, if not stop character
if dir != 0:
velocity.x = dir * speed * delta #move player 32 pixels left or right
if abs(position.x - start_pos.x) >= abs(dir):
print(measured_distance, " px passed") #debug, always works
dir_distance = 0 #reset universal directory distance to 0
stepping = false #announcing the end of stepping process
position.x = start_pos.x + dir
velocity.x = 0
else:
stop_step()
#script starts here
func _physics_process(delta):
#if not standing on floor add gravity
if !is_on_floor():
velocity.y += gravity * delta
#if jump pressed once...
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = jump_velocity * delta
#if not doing any step currently allow to press left or right buttons
if !stepping:
if Input.is_action_just_pressed("right"):
start_pos = position
dir_distance = step_distance #inherit value with positive value (right)
start_measure()
elif Input.is_action_just_pressed("left"):
start_pos = position
dir_distance = -step_distance #inherit value with negative value (left)
start_measure()
#constantly update movement
step(dir_distance, delta) #passes direction (32 pixels left or right) and delta value
if not velocity == Vector2.ZERO:
print(velocity)
move_and_slide()