format
Some checks failed
Some checks failed
This commit is contained in:
308
scenes/game/gameplays/Tile.gd
Normal file
308
scenes/game/gameplays/Tile.gd
Normal file
@@ -0,0 +1,308 @@
|
||||
extends Node2D
|
||||
|
||||
signal tile_selected(tile: Node2D)
|
||||
|
||||
# Target size for each tile to fit in the 54x54 grid cells
|
||||
const TILE_SIZE = 48 # Slightly smaller than 54 to leave some padding
|
||||
|
||||
@export var tile_type: int = 0:
|
||||
set = _set_tile_type
|
||||
|
||||
var grid_position: Vector2i
|
||||
var is_selected: bool = false:
|
||||
set = _set_selected
|
||||
var is_highlighted: bool = false:
|
||||
set = _set_highlighted
|
||||
var original_scale: Vector2 = Vector2.ONE # Store the original scale for the board
|
||||
|
||||
# All available gem textures
|
||||
var all_gem_textures: Array[Texture2D] = [
|
||||
preload("res://assets/sprites/skulls/red.png"),
|
||||
preload("res://assets/sprites/skulls/blue.png"),
|
||||
preload("res://assets/sprites/skulls/green.png"),
|
||||
preload("res://assets/sprites/skulls/pink.png"),
|
||||
preload("res://assets/sprites/skulls/purple.png"),
|
||||
preload("res://assets/sprites/skulls/dark-blue.png"),
|
||||
preload("res://assets/sprites/skulls/grey.png"),
|
||||
preload("res://assets/sprites/skulls/orange.png"),
|
||||
preload("res://assets/sprites/skulls/yellow.png"),
|
||||
]
|
||||
|
||||
# Currently active gem types (indices into all_gem_textures)
|
||||
var active_gem_types: Array[int] = [] # Will be set from TileManager
|
||||
|
||||
@onready var sprite: Sprite2D = $Sprite2D
|
||||
|
||||
|
||||
func _set_tile_type(value: int) -> void:
|
||||
tile_type = value
|
||||
# Fixed: Add sprite null check to prevent crashes during initialization
|
||||
if not sprite:
|
||||
return
|
||||
if value >= 0 and value < active_gem_types.size():
|
||||
var texture_index = active_gem_types[value]
|
||||
sprite.texture = all_gem_textures[texture_index]
|
||||
_scale_sprite_to_fit()
|
||||
else:
|
||||
DebugManager.log_error(
|
||||
(
|
||||
"Invalid tile type: "
|
||||
+ str(value)
|
||||
+ ". Available types: 0-"
|
||||
+ str(active_gem_types.size() - 1)
|
||||
),
|
||||
"Match3"
|
||||
)
|
||||
|
||||
|
||||
func _scale_sprite_to_fit() -> void:
|
||||
# Fixed: Add additional null checks
|
||||
if sprite and sprite.texture:
|
||||
var texture_size = sprite.texture.get_size()
|
||||
var max_dimension = max(texture_size.x, texture_size.y)
|
||||
var scale_factor = TILE_SIZE / max_dimension
|
||||
original_scale = Vector2(scale_factor, scale_factor)
|
||||
sprite.scale = original_scale
|
||||
DebugManager.log_debug(
|
||||
(
|
||||
"Set original scale to %s for tile (%d,%d)"
|
||||
% [original_scale, grid_position.x, grid_position.y]
|
||||
),
|
||||
"Match3"
|
||||
)
|
||||
|
||||
|
||||
func set_active_gem_types(gem_indices: Array[int]) -> void:
|
||||
if not gem_indices or gem_indices.is_empty():
|
||||
DebugManager.log_error("Empty gem indices array provided", "Tile")
|
||||
return
|
||||
|
||||
active_gem_types = gem_indices.duplicate()
|
||||
|
||||
# Validate all gem indices are within bounds
|
||||
for gem_index in active_gem_types:
|
||||
if gem_index < 0 or gem_index >= all_gem_textures.size():
|
||||
DebugManager.log_error(
|
||||
(
|
||||
"Invalid gem index: %d (valid range: 0-%d)"
|
||||
% [gem_index, all_gem_textures.size() - 1]
|
||||
),
|
||||
"Tile"
|
||||
)
|
||||
# Use default fallback
|
||||
active_gem_types = [0, 1, 2, 3, 4]
|
||||
break
|
||||
|
||||
# Re-validate current tile type
|
||||
if tile_type >= active_gem_types.size():
|
||||
# Generate a new random tile type within valid range
|
||||
tile_type = randi() % active_gem_types.size()
|
||||
|
||||
_set_tile_type(tile_type)
|
||||
|
||||
|
||||
func get_active_gem_count() -> int:
|
||||
return active_gem_types.size()
|
||||
|
||||
|
||||
func add_gem_type(gem_index: int) -> bool:
|
||||
if gem_index < 0 or gem_index >= all_gem_textures.size():
|
||||
DebugManager.log_error("Invalid gem index: %d" % gem_index, "Tile")
|
||||
return false
|
||||
|
||||
if not active_gem_types.has(gem_index):
|
||||
active_gem_types.append(gem_index)
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
func remove_gem_type(gem_index: int) -> bool:
|
||||
var type_index = active_gem_types.find(gem_index)
|
||||
if type_index == -1:
|
||||
return false
|
||||
|
||||
if active_gem_types.size() <= 2: # Keep at least 2 gem types
|
||||
DebugManager.log_warn(
|
||||
"Cannot remove gem type - minimum 2 types required", "Tile"
|
||||
)
|
||||
return false
|
||||
|
||||
active_gem_types.erase(gem_index)
|
||||
|
||||
# Update tile if it was using the removed type
|
||||
if tile_type >= active_gem_types.size():
|
||||
tile_type = 0
|
||||
_set_tile_type(tile_type)
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func _set_selected(value: bool) -> void:
|
||||
var old_value = is_selected
|
||||
is_selected = value
|
||||
DebugManager.log_debug(
|
||||
(
|
||||
"Tile (%d,%d) selection changed: %s -> %s"
|
||||
% [grid_position.x, grid_position.y, old_value, value]
|
||||
),
|
||||
"Match3"
|
||||
)
|
||||
_update_visual_feedback()
|
||||
|
||||
|
||||
func _set_highlighted(value: bool) -> void:
|
||||
var old_value = is_highlighted
|
||||
is_highlighted = value
|
||||
DebugManager.log_debug(
|
||||
(
|
||||
"Tile (%d,%d) highlight changed: %s -> %s"
|
||||
% [grid_position.x, grid_position.y, old_value, value]
|
||||
),
|
||||
"Match3"
|
||||
)
|
||||
_update_visual_feedback()
|
||||
|
||||
|
||||
func _update_visual_feedback() -> void:
|
||||
if not sprite:
|
||||
return
|
||||
|
||||
# Determine target values based on priority: selected > highlighted > normal
|
||||
var target_modulate: Color
|
||||
var target_scale: Vector2
|
||||
var scale_multiplier: float
|
||||
|
||||
if is_selected:
|
||||
# Selected: bright and larger than original board size
|
||||
target_modulate = Color(1.2, 1.2, 1.2, 1.0)
|
||||
scale_multiplier = UIConstants.TILE_SELECTED_SCALE
|
||||
DebugManager.log_debug(
|
||||
(
|
||||
"SELECTING tile (%d,%d): target scale %.2fx, current scale %s"
|
||||
% [
|
||||
grid_position.x,
|
||||
grid_position.y,
|
||||
scale_multiplier,
|
||||
sprite.scale
|
||||
]
|
||||
),
|
||||
"Match3"
|
||||
)
|
||||
elif is_highlighted:
|
||||
# Highlighted: subtle glow and larger than original board size
|
||||
target_modulate = Color(1.1, 1.1, 1.1, 1.0)
|
||||
scale_multiplier = UIConstants.TILE_HIGHLIGHTED_SCALE
|
||||
(
|
||||
DebugManager
|
||||
. log_debug(
|
||||
(
|
||||
"HIGHLIGHTING tile (%d,%d): target scale %.2fx, current scale %s"
|
||||
% [
|
||||
grid_position.x,
|
||||
grid_position.y,
|
||||
scale_multiplier,
|
||||
sprite.scale
|
||||
]
|
||||
),
|
||||
"Match3"
|
||||
)
|
||||
)
|
||||
else:
|
||||
# Normal state: white and original board size
|
||||
target_modulate = Color.WHITE
|
||||
scale_multiplier = UIConstants.TILE_NORMAL_SCALE
|
||||
DebugManager.log_debug(
|
||||
(
|
||||
"NORMALIZING tile (%d,%d): target scale %.2fx, current scale %s"
|
||||
% [
|
||||
grid_position.x,
|
||||
grid_position.y,
|
||||
scale_multiplier,
|
||||
sprite.scale
|
||||
]
|
||||
),
|
||||
"Match3"
|
||||
)
|
||||
|
||||
# Calculate target scale relative to original board scale
|
||||
target_scale = original_scale * scale_multiplier
|
||||
|
||||
# Apply modulate immediately
|
||||
sprite.modulate = target_modulate
|
||||
|
||||
# Only animate scale if it's actually changing
|
||||
if sprite.scale != target_scale:
|
||||
DebugManager.log_debug(
|
||||
(
|
||||
"Animating scale from %s to %s for tile (%d,%d)"
|
||||
% [sprite.scale, target_scale, grid_position.x, grid_position.y]
|
||||
),
|
||||
"Match3"
|
||||
)
|
||||
|
||||
var tween = create_tween()
|
||||
tween.tween_property(sprite, "scale", target_scale, 0.15)
|
||||
|
||||
# Add completion callback for debugging
|
||||
tween.tween_callback(_on_scale_animation_completed.bind(target_scale))
|
||||
else:
|
||||
DebugManager.log_debug(
|
||||
(
|
||||
"No scale change needed for tile (%d,%d)"
|
||||
% [grid_position.x, grid_position.y]
|
||||
),
|
||||
"Match3"
|
||||
)
|
||||
|
||||
|
||||
func _on_scale_animation_completed(expected_scale: Vector2) -> void:
|
||||
DebugManager.log_debug(
|
||||
(
|
||||
"Scale animation completed for tile (%d,%d): expected %s, actual %s"
|
||||
% [grid_position.x, grid_position.y, expected_scale, sprite.scale]
|
||||
),
|
||||
"Match3"
|
||||
)
|
||||
|
||||
|
||||
func force_reset_visual_state() -> void:
|
||||
# Force reset all visual states - debug function
|
||||
is_selected = false
|
||||
is_highlighted = false
|
||||
if sprite:
|
||||
sprite.modulate = Color.WHITE
|
||||
sprite.scale = original_scale # Reset to original board scale, not 1.0
|
||||
DebugManager.log_debug(
|
||||
(
|
||||
"Forced visual reset on tile (%d,%d) to original scale %s"
|
||||
% [grid_position.x, grid_position.y, original_scale]
|
||||
),
|
||||
"Match3"
|
||||
)
|
||||
|
||||
|
||||
# Handle input for tile selection
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
||||
# Check if the mouse click is within the tile's bounds
|
||||
var local_position = to_local(get_global_mouse_position())
|
||||
var sprite_rect = Rect2(
|
||||
-TILE_SIZE / 2.0, -TILE_SIZE / 2.0, TILE_SIZE, TILE_SIZE
|
||||
)
|
||||
|
||||
if sprite_rect.has_point(local_position):
|
||||
tile_selected.emit(self)
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
add_to_group("tiles") # Add to group for gem pool management
|
||||
|
||||
# Initialize with default gem pool if not already set
|
||||
if active_gem_types.is_empty():
|
||||
active_gem_types = [0, 1, 2, 3, 4] # Default to first 5 gems
|
||||
|
||||
_set_tile_type(tile_type)
|
||||
Reference in New Issue
Block a user