88 lines
2.9 KiB
GDScript
88 lines
2.9 KiB
GDScript
class_name Match3InputHandler
|
|
extends RefCounted
|
|
|
|
## Mouse input handler for Match3 gameplay
|
|
##
|
|
## Static methods for handling mouse interactions in Match3 games.
|
|
## Converts between world coordinates and grid positions, performs hit detection on tiles.
|
|
##
|
|
## Usage:
|
|
## var tile = Match3InputHandler.find_tile_at_position(grid, grid_size, mouse_pos)
|
|
## var grid_pos = Match3InputHandler.get_grid_position_from_world(node, world_pos, offset, size)
|
|
|
|
|
|
static func find_tile_at_position(
|
|
grid: Array, grid_size: Vector2i, world_pos: Vector2
|
|
) -> Node2D:
|
|
## Find the tile that contains the world position.
|
|
##
|
|
## Iterates through all tiles and checks if the world position falls within
|
|
## any tile's sprite boundaries.
|
|
##
|
|
## Args:
|
|
## grid: 2D array of tile nodes arranged in [y][x] format
|
|
## grid_size: Dimensions of the grid (width x height)
|
|
## world_pos: World coordinates to test
|
|
##
|
|
## Returns:
|
|
## The first tile node that contains the position, or null if no tile found
|
|
for y in range(grid_size.y):
|
|
for x in range(grid_size.x):
|
|
if y < grid.size() and x < grid[y].size():
|
|
var tile = grid[y][x]
|
|
if tile and tile.has_node("Sprite2D"):
|
|
var sprite = tile.get_node("Sprite2D")
|
|
if sprite and sprite.texture:
|
|
var sprite_bounds = get_sprite_world_bounds(
|
|
tile, sprite
|
|
)
|
|
if is_point_inside_rect(world_pos, sprite_bounds):
|
|
return tile
|
|
return null
|
|
|
|
|
|
static func get_sprite_world_bounds(tile: Node2D, sprite: Sprite2D) -> Rect2:
|
|
## Calculate the world space bounding rectangle of a sprite.
|
|
##
|
|
## Args:
|
|
## tile: The tile node containing the sprite
|
|
## sprite: The Sprite2D node to calculate bounds for
|
|
##
|
|
## Returns:
|
|
## Rect2 representing the sprite's bounds in world coordinates
|
|
var texture_size = sprite.texture.get_size()
|
|
var actual_size = texture_size * sprite.scale
|
|
var half_size = actual_size * 0.5
|
|
var top_left = tile.position - half_size
|
|
return Rect2(top_left, actual_size)
|
|
|
|
|
|
static func is_point_inside_rect(point: Vector2, rect: Rect2) -> bool:
|
|
# Check if a point is inside a rectangle
|
|
return (
|
|
point.x >= rect.position.x
|
|
and point.x <= rect.position.x + rect.size.x
|
|
and point.y >= rect.position.y
|
|
and point.y <= rect.position.y + rect.size.y
|
|
)
|
|
|
|
|
|
static func get_grid_position_from_world(
|
|
node: Node2D, world_pos: Vector2, grid_offset: Vector2, tile_size: float
|
|
) -> Vector2i:
|
|
## Convert world coordinates to grid array indices.
|
|
##
|
|
## Args:
|
|
## node: Reference node for coordinate space conversion
|
|
## world_pos: Position in world coordinates to convert
|
|
## grid_offset: Offset of the grid's origin from the node's position
|
|
## tile_size: Size of each tile in world units
|
|
##
|
|
## Returns:
|
|
## Vector2i containing the grid coordinates (x, y) for array indexing
|
|
var local_pos = node.to_local(world_pos)
|
|
var relative_pos = local_pos - grid_offset
|
|
var grid_x = int(relative_pos.x / tile_size)
|
|
var grid_y = int(relative_pos.y / tile_size)
|
|
return Vector2i(grid_x, grid_y)
|