Trying to have a Sprite2D follow mouse while snapping to tilemaplayer and preventing overlapping to other placed Sprites

Godot Version

4.4.1.stable

Question

I tried to do this with tiles and code, but it got overly complicated over time. I decided to spawn Sprite2D as ‘cargo’ boxes for my game. The idea is for the game to spawn buttons that are then assigned to random cargo of a variety of shapes. Then you have to fit then into the ship’s cargohold but they cannot overlap each other. I was able to figure out how to spawn sprites via gdscript and have them follow the mouse pointer, but I do not know how to spawn the sprite so the mouse pointer is ‘centered’ on a corner of the sprite. And how do I ‘place’ a Sprite2D? And when the Sprite2D is placed, I want to prevent other shapes from overlapping it. I understand Collisionshap2D can prevent the Sprite2D from overlapping each other, but how do I set that if the Sprite2D is being made via code? Also, how can I make the Sprite2D ‘snap’ to the grid of the tilemap? The code below is what I have so far:

extends TileMapLayer

@onready var h_box_container: HBoxContainer = $"../HUD/Panel/HBoxContainer"
@onready var cargo: TileMapLayer = $"."
@onready var placed_cargo: TileMapLayer = $"../Placed_cargo"

var mouse_position: Vector2i
var old_mouse_position: Vector2i

func button_pressed(btn: Button, cargo_selector: int):
		Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
		var sprite = Sprite2D.new()
		sprite.texture = load("res://sprites/L.png")
		add_child(sprite)
		btn.queue_free()

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float):
	mouse_position = local_to_map(get_local_mouse_position())
	position = get_viewport().get_mouse_position()
	
	if old_mouse_position != mouse_position:
		erase_cell(old_mouse_position)
		temp_occupied_tiles.clear()
		old_mouse_position = mouse_position

I didn’t really understand what you want to do but I think you have to create a collision too because when you create a sprit via the code you also have to create a collision

Is it possible to create a collision via code? And is it possible to make a collision of a variety of shapes in code or are basic shapes only possible?

I implemented it, give me your code if it doesn’t work, come tell me

extends TileMapLayer

@onready var h_box_container: HBoxContainer = $“../HUD/Panel/HBoxContainer”
@onready var cargo: TileMapLayer = $“.”
@onready var placed_cargo: TileMapLayer = $“../Placed_cargo”

var mouse_position: Vector2i
var old_mouse_position: Vector2i

func button_pressed(btn: Button, cargo_selector: int):
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)

# Create the Sprite2D
var sprite = Sprite2D.new()
sprite.texture = load("res://sprites/L.png")
add_child(sprite)

# Create the CollisionShape2D
var collision = CollisionShape2D.new()
var shape = RectangleShape2D.new()

# Example: set the collision size to match the sprite size
if sprite.texture:
	shape.extents = sprite.texture.get_size() * 0.5
else:
	shape.extents = Vector2(16, 16)  # fallback size

collision.shape = shape

# Add the CollisionShape2D as a sibling of the sprite
add_child(collision)

# Optional: align positions
sprite.position = Vector2.ZERO
collision.position = Vector2.ZERO

btn.queue_free()

Called every frame. ‘delta’ is the elapsed time since the previous frame.

func _process(_delta: float):
mouse_position = local_to_map(get_local_mouse_position())
position = get_viewport().get_mouse_position()

if old_mouse_position != mouse_position:
	erase_cell(old_mouse_position)
	temp_occupied_tiles.clear()
	old_mouse_position = mouse_position

Yes, you can create collisions by code in Godot!
You just add a CollisionShape2D (or CollisionPolygon2D for more complex shapes) as a child of the same parent as your Sprite2D.

Example:
When you create the sprite, you also create a collision shape, set its size to match the sprite’s texture, and add both as children of your parent node (TileMapLayer in your case).

This way, the sprite shows the image and the collision handles physics or overlap detection. They stay aligned because they share the same parent.

Key point:
Collisions and visuals are separate nodes, but they move together under the same parent.

So yes — both simple and complex collisions can be done fully by code!

Ah, interesting. I may tinker with that method then!

1 Like