164 lines
4.8 KiB
GDScript
164 lines
4.8 KiB
GDScript
## Represents a 3D tetromino (tower block) with shape, position, and rotation.
|
|
##
|
|
## Manages 3D grid cell data, mesh instances, position/rotation state,
|
|
## synergy detection, and material effects.
|
|
class_name Tetromino
|
|
extends Node3D
|
|
|
|
signal hovered(tetromino)
|
|
signal unhovered(tetromino)
|
|
signal selected(tetromino, grid_pos)
|
|
signal deselected(tetromino)
|
|
|
|
# Data
|
|
@export var resource: TetrominoDefinition
|
|
|
|
# Visual
|
|
@export var mesh_color: Color = Color.WHITE
|
|
var _material: StandardMaterial3D
|
|
var _is_ghost: bool = false
|
|
var _original_color: Color = Color.WHITE
|
|
|
|
# Runtime
|
|
@onready var base_damage: int = resource.base_damage
|
|
@onready var fire_rate: float = resource.fire_rate
|
|
@onready var synergy_radius: float = resource.synergy_radius
|
|
@onready var synergy_tags: PackedStringArray = resource.synergy_tags
|
|
@onready var _mesh_instance: MeshInstance3D = get_node("Visuals/MeshInstance3D")
|
|
|
|
# Grid state
|
|
var grid_position: Vector3i = Vector3i.ZERO
|
|
var rotation_quat: Quaternion = Quaternion.IDENTITY
|
|
var _grid_cells: PackedVector3Array = [] # Relative cell coordinates
|
|
|
|
|
|
func _ready() -> void:
|
|
_initialize_material()
|
|
_set_mesh_representation()
|
|
pass
|
|
|
|
|
|
## Initializes the material for visual representation.
|
|
func _initialize_material() -> void:
|
|
_material = StandardMaterial3D.new()
|
|
_material.albedo_color = Color.RED
|
|
_material.metallic = 0.3
|
|
_material.roughness = 0.7
|
|
|
|
|
|
## Creates a simple mesh representation based on shape type.
|
|
func _set_mesh_representation() -> void:
|
|
_mesh_instance.mesh = resource.mesh
|
|
_mesh_instance.set_surface_override_material(0, _material)
|
|
$SelectionArea/CollisionShape3D.shape = _mesh_instance.mesh.create_trimesh_shape()
|
|
_grid_cells = resource.grid_cells
|
|
|
|
|
|
## Gets the grid cells occupied by this tetromino at its current position.
|
|
func get_grid_cells(at_position: Vector3i = grid_position) -> PackedVector3Array:
|
|
var result = PackedVector3Array()
|
|
for cell in _grid_cells:
|
|
result.append(at_position + Vector3i(cell.x, cell.y, cell.z))
|
|
return result
|
|
|
|
|
|
## Gets grid cells with a specific rotation applied.
|
|
func get_grid_cells_with_rotation(at_position: Vector3i, rotation: Quaternion) -> PackedVector3Array:
|
|
var result = PackedVector3Array()
|
|
|
|
# Apply rotation to relative grid cells
|
|
for cell in _grid_cells:
|
|
var rotated = rotation * Vector3(cell)
|
|
var rotated_int = Vector3i(rotated.round())
|
|
result.append(at_position + rotated_int)
|
|
|
|
return result
|
|
|
|
|
|
## Gets the bounds (AABB) of this tetromino.
|
|
func get_bounds() -> AABB:
|
|
var min_cell = Vector3i.ZERO
|
|
var max_cell = Vector3i.ZERO
|
|
|
|
for cell in _grid_cells:
|
|
min_cell = min_cell.min(cell)
|
|
max_cell = max_cell.max(cell)
|
|
|
|
var size = Vector3(max_cell - min_cell) + Vector3.ONE
|
|
var pos = grid_position + min_cell
|
|
|
|
return AABB(Vector3(pos), size)
|
|
|
|
|
|
## Sets the color/material of the tetromino.
|
|
func set_color(color: Color) -> void:
|
|
mesh_color = color
|
|
_original_color = color
|
|
if _material:
|
|
_material.albedo_color = color
|
|
|
|
|
|
## Enables/disables ghost mode (semi-transparent, movable state).
|
|
func set_ghost_mode(enabled: bool) -> void:
|
|
_is_ghost = enabled
|
|
|
|
if enabled:
|
|
# Create material if needed
|
|
if not _material:
|
|
_initialize_material()
|
|
|
|
# Make semi-transparent
|
|
var ghost_color = _original_color
|
|
ghost_color.a = 0.5
|
|
_material.albedo_color = ghost_color
|
|
_mesh_instance.set_surface_override_material(0, _material)
|
|
else:
|
|
# Restore original appearance
|
|
if _material:
|
|
_material.albedo_color = _original_color
|
|
_material.albedo_color.a = 1.0
|
|
_mesh_instance.set_surface_override_material(0, _material)
|
|
|
|
|
|
## Enables/disables highlight for visual feedback.
|
|
func set_highlighted(enabled: bool) -> void:
|
|
if _material:
|
|
_material.emission_enabled = enabled
|
|
if enabled:
|
|
_material.emission = mesh_color
|
|
_material.emission_energy_multiplier = 2.0
|
|
else:
|
|
_material.emission_energy_multiplier = 0.0
|
|
|
|
|
|
## Returns string representation for debugging.
|
|
func _to_string() -> String:
|
|
return "Tetromino3D[type=%s, pos=%v, cells=%d]" % [
|
|
resource.shape_type,
|
|
grid_position,
|
|
_grid_cells.size()
|
|
]
|
|
|
|
## Callback used to handle tetromino selection and deselection
|
|
func _on_selection_area_input_event(camera: Node, event: InputEvent, event_position: Vector3, normal: Vector3, shape_idx: int) -> void:
|
|
if event is InputEventMouseButton:
|
|
if event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
|
|
print("Tetromino selected")
|
|
selected.emit(self, grid_position)
|
|
elif event.pressed and event.button_index == MOUSE_BUTTON_RIGHT:
|
|
print("Tetromino released")
|
|
deselected.emit(self)
|
|
|
|
|
|
## Callback used to handle tetromino hovering
|
|
func _on_selection_area_mouse_entered() -> void:
|
|
print("Tetromino hovered")
|
|
set_highlighted(true)
|
|
hovered.emit(self)
|
|
|
|
## Callback used to handle tetromino unhovering
|
|
func _on_selection_area_mouse_exited() -> void:
|
|
print("Tetromino unhovered")
|
|
set_highlighted(false)
|
|
unhovered.emit(self)
|