Add tetromino movement

This commit is contained in:
2026-01-14 13:52:57 +01:00
parent 6982ded2a1
commit e9689ac3cd
4 changed files with 80 additions and 42 deletions

View File

@@ -20,6 +20,7 @@ signal placement_invalid(reason: String)
var _grid: Dictionary = {} # Key: Vector3i, Value: GridCell3D
var _tetrominoes: Array[Tetromino] = []
var _occupied_cells: Dictionary = {} # Key: Vector3i, Value: Tetromino3D reference
var selected_tetromino: Tetromino
# Ray casting for placement validation
var _space_state: PhysicsDirectSpaceState3D
@@ -28,6 +29,20 @@ var _space_state: PhysicsDirectSpaceState3D
func _ready() -> void:
_space_state = get_world_3d().direct_space_state
_initialize_grid()
# Connect to every tetrominos already present on board
var curr_tetrominos = $TetrominoContainer.get_children();
for t in curr_tetrominos:
t.selected.connect(_on_tetromino_selected)
t.deselected.connect(_on_tetromino_deselected)
func _on_tetromino_selected(tetromino: Tetromino):
print("Tetromino selected")
selected_tetromino = tetromino
func _on_tetromino_deselected(tetromino: Tetromino):
print("Tetromino deselected")
selected_tetromino = null
## Initializes the 3D grid structure with empty cells.
@@ -72,16 +87,16 @@ func is_cell_empty(grid_pos: Vector3i) -> bool:
## Attempts to place a tetromino at the given grid position with optional rotation.
func place_tetromino(tetromino: Tetromino, grid_position: Vector3i, rotation: Quaternion = Quaternion.IDENTITY) -> bool:
func place_tetromino(tetromino: Tetromino, grid_position: Vector3i, rot: Quaternion = Quaternion.IDENTITY) -> bool:
# Validate placement
if not _can_place_tetromino(tetromino, grid_position, rotation):
if not _can_place_tetromino(tetromino, grid_position, rot):
placement_invalid.emit("Invalid placement: overlapping or out of bounds")
return false
# Update tetromino state
tetromino.grid_position = grid_position
tetromino.rotation_quat = rotation
tetromino.world_position = grid_to_world(grid_position)
tetromino.rotation_quat = rot
tetromino.global_position = grid_to_world(grid_position)
# Mark cells as occupied
var cells = tetromino.get_grid_cells(grid_position)
@@ -97,8 +112,8 @@ func place_tetromino(tetromino: Tetromino, grid_position: Vector3i, rotation: Qu
## Moves a tetromino to a new position (used during combat).
func move_tetromino(tetromino: Tetromino, new_grid_position: Vector3i) -> bool:
if tetromino not in _tetrominoes:
return false
#if tetromino not in _tetrominoes:
#return false
# Clear old occupation
var old_cells = tetromino.get_grid_cells(tetromino.grid_position)
@@ -107,20 +122,20 @@ func move_tetromino(tetromino: Tetromino, new_grid_position: Vector3i) -> bool:
if cell_pos in _grid:
_grid[cell_pos].owner = null
# Validate new position
if not _can_place_tetromino(tetromino, new_grid_position, tetromino.rotation_quat):
# Restore old occupation
for cell_pos in old_cells:
_occupied_cells[cell_pos] = tetromino
if cell_pos in _grid:
_grid[cell_pos].owner = tetromino
placement_invalid.emit("Cannot move to target position")
return false
## Validate new position
#if not _can_place_tetromino(tetromino, new_grid_position, tetromino.rotation_quat):
## Restore old occupation
#for cell_pos in old_cells:
#_occupied_cells[cell_pos] = tetromino
#if cell_pos in _grid:
#_grid[cell_pos].owner = tetromino
#placement_invalid.emit("Cannot move to target position")
#return false
# Update position
var old_position = tetromino.grid_position
tetromino.grid_position = new_grid_position
tetromino.world_position = grid_to_world(new_grid_position)
tetromino.global_position = grid_to_world(new_grid_position)
# Mark cells as occupied
var new_cells = tetromino.get_grid_cells(new_grid_position)
@@ -129,7 +144,7 @@ func move_tetromino(tetromino: Tetromino, new_grid_position: Vector3i) -> bool:
if cell_pos in _grid:
_grid[cell_pos].owner = tetromino
tetromino_moved.emit(tetromino, grid_to_world(old_position), tetromino.world_position)
tetromino_moved.emit(tetromino, grid_to_world(old_position), tetromino.global_position)
return true
@@ -194,13 +209,13 @@ func get_tetromino_at(grid_pos: Vector3i) -> Tetromino:
## Gets all adjacent tetrominoes within synergy radius.
func get_adjacent_tetrominoes(tetromino: Tetromino, synergy_radius: float = 2.5) -> Array[Tetromino]:
var adjacent: Array[Tetromino] = []
var world_pos = tetromino.world_position
var world_pos = tetromino.global_position
for other in _tetrominoes:
if other == tetromino:
continue
var distance = world_pos.distance_to(other.world_position)
var distance = world_pos.distance_to(other.global_position)
if distance <= synergy_radius:
adjacent.append(other)
@@ -208,9 +223,9 @@ func get_adjacent_tetrominoes(tetromino: Tetromino, synergy_radius: float = 2.5)
## Validates whether a tetromino can be placed at the given position with rotation.
func _can_place_tetromino(tetromino: Tetromino, grid_position: Vector3i, rotation: Quaternion) -> bool:
func _can_place_tetromino(tetromino: Tetromino, grid_position: Vector3i, rot: Quaternion) -> bool:
# Get the cells this tetromino would occupy
var cells = tetromino.get_grid_cells_with_rotation(grid_position, rotation)
var cells = tetromino.get_grid_cells_with_rotation(grid_position, rot)
# Check all cells are within bounds and empty
for cell_pos in cells:
@@ -222,7 +237,7 @@ func _can_place_tetromino(tetromino: Tetromino, grid_position: Vector3i, rotatio
return false
# Raycast check for physical obstacles
if not _validate_placement_raycast(tetromino, grid_position, rotation):
if not _validate_placement_raycast(tetromino, grid_position):
return false
return true
@@ -230,7 +245,7 @@ func _can_place_tetromino(tetromino: Tetromino, grid_position: Vector3i, rotatio
## Performs raycast validation for tetromino placement.
## Checks for physical obstacles using raycasting.
func _validate_placement_raycast(tetromino: Tetromino, grid_position: Vector3i, rotation: Quaternion) -> bool:
func _validate_placement_raycast(tetromino: Tetromino, grid_position: Vector3i) -> bool:
if not _space_state:
return true