Pausing / Resuming Your App
The dill pixel framework provides robust pause and resume functionality through the application instance. This allows you to control various aspects of your game’s state, including audio playback, animations, timers, and the game loop.
Basic Usage
The simplest way to pause and resume your game is to use the pause()
and resume()
methods:
// Pause the gamethis.app.pause();
// Resume the gamethis.app.resume();
// Toggle pause statethis.app.togglePause();
// Check if game is pausedif (this.app.paused) { // Game is paused}
Configuring Pause Behavior
You can customize what gets paused by passing a configuration object to the pause()
method. The configuration supports the following options:
interface PauseConfig { pauseAudio: boolean; // Pause all audio playback pauseAnimations: boolean; // Pause GSAP animations pauseTicker: boolean; // Pause the game loop/ticker pauseTimers: boolean; // Pause all game timers}
Examples
Here are some common pause configurations:
// Pause everythingthis.app.pause({ pauseAudio: true, pauseAnimations: true, pauseTicker: true, pauseTimers: true,});
// Pause only audio and animations (game loop continues)this.app.pause({ pauseAudio: true, pauseAnimations: true, pauseTicker: false, pauseTimers: false,});
// Pause only the game loopthis.app.pause({ pauseAudio: false, pauseAnimations: false, pauseTicker: true, pauseTimers: false,});
Default Behavior
If no configuration is provided, the default behavior is:
const defaultPauseConfig = { pauseAudio: false, pauseAnimations: false, pauseTicker: false, pauseTimers: false,};
Listening for Pause Events
You can listen for pause and resume events using the application’s signals:
// Listen for pause eventsthis.app.onPause.connect((config) => { console.log('Game paused with config:', config); // Handle pause});
// Listen for resume eventsthis.app.onResume.connect((config) => { console.log('Game resumed from config:', config); // Handle resume});
Document Visibility Handling
The framework automatically handles document visibility changes (when the user switches tabs or minimizes the window). By default:
-
When the document becomes hidden:
- Audio is suspended
- All timers are paused
-
When the document becomes visible:
- Audio is restored
- All timers are resumed
This behavior is handled through the WebEvents plugin and can be observed in your code:
// Listen for visibility changesthis.app.webEvents.onVisibilityChanged.connect((isVisible) => { if (isVisible) { // Document is visible console.log('Game window is visible'); } else { // Document is hidden console.log('Game window is hidden'); }});
Best Practices
-
Consistent State Management: When pausing, ensure all game systems are in a consistent state. This might include:
- Disabling user input
- Showing a pause menu
- Saving the current game state
-
Selective Pausing: Consider what should and shouldn’t be paused. For example:
- Background music might continue during pause
- UI animations might still run
- Particle effects might freeze
-
Resume Handling: When resuming, make sure to:
- Restore the correct game state
- Re-enable user input
- Hide pause UI
- Resume from the correct point in time
Example Implementation
Here’s a complete example of implementing a pause system:
import { Scene } from 'dill-pixel';class GameScene extends Scene { private isPauseMenuVisible = false;
constructor() { super();
// Listen for ESC key to toggle pause this.app.keyboard.onKeyDown('Escape').connect(this.togglePause); }
private togglePause = () => { if (this.app.paused) { this.resumeGame(); } else { this.pauseGame(); } };
private pauseGame() { // Pause game systems this.app.pause({ pauseAudio: true, pauseAnimations: true, pauseTicker: true, pauseTimers: true, });
// Show pause menu this.showPauseMenu(); }
private resumeGame() { // Hide pause menu first this.hidePauseMenu();
// Resume game systems this.app.resume(); }
private showPauseMenu() { this.isPauseMenuVisible = true; // Implement your pause menu display logic }
private hidePauseMenu() { this.isPauseMenuVisible = false; // Implement your pause menu hide logic }}
Practical Examples
Let’s look at some practical scenarios and how different pause configurations affect game elements:
Scenario: Manually Pause your Scene’s update loop:
When pauseTicker
is true, the game loop will pause:
class GameScene extends Scene { initialize() { // listen for the pause events this.addSignalConnection(this.app.onPause.connect(this._onPause), this.app.onResume.connect(this._onResume));
setTimeout(() => { this._pause(); }, 5000); }
update() { // check if the game is paused if (this.app.paused) { return; } // Your update logic here (this will not run if the game is paused) }
private _pause() { // call pause method with no config to pause the game, and control the pause state from the scene this.app.pause();
setTimeout(() => { this._resume(); }, 5000); }
private _resume() { this.app.resume(); }
private _onPause() { console.log('Game paused'); }
private _onResume() { console.log('Game resumed'); }}
Scenario: GSAP Animations
When pauseAnimations
is true, GSAP animations like this will pause:
// GSAP animation that will pause when pauseAnimations is truegsap.to(sprite.pivot, { x: 200, duration: 1, ease: 'power2.inOut', yoyo: true, repeat: -1,});
// Pause configuration that will stop the animationthis.app.pause({ pauseAnimations: true, pauseAudio: false, pauseTicker: false, pauseTimers: false,});
Scenario: Ticker-Based Animations
When pauseTicker
is true, any animations using Pixi’s ticker will pause:
class GameScene extends Scene { private sprite: Sprite; private direction = 1;
update() { // This animation will pause when pauseTicker is true this.sprite.x += 5 * this.direction; if (this.sprite.x >= 500) { this.direction = -1; } else if (this.sprite.x <= 0) { this.direction = 1; } }}
// Pause configuration that will stop ticker-based animationsthis.app.pause({ pauseTicker: true, pauseAnimations: false, pauseAudio: false, pauseTimers: false,});
Scenario: Timers and Audio
When using timers and audio together, you might want to pause both:
class GameScene extends Scene { initialize() { // Create a countdown timer const countdown = this.app.timers.createTimer({ duration: 5000, // 5 seconds autoStart: true, useWorker: true, loop: true, onTick: (remaining) => { this.updateCountdown(remaining); }, });
// Play background music await this.app.audio.play('backgroundMusic', 'music', { singleInstance: true, loop: true, }); }
// Pause both timers and audio pauseGameAndAudio() { this.app.pause({ pauseTimers: true, pauseAudio: true, pauseAnimations: false, pauseTicker: false, }); }}
Tips for Different Game Types
-
Action Games
// Pause everything for action games where timing is criticalthis.app.pause({pauseAudio: true,pauseAnimations: true,pauseTicker: true,pauseTimers: true,}); -
Puzzle Games
// Maybe keep animations running but pause timers and gameplaythis.app.pause({pauseAudio: false, // Keep background musicpauseAnimations: false, // Keep UI animationspauseTicker: true, // Pause gameplaypauseTimers: true, // Pause level timer}); -
Menu Screens
// Pause gameplay but keep UI responsivethis.app.pause({pauseAudio: false,pauseAnimations: true,pauseTicker: false,pauseTimers: true,});
Remember to always consider the user experience when choosing what to pause. For example, you might want to keep UI animations running during pause to maintain responsiveness, while pausing gameplay elements to prevent any game state changes.