Tile-Based Random Movement Going Too Fast

Godot Version

Godot 4.7

Question

I am trying to make an entity that randomly moves while snapping to a grid. With the code I currently have, it generates a random number, then uses that number to decide which direction to go to. However, it will continue to go in that direction very quickly, which is probably due to the physics processing speed. I need it to pick a direction, move one tile, then pick a new direction instead of repeating the same direction for the duration of the timer.

Here is the movement code I have now. I tried adding timers to stall movement, but they didn’t have any effect.

extends CharacterBody2D

const tile_size: Vector2 = Vector2(16, 16)
var currPos = [0,0]
var dir
var current_states
enum entity_states{MOVERIGHT, MOVELEFT, MOVEUP, MOVEDOWN}

func _on_timer_timeout() -> void:
	random_generation()
	print(dir)
	$Timer.start()

func random_generation():
	dir = randi() % 4
	random_direction()

func random_direction():
	match dir:
		0:
			current_states = entity_states.MOVERIGHT
		1:
			current_states = entity_states.MOVELEFT
		2:
			current_states = entity_states.MOVEUP
		3:
			current_states = entity_states.MOVEDOWN

func move_right():
	if !$right.is_colliding():
		currPos[0] += 16
		$Sprite2D.flip_h = true
		print("right")
func move_left():
	if !$left.is_colliding():
		currPos[0] -= 16
		$Sprite2D.flip_h = false
		print("left")
func move_up():
	if !$up.is_colliding():
		currPos[1] -= 16
		print("up")
func move_down():
	if !$down.is_colliding():
		currPos[1] += 16
		print("down")

func _physics_process(delta: float) -> void:
	match current_states:
		entity_states.MOVERIGHT:
			move_right()
		entity_states.MOVELEFT:
			move_left()
		entity_states.MOVEUP:
			move_up()
		entity_states.MOVEDOWN:
			move_down()
	self.position = Vector2(currPos[0], currPos[1])

You could add a new state, entity_states.WAITING. Now the movement states move the entity only once.

func _physics_process(delta: float) -> void:
	match current_states:
		entity_states.WAITING:
			return # don't do anything
		entity_states.MOVERIGHT:
			move_right()
		entity_states.MOVELEFT:
			move_left()
		entity_states.MOVEUP:
			move_up()
		entity_states.MOVEDOWN:
			move_down()
	# entity just moved, so change state to WAITING
	current_states = entity_states.WAITING
	self.position = Vector2(currPos[0], currPos[1])

That worked, thank you!