Coding Push-able blocks on a GridMap

Godot Version

Godot 4

Question

I wanted to make a 3D push block puzzle and make it so that the blocks were aligned on a grid. I found this old tutorial from GDQuest on how to do it, but it was in 2D and in Godot 3. I’ve haven’t ran into many problems so far when trying to reconfigure the entire tutorial to be in 3D and Godot 4, but I’ve finally hit a wall.

I am now at the part [7:13] where we code to align the box to the tile map (in this case it would be my Grid map). old GDScript syntax had the function world_to_map(). I was able to find an equivlant in local_to_map() / map_to_local() but when reading doccumentation for these two functions and comparing them to the old one, I noticed that they both use a new data type called Vector3i. which makes sense because if you are aligned to a grid there will be no decimal values.

I am currently getting an error that I “obviously” cant add the vector3 direction of my character pushing on the box to the Vector3i of the local_to_map() function. So I tried changing some values to be Vector3i, which didnt give me any errors or crashes but my block would not budge whatsoever. I now changed my code back to be the “exact” replication from the video. So now I am getting the error for var grid_map_position where i cant add the Vector3i and Vector3 together. How can I modify this to work in Godot 4?

**EDIT:**I found that all i needed to do for converting the direction argument was to put Vector3i(direction).i then found out that since it rounds any decimal value down to 0 and that I was normalizing the argument it would never move anywhere because direction was 0. so i wrote Vector3i(direction.round()) and it now properly moves one grid space whenever i collide with it.

But now I am able to push it diagonally as well as run up against it and push it along with me. So now I am wondering how do I stop those two cases from happening?


@export var sliding_time:= 0.3

var grid_map : GridMap
var sliding: = false

func initialize(_grid_map: GridMap) -> void:
	grid_map = _grid_map
	position = calculate_destination(Vector3())

func push(push_force: Vector3) -> void:
	if sliding:
		return
	var move_to:= calculate_destination(push_force.normalized())
	if can_move(move_to): 
		var tween := get_tree().create_tween()
		sliding = true
		tween.tween_property(self, "global_position", move_to, sliding_time).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_CUBIC)
		await tween
		sliding = false

func calculate_destination(direction: Vector3) -> Vector3:
	var grid_map_position = grid_map.local_to_map(global_position) + Vector3i(direction.round())
	return grid_map.map_to_local(grid_map_position)

func can_move(move_to: Vector3) -> bool:
	var future_transform: = Transform3D(transform)
	future_transform.origin = move_to
	return not test_move(future_transform, Vector3())