How to make player move on a grid & pre-detect collision before moving?

Godot Version

4.2.2

Question

I’m new to Godot so thanks for any help. I’m making a roll & move game (kind of like a board game). I want players to be able to move right, left, up, down with the arrow keys. Each time they press a key, they move a certain # of pixels in that direction (one square).

I’m using a Node2D with a child CharacterBody2D and CollisionShape2D.

I have a tilemap set up with a collision layer/collision map. It works fine if I just use move_and_slide.

Below is the code I have now attached to the CharacterBody2D. It works, but the character moves right through the tiles I have designated as collisions.

My question: how can I pre-determine if the sprite is going to collide with something before it moves and, if so, ignore the input.

extends CharacterBody2D

func get_input():
	var input_direction = Input.get_vector("left", "right", "up", "down")
	
	var dir_l = Input.is_action_just_released("left")
	var dir_r = Input.is_action_just_released("right")
	var dir_u = Input.is_action_just_released("up")
	var dir_d = Input.is_action_just_released("down")

	if dir_l == true:
		position = Vector2(position.x - 16, position.y)
	if dir_r == true:
		position = Vector2(position.x + 16, position.y)
	if dir_u == true:
		position = Vector2(position.x, position.y - 16)
	if dir_d == true:
		position = Vector2(position.x, position.y + 16)
	

func _physics_process(delta):
	get_input()

I’d use a RayCast2D as a child node of the player. If the RayCast is colliding with an obstacle, you can ignore the player’s input.

Thanks. That got me closer. However, I’m still having some strange issues. I added a RayCast2D child node to the CharacterBody2D. Here is the code I am using now:

func get_input():
	var input_direction = Input.get_vector("left", "right", "up", "down")
	
	var dir_l = Input.is_action_just_released("left")
	var dir_r = Input.is_action_just_released("right")
	var dir_u = Input.is_action_just_released("up")
	var dir_d = Input.is_action_just_released("down")

	if dir_l == true:
		$RayCast2D.target_position = Vector2(-16,0)
		if $RayCast2D.is_colliding():
			print("collision")
			var point = $RayCast2D.get_collision_point()
			print(point)
		else:
			position = Vector2(position.x - 16, position.y)

If I’m understanding this correctly, if the player presses the left arrow, this should check to see if there are any collisions with 16 pixels to the left of the player sprite. If not, the player will move 16 pixels to the left. If there is a collision, the left key press will be ignored and the collision will be logged in the debug console.

But, what is actually happening is I get collisions when the player sprite in nowhere near a tile I have given a collision mask to. Here is a little screencap video showing what’s happening (only the wall tiles have a collision mask):

Thanks for any help you can give.

Nevermind–I figured this out. I had an offset on the sprite that was messing things up. It is working now.