So I wrote my own Virtual Joystick Plugin for the HTML5 game engine Phaser. That may sound stupid now, but at that time @photostorm didn’t release his official plugin yet. Still, it’s a $20 value there.
So I needed a Virtual Joystick plugin (kinda) a few weeks ago. I found phaser-touch-control-plugin, but I want the joystick to stay in one place on the screen. So I wrote my own Virtual Joystick Plugin. That may sound stupid now, but at that time @photostorm didn’t release his official plugin yet.
Let’s start with a quick demonstration.
Design
- A background for the joystick (the grey box) to show the players where to put their finger.
class Joystick extends Phaser.Sprite { constructor(x, y) { super(game, 0, 0, 'background'); this.anchor.setTo(0.5, 0.5); } }
- A draggable sprite for the pin (the red box) which players can, duh, drag. Here,
pin.input.enableDrag
is called with first paramtrue
so that the pin is always centered at your finger tip.constructor(x, y) { ... let pin = game.add.sprite(0, 0, 'pin'); pin.anchor.setTo(0.5, 0.5); pin.inputEnabled = true; pin.input.enableDrag(true); this.addChild(pin); this.pin = pin; }
- Event
onDragStop
: The pin returns to the center of the background.constructor(x, y) { ... pin.events.onDragStop.add(this.onDragStop, this); ... } onDragStop(){ this.pin.position.setTo(0, 0); }
- A restriction
maxDistance
to prevent the pin from going outside of the background (like in the picture below). If the background is a circle, this is normally the radius, meaning half of the background image width. The check happens at eventonDragUpdate
.constructor(x, y) { ... this.maxDistance = this.width/2; pin.events.onDragUpdate.add(this.onDragUpdate, this); ... } onDragUpdate(){ let {pin, maxDistance} = this; var distance = pin.getMagnitude(); if (distance > maxDistance) { pin.setMagnitude(maxDistance); } }
There are two problems:
- Event
onDragUpdate
: ifdistance
is larger thanmaxDistance
, the pin position is changed and not at player finger anymore. - In other game, players can start dragging from anywhere on the background of the joystick and the pin jumps at it immediately. Here, players have to actually start dragging at the pin position.
To solve this, I added a transparent layer to act as the draggable, and use the pin only for indication of position.
- Add a transparent
dragger
and movedragging
events todragger
constructor(x, y) { ... let dragger = this.dragger = game.add.sprite(0, 0, null); dragger.anchor.setTo(0.5, 0.5); dragger.width = dragger.height = this.width; dragger.inputEnabled = true; dragger.input.enableDrag(true); this.addChild(dragger); dragger.events.onDragStop.add(this.onDragStop, this); dragger.events.onDragUpdate.add(this.onDragUpdate, this); } onDragStop(){ this.dragger.position.setTo(0, 0); this.pin.position.setTo(0, 0); }
- The pin’s position then would be set based on the dragger’s position and
maxDistance
.onDragUpdate(){ let {pin, dragger, maxDistance} = this; var distance = dragger.getMagnitude(); pin.position.copyFrom(dragger); if (distance > maxDistance) { pin.setMagnitude(maxDistance); } }
Check out the full source code on this gist, and see this Virtual Joystick in action.