Player position interaction issue

Godot Version

4.2.1

Question

How can I wait for my player to stop moving?
Hi everyone! new to this forum. I hope someone can help me, and in the future, I could help someone else!
So, this is my players code. It’s a grid-based movement like in the old pokemons. Basically can turn before moving, and then starts moving.

extends CharacterBody2D

class_name Player

signal player_moving_signal
signal player_stopped_signal

signal player_in_grass
signal player_out_of_grass

signal player_entering_door_signal
signal player_entered_door_signal

@export var walk_speed = 8
@export var jump_speed = 4.0

const TILE_SIZE = 16

@onready var anim_tree = $AnimationTree
@onready var anim_state = anim_tree.get("parameters/playback")

@onready var ray = $"RayCast_Collision_World"
@onready var gras = $"RayCast_Entered_TallGras"
@onready var door = $RayCast_Door

@onready var player = get_node("/root/Main/Player")

enum PlayerState { IDLE, TURNING, WALKING }
enum FacingDirection { LEFT, RIGHT, UP, DOWN }

var player_state = PlayerState.IDLE
var facing_direction = FacingDirection.DOWN

static var initial_position = Vector2(0, 0)
var input_direction = Vector2(0, 1)
var is_moving = false
var is_touching_door = false
var stop_input: bool = false
var percent_moved_to_next_tile = 0.0


func _ready():
	$Sprite2D.visible = true
	anim_tree.active = true
	initial_position = position
	anim_tree.set("parameters/Idle/blend_position", input_direction)
	anim_tree.set("parameters/Walk/blend_position", input_direction)
	anim_tree.set("parameters/Turn/blend_position", input_direction)

func set_spawn(location: Vector2, direction: Vector2):
		anim_tree.set("parameters/Idle/blend_position", direction)
		anim_tree.set("parameters/Walk/blend_position", direction)
		anim_tree.set("parameters/Turn/blend_position", direction)
		position = location

func _physics_process(delta):
	if player_state == PlayerState.TURNING or stop_input:
		return
	elif is_moving == false:
		process_player_movement_input()
	elif input_direction != Vector2.ZERO:
		anim_state.travel("Walk")
		move(delta)
	else:
		anim_state.travel("Idle")
		is_moving = false

#region Player movement logic

func process_player_movement_input():
	if input_direction.y == 0:
		input_direction.x = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))
	if input_direction.x == 0:
		input_direction.y = int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up"))
		
	if input_direction != Vector2.ZERO:
		anim_tree.set("parameters/Idle/blend_position", input_direction)
		anim_tree.set("parameters/Walk/blend_position", input_direction)
		anim_tree.set("parameters/Turn/blend_position", input_direction)
		
		if need_to_turn():
			player_state = PlayerState.TURNING
			anim_state.travel("Turn")
		else:
			initial_position = position
			is_moving = true
	else:
		anim_state.travel("Idle")

func need_to_turn():
	var new_facing_direction
	if input_direction.x < 0:
		new_facing_direction = FacingDirection.LEFT
	elif input_direction.x > 0:
		new_facing_direction = FacingDirection.RIGHT
	elif input_direction.y < 0:
		new_facing_direction = FacingDirection.UP
	elif input_direction.y > 0:
		new_facing_direction = FacingDirection.DOWN
	
	if facing_direction != new_facing_direction:
		facing_direction = new_facing_direction
		return true
	facing_direction = new_facing_direction
	return false

func entered_door():
	emit_signal("player_entered_door_signal")

func finished_turning():
	player_state = PlayerState.IDLE

func move(delta):
	var desired_step: Vector2 = input_direction * TILE_SIZE / 2
	ray.target_position = desired_step
	ray.force_raycast_update()
	
	door.target_position = desired_step
	door.force_raycast_update()
	if door.is_colliding():
		if percent_moved_to_next_tile == 0.0:
			emit_signal("player_entering_door_signal")
			percent_moved_to_next_tile += walk_speed * delta
		if percent_moved_to_next_tile >=  0.99:
			position = initial_position + (input_direction * TILE_SIZE)
			percent_moved_to_next_tile = 0.0
			is_moving = false
			stop_input = true
			$AnimationPlayer.play("Disappear")
			$Camera2D.clean_current()
		else:
			position = initial_position + (input_direction * TILE_SIZE * percent_moved_to_next_tile)
	elif !ray.is_colliding():
		if percent_moved_to_next_tile == 0:
			emit_signal("player_moving_signal")
		percent_moved_to_next_tile += walk_speed * delta
		if percent_moved_to_next_tile >= 0.99:
			position = initial_position + (input_direction * TILE_SIZE)
			percent_moved_to_next_tile = 0.0
			is_moving = false
			emit_signal("player_stopped_signal")
		else:
			position = initial_position + (input_direction * TILE_SIZE * percent_moved_to_next_tile)
	else:
		is_moving = false
		
	
	if gras.is_colliding():
		emit_signal("player_in_grass")
	
	if door.is_colliding():
		pass

#endregion


#region Handling player visibility/position related to game interactions

func get_player_global_position() -> Vector2:
	return global_position

func stop_physics_process():
	set_physics_process(false)

func start_physics_process():
	set_physics_process(true)

func _on_scene_switcher_change_player_position(need_scene_name):
	match need_scene_name:
		"overworld_part1":
			player.position = Vector2(480,480)
		"interior_scene":
			player.position = Vector2(176,192)
		"battle_scene":
			pass
		"start_menu":
			pass
		_:
			print(get_player_global_position())
#endregion

Let’s say I want to enter an Area2D. This Area2D will trigger a signal to a higher Node that is in charge of changing scenes.
The problem is that as soon as the Area2D logic triggers, the player keeps moving, so, the player. Position will be the same as the one he was moving. Meaning if I want to change his position depending on the scene, like at the final of the player script. Is there a way for me to tell in the Area2D to wait or let the player finish his movement?

I hope I’m clear with my concern and thanks a lot if you get to this part.! :grinning:

It seems you already have a player_stopped_signal signal, so you would need to connect this signal with a method on that Area2D. The on_area_entered signal from Area2D could be use to store a variable like has_player and then, with the player stopped signal connected to the area, when it triggers, make the method check if has_player. If it has, emit a signal from the Area2D to that higher node (player_entered_area or something like that)

1 Like

I figured it out what is happening.
so i tried to just
set_physics_process(false)

when the player touches the area2d that triggers the scene change.
the thing is that now if i set_physics_process(true) the queue is already loaded and the player goes back to where he was.

It’s there a way to clear the physics_process queue? or just refresh the values

I believe you would need to set each variable to whatever default values they have and then set the physics process to true