@dreams-engine/slot
v1.0.2
Published
This package provides a powerful, configuration-driven slot engine for PixiJS. It includes a central `SlotMachine` orchestrator that manages reels, symbols, and the complete spin lifecycle, as well as the underlying systems for creating flexible reels and
Downloads
409
Readme
@dreams-engine/slot
This package provides a powerful, configuration-driven slot engine for PixiJS. It includes a central SlotMachine orchestrator that manages reels, symbols, and the complete spin lifecycle, as well as the underlying systems for creating flexible reels and data-driven symbols.
Key Features
- Configuration-Driven: Define complex machines with a single options object.
- Powerful Orchestration: The central
SlotMachineclass manages the entire game flow. - Flexible Layouts: Automatic horizontal/vertical layouts with spacing, or full manual control.
- Advanced Sequence Control: Fine-tune the timing and order of reel spins and stops for game feel.
- Dynamic Reels: Add or remove reels at runtime.
- Efficient: Uses a shared object pool for symbols to optimize performance.
- Extensible: Comes with built-in spin behaviors (
strip,fall) and symbol types, all of which can be extended.
Installation
npm i @dreams-engine/slotThe SlotMachine Orchestrator
The SlotMachine class is the primary entry point and central controller for the slot engine. It is a non-visual orchestrator that reads a configuration to build and manage a collection of IReel instances.
Quick Start
Here is a basic example of how to create a 5-reel slot machine.
import { SlotMachine, MachineOptions } from '@dreams-engine/slot';
import { Application, Assets } from 'pixi.js';
// Assuming 'app' is your PIXI.Application and assets are loaded
const app = new Application();
// 1. Define the machine configuration
const machineOptions: MachineOptions = {
visibleCount: 4,
cellWidth: 205,
cellHeight: 185,
symbolConfig: Assets.get('symbol-def'), // Master configuration for all symbol types
useMachineMask: true,
machineContainerOptions: { x: 100, y: 100 },
layout: { type: 'auto', align: 'horizontal', spacing: 10 },
reels: [
{
count: 5, // Create 5 identical reels
direction: 'down',
spinBehavior: { type: 'strip', options: { /* ... */ }},
}
],
initialSymbols: [ /* ... 2D array of initial symbols ... */ ],
startSequence: { delay: 0.25 },
stopSequence: { delay: 0.5 },
};
// 2. Create the SlotMachine instance
const slotMachine = new SlotMachine(app, machineOptions);
// 3. Add the machine's container to the stage
app.stage.addChild(slotMachine.container);
// 4. Listen for when the spin is fully complete
slotMachine.on('machineallreelsstopped', () => {
console.log('All reels have stopped! Machine is idle.');
});
// 5. Start a spin!
if (slotMachine.isIdle) {
slotMachine.start({ speed: 1 });
// After a delay (e.g., getting a response from a server)
// provide the landing symbols to stop the machine.
setTimeout(() => {
const landingSymbols = [ /* ... 2D array of final symbols ... */ ];
slotMachine.stop({ landingSymbols });
}, 2000);
}Configuration (MachineOptions)
The machine is configured via the MachineOptions object. Below are the key properties:
| Property | Type | Description |
| ------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| reels | ReelMachineConfig[] | Required. Defines the configuration for the reels to be created. Use count to create multiple reels from one definition. |
| symbolConfig | { [id: string]: SymbolOptions } | Required. A master map defining the properties and visuals for every symbol type the machine can display. |
| layout | LayoutOptions | Defines the positioning strategy. type: 'auto' arranges reels in a line with spacing. type: 'manual' defers to each reel's x/y. |
| initialSymbols | string[][] | A 2D array of symbol IDs to display when the machine is first created. |
| startSequence/stopSequence | SequenceOptions | Fine-tune the spin/stop process by defining the order of reels and the delay (in seconds) between each action. |
| machineContainerOptions | ContainerOptions | PIXI ContainerOptions for the main container that holds all the reels. Use this to position the entire machine on the stage. |
| useMachineMask | boolean | If true, creates a single, optimized mask for the entire machine's visible area. Defaults to true. |
| ... | Partial<ReelOptions> | Top-level options in MachineOptions (e.g., visibleCount, cellWidth) act as defaults for all reels defined in the reels array. |
API & Events
The SlotMachine class provides a simple API to control the game flow and emits events for key lifecycle moments.
Core Methods
start(config: SpinConfig): Starts the spin sequence.stop(config: StopConfig): Provides landing symbols and starts the stop sequence.forceStop(): Immediately stops all reels, bypassing any delays.
Key Events
on('machinespinstart', () => { ... }): Fired when the machine begins to spin.on('machineallreelsstopped', () => { ... }): Fired when all reels have stopped and the machine is idle. This is the primary event for knowing when a spin cycle is complete.on('machinereelstopped', (reel) => { ... }): Fired each time an individual reel comes to a stop.
Underlying Systems
The SlotMachine orchestrator is built upon several powerful, modular systems that can also be understood independently.
Slot Symbol System
This package provides a flexible, data-driven system for creating and managing symbols in a slot game. It's built on Pixi.js and designed to be easily extensible.
Overview
The Slot Symbol system is designed to decouple a symbol's data and state logic from its visual representation. This is achieved through two main components:
SlotSymbol: The core class that represents a symbol. It manages the symbol's state, properties (like ID, payouts, wild/scatter status), and animations. It acts as aPIXI.Container.- Visuals (
ISymbolVisual): These are the rendering strategies for a symbol. ASlotSymboldelegates its visual representation to a separate class that handles the actual rendering (e.g., as a static sprite, an animated sprite, or a Spine animation).
This separation allows you to define a symbol's behavior and properties once and then easily switch its visual representation without changing the core logic.
Core Components
SlotSymbol
The SlotSymbol class is the heart of the system. It holds all the data for a symbol and controls its lifecycle.
- State Management: Manages the symbol's current state (e.g.,
idle,win,blur). You can change the state by callingsymbol.setState('win'). - Animation & Sound: When the state changes, it automatically triggers the corresponding animation and sound effect as defined in the symbol's configuration.
- Data-Driven: All properties of a symbol, such as its name, payouts, and whether it's a wild or scatter, are loaded from a configuration object.
- Event-Driven: Emits events for key moments, such as
animation_startandanimation_complete.
Chain Animations
The SlotSymbol class now supports playing a sequence of animations one after another, often referred to as "chain animations". This is useful for creating complex visual effects that involve multiple distinct animation segments.
playChainAnim(animNames: SymbolState[], onComplete?: () => void): Plays a series of animations in the order they are provided in theanimNamesarray. TheonCompletecallback is triggered only after all animations in the chain have finished.stopChainAnim(): Immediately stops the currently playing animation within a chain and prevents any subsequent animations in that chain from starting.
Visuals & VisualFactory
A symbol's appearance is handled by a "visual" class that implements the ISymbolVisual interface. This interface ensures that all visual types have a common API for playing animations, applying filters, and handling destruction.
The system includes several built-in visual types:
SpriteVisual: For static images.AnimatedSpriteVisual: For spritesheet animations.TextVisual: For standard text.BitmapTextVisual: For bitmap fonts.SpineVisual: For Spine skeletal animations.
The createVisual factory function is responsible for creating the correct visual instance based on the configuration provided for a symbol.
Configuration (SymbolOptions)
The entire system is driven by a SymbolOptions configuration object. This object defines everything about a symbol.
Here is an example of a SymbolOptions object:
import { SymbolOptions } from './src/symbol/types';
const cherrySymbolOptions: SymbolOptions = {
// Core Properties
id: 'SYM_CHERRY',
symName: 'Cherry',
payouts: { '3': 10, '4': 50, '5': 200 },
isWild: false,
isScatter: false,
// Visual Configuration
visualOptions: {
type: 'sprite', // 'sprite', 'animatedSprite', 'spine', etc.
texture: 'cherry.png' // Asset key for the texture
},
// Animation Mapping
anims: {
'win': 'cherry-win-effect', // Map 'win' state to this animation name
'land': 'cherry-land-bounce'
},
// Sound Effect Mapping
sfx: {
'win': 'sfx_cherry_win', // Map 'win' state to this sound alias
'land': 'sfx_symbol_land'
},
// Interactivity
interactive: true
};Usage Example
Here’s how you might create and use a SlotSymbol instance.
import { SlotSymbol } from './src/symbol/SlotSymbol';
import { Application } from 'pixi.js';
// Assume `app` is your Pixi Application and `options` is a valid SymbolOptions object.
const app = new Application();
const options = { /* ... your symbol options ... */ };
// 1. Create the symbol instance
const symbol = new SlotSymbol(app, options);
// 2. Add it to the stage
app.stage.addChild(symbol);
// 3. Change its state to play a "win" animation
symbol.setState('win');
// After the "win" animation (if not looping), it will automatically revert to 'idle'.
// 4. Reset the symbol to its initial state
symbol.reset();Slot Reel System
This package also includes a powerful and flexible system for creating and managing slot reels.
Purpose
The main goal of this module is to create a flexible and extensible slot reel system. This system is designed to be easily configurable with different spin behaviors and to meet the requirements of modern slot games.
Key Features
Spin Behaviors: Determine the animation and logic of the reel's spin. This project includes two basic spin behaviors:
StripSpinBehavior: Provides an animation where the symbols rotate on a strip, as in traditional slot machines. For performance, it creates and uses symbol strips as textures.FallSpinBehavior: Provides an animation where the symbols fall from top to bottom. This is a common feature in modern slot games, also known as "cascading" or "tumbling" reels.
direction: TheBaseReelclass has adirectionproperty that can be set toup,down,left, orright. This allows the reel to spin in any direction, providing more flexibility for game design.shuffle: Theshuffleproperty is a boolean that, when set totrue, shuffles thereelSetListbefore each spin. This is useful for games where the order of symbols on the reel needs to be randomized.
These behaviors and features are created dynamically through the BehaviorFactory and configured in the BaseReel class. This makes it easy to add new spin behaviors or modify existing ones.
Core Components
BaseReel
The BaseReel class is the core of the reel system. It manages the symbols, their positions, and the overall state of the reel.
- State Management: Manages the reel's current state (e.g.,
spinning,stopping,idle). - Spin Control: Provides methods to
startSpin,stopSpin, andforceStopthe reel. - Symbol Management: Manages the list of symbols on the reel and uses an
ObjectPoolfor efficient symbol reuse. - Event-Driven: Emits events for key moments, such as
reelspinstart,reelstopcomplete, andreelsymbolsupdate.
Reel Behaviors (IReelBehavior)
A reel's spinning animation and logic are handled by a "behavior" class that implements the IReelBehavior interface. This allows for different types of reel animations to be easily swapped out.
The system includes two built-in behaviors:
StripSpinBehavior: Simulates a classic slot machine reel using a continuous strip of symbols.FallSpinBehavior: Makes the symbols fall from the top of the reel.
BehaviorFactory
The createBehavior factory function is responsible for creating the correct reel behavior instance based on the configuration provided for a reel.
Configuration (ReelOptions)
The entire reel system is driven by a ReelOptions configuration object. This object defines everything about a reel.
Here is an example of a ReelOptions object:
import { ReelOptions } from './src/reels/interfaces';
const reelOptions: ReelOptions = {
id: 0,
visibleCount: 3,
extraCount: 1,
cellWidth: 100,
cellHeight: 100,
reelSet: ['SYM_A', 'SYM_K', 'SYM_Q', 'SYM_J'],
spinBehavior: {
type: 'strip',
options: {
duration: 0.5,
ease: 'power2.inOut'
}
},
direction: 'down',
shuffle: true
};Usage Example
Here’s how you might create and use a BaseReel instance.
import { BaseReel } from './src/reels/BaseReel';
import { Application } from 'pixi.js';
import { ObjectPool } from './src/pool/ObjectPool';
import { SlotSymbol } from './src/symbol/SlotSymbol';
// Assume `app` is your Pixi Application and `reelOptions` is a valid ReelOptions object.
const app = new Application();
const symbolPool = new ObjectPool<SlotSymbol>(
(id, options) => new SlotSymbol(app, options)
);
// 1. Create the reel instance
const reel = new BaseReel(app, reelOptions, symbolPool);
// 2. Add the reel's container to the stage
app.stage.addChild(reel.container);
// 3. Start the spin
reel.startSpin({ speed: 2 });
// 4. Stop the spin with a specific set of landing symbols
reel.stopSpin({ landingSymbols: ['SYM_A', 'SYM_K', 'SYM_Q'] });Object Pool (ObjectPool.ts)
To optimize performance and reduce garbage collection, the package includes a generic ObjectPool. This can be used to recycle and reuse SlotSymbol instances (or any other object).
How It Works
get(id, ...args): Retrieves an inactive object from the pool. If no inactive objects are available, it creates a new one using the factory function provided during the pool's construction.return(id, object): Marks an object as inactive and returns it to the pool, making it available for reuse.
Usage Example
import { ObjectPool } from './src/pool/ObjectPool';
import { SlotSymbol } from './src/symbol/SlotSymbol';
import { Application } from 'pixi.js';
const app = new Application();
// 1. Create a pool for SlotSymbol objects
const symbolPool = new ObjectPool<SlotSymbol>(
(id, options) => new SlotSymbol(app, options)
);
// 2. Get a symbol from the pool
const symbol1 = symbolPool.get('SYM_A', { id: 'SYM_A', /* ... other options */ });
// 3. When you're done with the symbol, return it to the pool
symbolPool.return('SYM_A', symbol1);
// 4. The next time you get 'SYM_A', the pool will reuse the returned instance
const symbol2 = symbolPool.get('SYM_A', { id: 'SYM_A', /* ... other options */ });
console.log(symbol1 === symbol2); // trueBy using the ObjectPool, you can significantly improve the performance of your game, especially in scenarios where many symbols are created and destroyed rapidly, such as during reel spins.
