Advanced Usage
Advanced Usage
Section titled “Advanced Usage”Learn advanced patterns and techniques for using Phaser Virtual Joystick in your games.
Multiple Joysticks
Section titled “Multiple Joysticks”You can create multiple joysticks for different purposes:
export class GameScene extends Phaser.Scene { private movementJoystick!: VirtualJoystick; private aimJoystick!: VirtualJoystick;
create() { // Movement joystick (left side) this.movementJoystick = new VirtualJoystick({ scene: this, bounds: { topLeft: { x: 0, y: 0 }, bottomRight: { x: this.cameras.main.width / 2, y: this.cameras.main.height } }, stick: { fillColor: 0x4ECDC4, // Teal radius: 35 } });
// Aim joystick (right side) this.aimJoystick = new VirtualJoystick({ scene: this, bounds: { topLeft: { x: this.cameras.main.width / 2, y: 0 }, bottomRight: { x: this.cameras.main.width, y: this.cameras.main.height } }, stick: { fillColor: 0xFF6B6B, // Red for aiming radius: 30 } });
this.add.existing(this.movementJoystick); this.add.existing(this.aimJoystick);
// Handle movement this.movementJoystick.on('move', (data) => { this.player.setVelocity(data.x * 200, data.y * 200); });
// Handle aiming this.aimJoystick.on('move', (data) => { this.aimWeapon(data.x, data.y); }); }
private aimWeapon(x: number, y: number) { const angle = Math.atan2(y, x); this.weapon.setRotation(angle); }}Custom Styling Themes
Section titled “Custom Styling Themes”Create different visual themes for your joysticks:
Neon Theme
Section titled “Neon Theme”const neonJoystick = new VirtualJoystick({ scene: this, deadZone: { fillColor: 0x00FF00, strokeColor: 0x00CC00, alpha: 0.3 }, baseArea: { fillColor: 0x00FF00, alpha: 0.1, strokeColor: 0x00CC00 }, stick: { fillColor: 0x00FF00, strokeColor: 0x00CC00, alpha: 0.9 }});Dark Theme
Section titled “Dark Theme”const darkJoystick = new VirtualJoystick({ scene: this, deadZone: { fillColor: 0x333333, strokeColor: 0x666666, alpha: 0.2 }, baseArea: { fillColor: 0x333333, alpha: 0.2, strokeColor: 0x666666 }, stick: { fillColor: 0x666666, strokeColor: 0x999999, alpha: 0.8 }});Minimal Theme
Section titled “Minimal Theme”const minimalJoystick = new VirtualJoystick({ scene: this, deadZone: { alpha: 0 }, baseArea: { alpha: 0.05, strokeWidth: 1, strokeColor: 0xFFFFFF }, stick: { fillColor: 0xFFFFFF, strokeWidth: 1, alpha: 0.8 }});Joystick with Custom Icon
Section titled “Joystick with Custom Icon”Add custom icons to your joystick:
export class GameScene extends Phaser.Scene { create() { // Create custom icon const stickIcon = this.add.text(0, 0, '🎮', { fontSize: '24px', color: '#ffffff' });
const joystick = new VirtualJoystick({ scene: this, stickIcon: stickIcon, stick: { fillColor: 0x4ECDC4, radius: 35 } });
this.add.existing(joystick); }}Dynamic Joystick Positioning
Section titled “Dynamic Joystick Positioning”Position the joystick where the user first touches:
export class GameScene extends Phaser.Scene { private joystick!: VirtualJoystick; private isJoystickActive = false;
create() { // Create joystick with custom bounds this.joystick = new VirtualJoystick({ scene: this, bounds: { topLeft: { x: 0, y: 0 }, bottomRight: { x: this.cameras.main.width, y: this.cameras.main.height } } });
this.add.existing(this.joystick);
// Handle touch events this.input.on('pointerdown', (pointer) => { if (!this.isJoystickActive) { this.isJoystickActive = true; // Joystick will appear at touch point } });
this.joystick.on('release', () => { this.isJoystickActive = false; }); }}Smooth Movement with Acceleration
Section titled “Smooth Movement with Acceleration”Add acceleration and deceleration for smoother movement:
export class GameScene extends Phaser.Scene { private joystick!: VirtualJoystick; private player!: Phaser.Physics.Arcade.Sprite; private targetVelocity = { x: 0, y: 0 }; private acceleration = 0.1; private maxSpeed = 200;
create() { this.player = this.physics.add.sprite(400, 300, 'player');
this.joystick = new VirtualJoystick({ scene: this });
this.add.existing(this.joystick);
this.joystick.on('move', (data) => { this.targetVelocity.x = data.x * this.maxSpeed; this.targetVelocity.y = data.y * this.maxSpeed; });
this.joystick.on('release', () => { this.targetVelocity.x = 0; this.targetVelocity.y = 0; }); }
update() { // Update joystick (required for smooth following behavior) this.joystick?.update();
// Smooth acceleration towards target velocity const currentVel = this.player.body.velocity;
this.player.setVelocity( currentVel.x + (this.targetVelocity.x - currentVel.x) * this.acceleration, currentVel.y + (this.targetVelocity.y - currentVel.y) * this.acceleration ); }}Joystick with Visual Feedback
Section titled “Joystick with Visual Feedback”Add visual feedback based on joystick input:
export class GameScene extends Phaser.Scene { private joystick!: VirtualJoystick; private player!: Phaser.Physics.Arcade.Sprite; private trail!: Phaser.GameObjects.Graphics;
create() { this.player = this.physics.add.sprite(400, 300, 'player');
// Create trail effect this.trail = this.add.graphics();
this.joystick = new VirtualJoystick({ scene: this });
this.add.existing(this.joystick);
this.joystick.on('move', (data) => { // Move player this.player.setVelocity(data.x * 200, data.y * 200);
// Update trail this.updateTrail(data); });
this.joystick.on('release', () => { this.player.setVelocity(0, 0); this.trail.clear(); }); }
private updateTrail(data: { x: number, y: number }) { this.trail.clear();
// Draw trail based on joystick intensity const intensity = Math.sqrt(data.x * data.x + data.y * data.y); const alpha = intensity * 0.5;
this.trail.fillStyle(0x00ff00, alpha); this.trail.fillCircle( this.player.x + data.x * 20, this.player.y + data.y * 20, 5 ); }}Joystick with Haptic Feedback
Section titled “Joystick with Haptic Feedback”Add haptic feedback for better mobile experience:
export class GameScene extends Phaser.Scene { private joystick!: VirtualJoystick; private lastHapticTime = 0;
create() { this.joystick = new VirtualJoystick({ scene: this });
this.add.existing(this.joystick);
this.joystick.on('press', () => { this.triggerHaptic('light'); });
this.joystick.on('move', (data) => { const magnitude = Math.sqrt(data.x * data.x + data.y * data.y);
// Trigger haptic feedback based on movement intensity if (magnitude > 0.8 && Date.now() - this.lastHapticTime > 100) { this.triggerHaptic('medium'); this.lastHapticTime = Date.now(); } });
this.joystick.on('release', () => { this.triggerHaptic('light'); }); }
private triggerHaptic(type: 'light' | 'medium' | 'heavy') { if ('vibrate' in navigator) { const patterns = { light: [10], medium: [20], heavy: [30] };
navigator.vibrate(patterns[type]); } }}Desktop Testing
Section titled “Desktop Testing”Enable joystick on desktop for testing:
const joystick = new VirtualJoystick({ scene: this, enableWithoutTouch: true // Allows mouse interaction on desktop});Performance Optimization
Section titled “Performance Optimization”Optimize joystick performance for better frame rates:
export class GameScene extends Phaser.Scene { private joystick!: VirtualJoystick; private updateThrottle = 0; private throttleRate = 16; // ~60fps
create() { this.joystick = new VirtualJoystick({ scene: this });
this.add.existing(this.joystick);
// Throttle updates for better performance this.joystick.on('move', (data) => { this.updateThrottle++; if (this.updateThrottle % 2 === 0) { // Update every other frame this.handleMovement(data); } }); }
update() { // Always call update for smooth following behavior this.joystick?.update(); }
private handleMovement(data: { x: number, y: number }) { // Your movement logic here this.player.setVelocity(data.x * 200, data.y * 200); }}Best Practices
Section titled “Best Practices”- Always call update(): Call
joystick.update()in your scene’s update method - Add to scene: Always call
this.add.existing(joystick)after creating - Use bounds: Define custom activation areas for better control
- Test on devices: Always test on actual mobile devices
- Consider haptics: Add haptic feedback for better UX
- Visual feedback: Use custom styling to show joystick state
- Multiple joysticks: Use separate joysticks for different actions
- Clean up: Destroy joysticks when changing scenes
- Custom icons: Add visual elements to make joysticks more intuitive
- Performance: Throttle updates if needed for better performance