Grid System
Relevant source files
The following files were used as context for generating this wiki page:
The Grid System is the core component of the Farm Siege gameplay, representing the 8x8 playable farm area. It is responsible for managing the state of each tile on the farm—what it contains (e.g., plant, mole, weed) and its properties (e.g., plant age)—as well as rendering the visual representation of the entire grid and its contents.
The system is architected around a central state manager, GridStore, which holds the game board's data. This data is then consumed by a hierarchy of rendering components (Grid, GridRow, GridTile) to draw the farm on the canvas. Interactions from the player, such as planting or removing items, and autonomous game events, like moles appearing or plants growing, are all managed through this system.
Architecture
The Grid System follows a unidirectional data flow pattern. The GridStore acts as the single source of truth for the grid's state. The GameScreen component retrieves this state and passes it down as props to the Grid rendering component, which in turn propagates it down to GridRow and finally GridTile components.
Component and Data Flow
This diagram illustrates the relationship between the state store and the rendering components.
*GridStore**: Manages the GridData array and all logic for updating it.
GameScreen: The top-level screen that integrates theGridwith other game elements.Grid: The main grid container, which lays out 8GridRowcomponents.GridRow: Represents a single row in the grid, laying out 8GridTilecomponents.GridTile: Represents a single tile, rendering its appearance based on its state.CharacterContainer: Handles player input and interacts withGridStoreto modify the grid state.
Sources: src/store/GridStore.ts, src/screens/GameScreen.ts:18-31, src/components/grid/Grid.ts:13-88, src/components/grid/GridRow.ts:15-80, src/components/CharacterContainer.ts:113-152
State Management (GridStore)
GridStore is a Store class that encapsulates the state and business logic for the game grid. It holds an 8x8 two-dimensional array representing the farm.
Sources: src/store/GridStore.ts
Data Structures
The grid's state is defined by a set of nested type aliases.
This diagram shows that GridData is an array of 8 RowData elements, and each RowData is an array of 8 TileData elements.
| Type | Definition | Description |
|---|---|---|
TileData | `{ type: TileContents; data: Record<string, string | number>; }` |
RowData | [TileData, TileData, ...] (8 elements) | An array of 8 TileData objects, representing one row. |
GridData | [RowData, RowData, ...] (8 elements) | An array of 8 RowData objects, representing the entire grid. |
Sources: src/store/GridStore.ts:11-17
Initial Grid Generation
When a new game starts, the grid is initialized by the GridUtils.generateInitialGrid() function. This process involves:
- Creating an 8x8 grid filled with
Emptytiles. - Randomly placing an initial number of
Planttiles on the grid, as defined byvalues.plant.startAmount. - Assigning a random starting
ageto each initial plant.
Dynamic Updates
GridStore uses timers to orchestrate dynamic events that change the grid state over time. When start() is called, it initiates several asynchronous update loops.
| Method | Trigger | Description |
|---|---|---|
growPlants() | Timer (every 100ms) | Increments the age of every Plant tile on the grid. |
updateMole() | Timer (random interval) | Manages the appearance and movement of moles. A mole can appear on a random tile, and if one already exists, it moves to a new location, leaving a Molehill behind. |
updateWeed() | Timer (random interval) | Handles the spawning and spreading of weeds. New weeds can appear on empty tiles, and existing weeds can spread to adjacent empty tiles. |
updateLightning() | Timer (random interval) | Simulates a lightning strike on a random 3x3 area, clearing all contents within it and briefly showing a Lightning effect on the central tile. |
The speed of these events (except plant growth) is affected by a speedMultiplier.
Sources: src/store/GridStore.ts:47-64, src/store/GridStore.ts:98-259
Public Methods
GridStore exposes methods for other parts of the application (like CharacterContainer) to interact with the grid.
| Method | Parameters | Description |
|---|---|---|
reset() | void | Resets the grid to a new initial state. |
start() | void | Starts all the dynamic update timers (plants, moles, etc.). |
stop() | void | Stops all active timers. |
removeContent() | x: number, y: number, callback?: (removedContent) => void | Clears the content of a specific tile. It can trigger a callback with the type of content that was removed. |
placePlant() | x: number, y: number | Places a new Plant with age: 0 on an empty tile. |
Sources: src/store/GridStore.ts:26-28, src/store/GridStore.ts:47-49, src/store/GridStore.ts:66-72, src/store/GridStore.ts:74-96, src/store/GridStore.ts:98-111
Rendering Components
The visual representation of the grid is handled by a hierarchy of components, starting with Grid and drilling down to GridTile.
Grid and GridRow
- The
Gridcomponent is a container that receives the entireGridDataobject. Its template consists of 8GridRowcomponents, one for each row in the data. - The
GridRowcomponent receives the data for a single row (RowData). Its template consists of 8GridTilecomponents, passing the appropriateTileDatato each.
This structure breaks down the rendering of the 64-tile grid into manageable, reusable components.
Sources: src/components/grid/Grid.ts:13-88, src/components/grid/GridRow.ts:15-80
GridTile
The GridTile component is responsible for rendering a single 128x128 pixel tile. It is composed of several layers that are conditionally rendered based on the tile's properties and position.
The layers of a GridTile are rendered in the following order:
- Base Sprite: A
dirt.pngsprite that forms the background of every tile. - Checkerboard Overlay: A semi-transparent black rectangle is shown if
(row + column) % 2 === 1to create a checkerboard pattern. - Tile Contents: A
SpriteorComponentis rendered based ontileData.type. This includes different sprites for moles, molehills, weeds, and plants at various growth stages. - Lightning: If the tile type is
Lightning, the dedicatedLightningcomponent is rendered. - Selection Highlight: A semi-transparent white rectangle is shown if the tile's coordinates match the player's current position, indicating the selected tile.
Sources: src/components/grid/GridTile.ts:31-140
The plant sprite is chosen based on its age relative to values.plant.age.fullyGrown.
// src/components/grid/GridTile.ts:71-74
sprite = tomato0;
if ((contentData.age as number) >= (values.plant.age.fullyGrown * 1) / 3) sprite = tomato1;
if ((contentData.age as number) >= (values.plant.age.fullyGrown * 2) / 3) sprite = tomato2;
if ((contentData.age as number) >= values.plant.age.fullyGrown) sprite = tomato3;
Sources: src/components/grid/GridTile.ts:71-74
Grid Utilities (GridUtils)
The GridUtils class provides static helper methods for grid-related calculations and operations.
| Method | Parameters | Return | Description |
|---|---|---|---|
coordsToField() | position: Coordinates | Coordinates | Converts pixel coordinates to integer-based grid field coordinates (e.g., (130, 260) -> (1, 2)). |
coordsToExactField() | position: Coordinates | Coordinates | Converts pixel coordinates to floating-point grid field coordinates. |
rowExists() | y: number | boolean | Checks if a row index is within the valid range (0-7). |
colExists() | x: number | boolean | Checks if a column index is within the valid range (0-7). |
isValidField() | x: number, y: number | boolean | Checks if both row and column indices are valid. |
initialTile | (getter) | TileData | Returns a default TileData object for an empty tile. |
generateInitialGrid() | void | GridData | Creates and returns the entire initial grid state. |
Sources: src/utils/Grid.ts
Summary
The Grid System is a well-defined and decoupled module that forms the foundation of the game's interactive world. It effectively separates state management (GridStore) from rendering logic (Grid, GridRow, GridTile), using a clear, hierarchical component structure. The use of timers in GridStore allows for dynamic and evolving gameplay, while utility functions in GridUtils provide robust helpers for managing grid state and coordinates. This architecture makes the system organized, scalable, and central to the player's experience in Farm Siege.