How can I make animated grid-based movement with physics collisions? (Godot 4.5)

Godot Version

Godot 4.5

Question

I am making a top-down 2d dungeon crawler game and want to implement grid-based movement. I have tried using move_and_collide() which does collide with the walls in my tilemap but I cannot figure out how to make it go no further than 1 tile per keypress. I have also tried move_toward() which makes it very easy to limit the movement to 1 tile, but ignores my physics layer completely. From my understanding, move_and_slide() is not useful here as I just want the player to stop when they hit a wall, not slide along it, and it would have the same problems as move_and_collide() anyway. So how do I either make move_toward() recognise the physics layer or make move_and_collide stop after 1 tile (16 pixels)? I am using a CharacterBody2D node with CollisionShape2D and AnimatedSprite2D children. Here is my current code (using move_toward() because although it goes through walls I understand it better than move_and_collide()):

extends CharacterBody2D

var direction := Vector2.ZERO
var target := Vector2.ZERO
const SPEED = 150.0

func _ready() -> void:
	position = Vector2(0.5 * 16,0.5 * 16)

func _physics_process(delta: float) -> void:
	# Handle the acceleration and deceleration:
	if direction:
		if (target-position).length() > 0.00390625:
			#move_and_collide(target)
			print(position)
			position = position.move_toward(target, SPEED * delta)
		else:
			position = target

func _input(event: InputEvent) -> void:
	# If the user tries to move, update the direction vector:
	if event.is_action_pressed("character_move_left"):
		direction = Vector2(Input.get_axis("character_move_left", "character_move_right"),Input.get_axis("character_move_up", "character_move_down"))
		target = position + direction * 16
		print(target)

If you’re using grid-based movement, it might be better to not give the player collision at all, and just have raycasts pointing in every direction the player can move. If the raycast is colliding, don’t move the player. If it isn’t, animate the movement and ignore or buffer inputs during the animation.

Thanks for the advice. Mostly implemented now and working great.

1 Like