nodes/hand.pyΒΆ
Part of Claustrowordia.
1"""Hand: the bottom row of letter tiles waiting to be placed.
2
3Lays out N tiles horizontally below the grid; tiles bounce-tween into
4their slot positions. The Hand owns no input; `Game` resolves clicks
5itself by querying `tile_at(world_pos)`.
6"""
7
8from __future__ import annotations
9
10from simvx.core import Node2D
11from simvx.core.math.types import Vec2
12
13from .textures import TILE_SIZE
14from .tile import Tile
15
16HAND_SIZE = 7
17HAND_SPACING = TILE_SIZE + 14
18
19
20class Hand(Node2D):
21 def __init__(self, centre: Vec2) -> None:
22 super().__init__(name="Hand")
23 self._centre = centre
24 self.tiles: list[Tile] = []
25
26 def on_ready(self) -> None:
27 # Tiles are added externally via `add_tile`.
28 pass
29
30 # ------------------------------------------------------------------
31 def add_tile(self, tile: Tile) -> None:
32 # Start tile off-screen below; layout will tween it up.
33 tile.set_position_immediate(Vec2(self._centre.x, self._centre.y + 200))
34 self.tiles.append(tile)
35 self.add_child(tile)
36 self.layout()
37
38 def remove_tile(self, tile: Tile) -> None:
39 if tile in self.tiles:
40 self.tiles.remove(tile)
41 self.remove_child(tile)
42 self.layout()
43
44 def layout(self) -> None:
45 n = len(self.tiles)
46 if n == 0:
47 return
48 cx = self._centre.x
49 cy = self._centre.y
50 for i, tile in enumerate(self.tiles):
51 x = cx + (i - (n - 1) / 2) * HAND_SPACING
52 tile.set_target(Vec2(x, cy))
53
54 def tile_at(self, world_pos: Vec2) -> Tile | None:
55 """Return topmost hand tile under `world_pos`, or None."""
56 for tile in reversed(self.tiles):
57 dx = world_pos.x - tile.position.x
58 dy = world_pos.y - tile.position.y
59 if abs(dx) <= TILE_SIZE / 2 and abs(dy) <= TILE_SIZE / 2:
60 return tile
61 return None
62
63 def clear(self) -> None:
64 for tile in list(self.tiles):
65 self.remove_child(tile)
66 self.tiles.clear()
67
68
69__all__ = ["Hand", "HAND_SIZE"]