Finally got a grid inventory working in Godot 4 and wanted to share the approach because the drag-and-drop docs kind of gloss over the multi-slot item case.
The grid itself is a flat 2D array (slot_map[row][col]) where each cell holds a reference to whichever ItemInstance occupies it, or null. Visually I'm using a GridContainer of custom SlotControl nodes, which keeps layout clean. The drag is handled by Godot's built-in _get_drag_data / _can_drop_data / _drop_data pipeline, which is actually decent once you stop fighting it.
The annoying part: multi-slot items. A 1x1 potion is fine. A 2x4 two-handed sword is not. The overlap check that ended up working:
func can_place_item(definition: ItemDefinition, grid_x: int, grid_y: int, ignore: ItemInstance = null) -> bool:
for x in range(definition.grid_width):
for y in range(definition.grid_height):
var tx = grid_x + x
var ty = grid_y + y
if tx >= GRID_COLS or ty >= GRID_ROWS:
return false
if slot_map[ty][tx] != null and slot_map[ty][tx] != ignore:
return false
return trueThe ignore parameter handles moving an item within the grid. Without it, the item blocks its own placement when dragged over its current position. Took me embarrassingly long to realize that was the issue.
What I haven't figured out yet: 90-degree item rotation. The width/height swap is obvious but the visual pivot math when the item preview follows the cursor is driving me up the wall. And stacking. Stackable items, do they get separate slot logic or do I just put a stack_size on the instance and let two instances occupy the same cell? Currently leaning toward the latter but it feels like it'll cause problems later.
Anyone else gone down this road? Especially curious how people handled rotation if you've done it. Every approach I've tried looks janky in the preview.