Adding New Tile Content
Relevant source files
The following files were used as context for generating this wiki page:Adding new content to a tile on the game grid is a multi-step process that touches on state management, component rendering, and player interaction logic. "Tile Content" refers to any dynamic entity that can occupy a grid square, such as a plant, mole, or weed. The system is designed to be extensible, allowing new types of content to be integrated by following a clear pattern.
The core architecture involves defining the content type in a central enum, implementing its behavior and lifecycle in the GridStore, creating its visual representation, and finally, integrating it into the GridTile component for rendering on the canvas. Player interactions with the new content are handled within the CharacterContainer component, which communicates with the GridStore to update the game state.
Core Data Structures
The state of each tile on the grid is defined by the TileData object, which is managed by the GridStore.
TileContentsEnum: A numeric enum that acts as a central registry for all possible types of content a tile can hold.TileDataType: An object that represents a single tile's state, containing its type and any associated metadata.
Sources: src/TileContents.ts, src/store/GridStore.ts:10-13
Data Schema
The following diagram illustrates the relationship between the main data structures that define the game grid.
This diagram shows how GridStore holds the GridData, which is a 2D array of TileData objects. Each TileData must have a type from the TileContents enum.
Sources: src/store/GridStore.ts:10-19, src/TileContents.ts:1-8
The TileData structure is defined as:
| Property | Type | Description |
|---|---|---|
type | TileContents | The type of content on the tile, from the TileContents enum. |
data | Record | A key-value object for storing additional state, like a plant's age. |
Sources: src/store/GridStore.ts:10-13
Step-by-Step Guide to Adding New Content
This is the general workflow for adding a new type of tile content.
This flowchart outlines the development process for introducing a new tile content type.
Step 1: Register the New Content Type
The first and most crucial step is to add the new content type to the TileContents enum. This makes the type officially recognized throughout the application.
File: src/TileContents.ts
enum TileContents {
Empty,
Mole,
Molehill,
Weed,
Plant,
Lightning,
// Add new content type here
}
export default TileContents;
Sources: src/TileContents.ts:1-8
Step 2: Implement Game Logic in GridStore
The GridStore is responsible for managing the state of the grid and the lifecycle of its contents. To add behavior for a new content type, you will likely need to:
- Create a new private method (e.g.,
updateNewContent) that handles its spawning, state changes, and removal logic. - Use a
Timerto call this method periodically, creating a lifecycle loop. - Initiate this timer in the
GridStore.start()method.
For example, the updateMole and updateWeed methods are called on a recurring timer to manage their presence and spread on the grid.
File: src/store/GridStore.ts
// src/store/GridStore.ts:49-54
public start(): void {
this.growPlants();
{
const duration = Random.between(values.mole.grace.min, values.mole.grace.max);
const timer = new Timer(duration, this.updateMole.bind(this));
this.timers.push(timer);
}
// ... other timers for weed, lightning, etc.
A new timer block would be added here to start the lifecycle for the new content type.
Sources: src/store/GridStore.ts:49-71, src/store/GridStore.ts:143-268
Step 3: Create the Visual Representation
A tile's content is rendered by the GridTile component. This involves adding a new case to its internal switch statement that maps the TileContents enum value to a visual asset.
For complex content with multiple states (like a growing tomato), it's good practice to create a separate component.
Example: The Tomato Component
The Tomato component renders a different sprite based on the age prop it receives, encapsulating the visual logic for a plant.
File: src/components/tileContents/Tomato.ts
// src/components/tileContents/Tomato.ts:18-34
props: (ctx: PropsContext<TomatoProps>): SpriteProps => {
let source;
switch (ctx.props.age) {
case 0:
source = tomato0;
break;
case 1:
source = tomato1;
break;
case 2:
source = tomato2;
break;
case 3:
source = tomato3;
break;
}
// ...
Sources: src/components/tileContents/Tomato.ts:1-39
Integrating into GridTile
The GridTile component contains a switch statement that determines what to render based on the tileData.type. A new case must be added here for the new content type. This can either point directly to a sprite or use a dedicated component.
File: src/components/grid/GridTile.ts
// src/components/grid/GridTile.ts:62-80
switch (ctx.props.tileData.type) {
case TileContents.Mole:
sprite = mole;
break;
case TileContents.Molehill:
sprite = molehill;
break;
case TileContents.Plant:
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;
break;
case TileContents.Weed:
sprite = weed;
break;
// Add a new case for the new content type here
}
Sources: src/components/grid/GridTile.ts:60-96
Step 4: Define Player Interaction
Player interactions with tile content (e.g., harvesting a plant, removing a weed) are handled in CharacterContainer.ts. When the player presses the 'use' key, it calls gridStore.removeContent. A callback is executed with the type of content that was removed.
A switch statement within this callback determines the outcome, such as adding score or changing the player's held item. A new case must be added for the new content type to define the result of the player's interaction.
This sequence diagram shows the flow from player input to score update when interacting with a tile.
Sources: src/components/CharacterContainer.ts:101-137
Summary
To add new tile content, a developer must modify four key areas of the codebase:
src/TileContents.ts: To define the new content's unique type identifier.src/store/GridStore.ts: To implement the content's lifecycle, behavior, and state transitions.src/components/grid/GridTile.ts: To add the rendering logic that displays the content on the grid.src/components/CharacterContainer.ts: To define how the player interacts with the content and the consequences of that interaction.
By following this established pattern, new features can be added to the game grid in a structured and maintainable way, ensuring they integrate correctly with the existing game engine and logic.