Visual Effects System
Relevant source files
The following files were used as context for generating this wiki page:
The Visual Effects System in Farm Siege is responsible for managing and rendering transient, non-interactive visual elements on the screen. These effects, such as floating score numbers, smoke puffs, and the game-over transition, enhance the player experience by providing visual feedback for in-game events. The system is designed to be decoupled, with a central store managing the state of all active effects and a dedicated overlay component handling their rendering.
The core components of this system are the EffectsStore, which acts as the single source of truth for all effect data, and the Effects overlay, which subscribes to the store and renders the effects on the canvas. Other game components can trigger effects by calling methods on the EffectsStore.
Architecture
The system's architecture separates state management from rendering. Game logic components (like CharacterContainer) dispatch requests to create new effects to the EffectsStore. The main game loop (Game.ts) calls the store's update method on each frame to manage the lifecycle of these effects. The Effects overlay component reads the state from the store and renders the visual representation of each active effect.
This diagram illustrates the data flow for creating and rendering a visual effect.
EffectsStore
The EffectsStore is the central state manager for all visual effects. It holds arrays of data for each effect type and provides methods to create, update, and remove them.
Sources: src/store/EffectsStore.ts
State (EffectsStoreContent)
The store maintains the state of all active effects in its content property.
| Key | Type | Description |
|---|---|---|
smoke | EffectData[] | An array of active smoke particle effects. |
scores | ScoreEffectData[] | An array of active score pop-up effects. |
gameOver | { active, timer, center } | An object managing the state of the game-over screen transition animation. |
Sources: src/store/EffectsStore.ts:13-20
Key Methods
| Method | Parameters | Description |
|---|---|---|
showSmoke | x: number, y: number | Creates a new EffectData instance and adds it to the smoke array. |
showScoreEffect | x: number, y: number, value: number | Creates a new ScoreEffectData instance and adds it to the scores array. |
showGameOverAnimation | center: Coordinates, callback: () => void | Activates the game-over animation, sets its center point, and schedules a callback to be executed after the animation duration. |
updateEffects | timeDifference: number | Called on every game tick. It updates the internal timers of all active effects and filters out any that have expired (i.e., their expired property is true). It also manages the gameOver timer. |
reset | (none) | Resets the store to its initial state, clearing all active effects. This is called when a new game starts. |
Sources: src/store/EffectsStore.ts:32-111, src/screens/StartScreen.ts:63-64
Effect Lifecycle
The updateEffects method is responsible for the entire lifecycle of an effect after its creation.
This flowchart shows the logic within the updateEffects method.
Effects Overlay
The Effects class is a component that renders the visual effects based on the data in EffectsStore. It uses a Repeating logical component to efficiently iterate through the smoke and scores arrays from the store and render a corresponding visual component for each data object.
Sources: src/overlays/Effects.ts
// src/overlays/Effects.ts:13-26
export default class Effects extends Component<EffectsProps> {
protected template: Template = [
// Smoke effects
{
component: new Repeating(),
props: (): RepeatingProps => {
const effectsStore = <EffectsStore>this.stores.effects;
return {
list: effectsStore.content.smoke,
component: (): Smoke => new Smoke(),
position: (data: EffectData): Coordinates => data.position,
props: (): {} => ({})
};
}
},
// ... Score effects similar
];
}
The overlay dynamically calculates the position and props for each effect on every frame. For score effects, it uses the verticalOffset from ScoreEffectData to create an upward floating animation.
Sources: src/overlays/Effects.ts:36-37
Effect Types
Score Effect
A floating number that appears when the player scores points.
- Component:
ScoreEffectrenders text prefixed with a+.
Sources: src/components/ScoreEffect.ts - Data:
ScoreEffectDatamanages the effect's state.- It has a
maxAgeof 500ms. - The
verticalOffsetgetter calculates the upward movement using an easing function (eases.quadOut), creating a smooth acceleration effect.
Sources: src/store/effects/ScoreEffectData.ts:6, 28-30
- It has a
This diagram shows the relationship between the data and component for a score effect.
Smoke Effect
An animated puff of smoke that appears when a rabbit is shot.
- Component:
Smokeis anAnimatedSpritethat plays a sequence of frames from a single sprite sheet.
Sources: src/components/Smoke.ts - Data: It uses the generic
EffectDataclass, which manages its position and lifetime.
Sources: src/store/EffectsStore.ts:15, src/store/effects/EffectData.ts
The smoke effect is triggered by the CharacterContainer when a bullet hits a movable object (a rabbit).
Sources: src/components/CharacterContainer.ts:192-194
Game Over Effect
A screen transition that plays when the game ends. This is a special effect managed directly within EffectsStore and rendered by GameOverEffect.
- Trigger:
Game.tsdetects the game-over condition (0 friendly plants) and callseffectsStore.showGameOverAnimation().
Sources: src/Game.ts:98-111 - State: The
gameOverobject inEffectsStoretracks if the animation isactive, itstimer, and thecentercoordinates for the animation's origin.
Sources: src/store/EffectsStore.ts:17-21 - Animation Logic: The
endAnimationProgressgetter inEffectsStorecalculates the progress of the transition (a value from 0 to 1) using multipleeasesfunctions (expoOut,expoInOut) to create a complex, multi-stage animation (fast start, pause, fast end).
Sources: src/store/EffectsStore.ts:113-133
Summary
The Visual Effects System is a well-structured module that handles the lifecycle and rendering of temporary visual feedback. By centralizing state in EffectsStore and separating rendering into the Effects overlay, the system remains organized and easy to extend with new effect types. Its use of data-driven components and easing functions allows for the creation of smooth, dynamic animations that contribute significantly to the game's polished feel.