Navigation

Details about the 3.18 Release and the changes to the Input API, with mouse wheel and multi-touch support.

Published on 11th June 2019

Welcome to Dev Log 147. It's been a few weeks since writing one of these, so there's quite a bit to catch up on. There may have been no dev log published, but that doesn't mean for a second that I've been resting. Far from it, in fact.

3.18 Beta 1

The 3.18 release of Phaser is nearly ready. I've been working solidly on it since 3.17 dropped because a few annoying issues wormed their way into 3.17 that needed addressing quickly. I'll talk in more detail about what 3.18 changes, but first, if you want to test it out right now then head on over to npm and grab it. You'll find it under the beta tag.

Rewriting the Input API

The biggest change in 3.18 is that I have completed the work I started on the Input API back in 3.16. Prior to this, input worked on an event queue and native DOM events would be placed into the queue, waiting for the next game step to be processed. While this worked well and kept things consistent, it also meant we had to hack our way around browser security issues (with code not running in native DOM callback handlers, i.e. opening a new browser window from a Phaser input event), and it also meant there was a delay between the DOM event happening and it being processed. It wasn't a long delay, usually, but in games, every ms counts.

So, in 3.16 I started removing this event queue and introducing an immediate mode. Where-by the DOM events filtered directly through to their Phaser callbacks without any queue. In 3.17 this was refined a little further, but still, both systems were in place, living and arguing together inside the API like two siblings.

In 3.18 the work has been completed. I've removed entirely the old 'queue' system and all associated switches and flags. Doing this has meant the removal of a huge chunk of code from the input API, which is always good. And more important, it has meant I've been able to streamline the process a lot. There are now far less jumps between the native DOM event coming in and it reaching your Phaser Game Objects, making it faster and more responsive.

This means a large number of internal API changes in 3.18. On the surface, the public API hasn't altered all that much, but if you author plugins that use the input system then you should take time going over the Change Log to see exactly what has changed, as I always list both internal and public API changes in there.

As well as streamlining the input API internals it also meant I could drop in some new features. Here are a few of them.

Mouse Wheel Support

Starting in 3.18 you can now listen for Wheel events coming from the mouse, or similar input pointer. They can be extremely handy for in-game UIs, such as scrolling content in text windows, or offering a zoom control in an RTS game.

As with most input events, there are three different ways to consume the new event.

The first is POINTER_WHEEL, which is dispatched on a global level from the Input Plugin itself. This is handy if you're using the wheel to scroll a backdrop or camera, such as in the example below:

image

image

The second event is GAMEOBJECT_WHEEL. This event is again dispatched by the Input Plugin, but only if the wheel event occurs over an interactive Game Object. It's not picky about which object that is, so long as it's interactive and in the current Scene.

The final event is GAMEOBJECT_POINTER_WHEEL which is dispatched by the Game Object itself. This is the event you want to use if you wish to listen for wheel actions taking place over a specific Game Object, such as in the example below:

image

image

When a wheel event is dispatched it will send the delta values created by the native DOM event to your handler. You'll get the x, y, and z delta values, so you can react based on horizontal, vertical or Z-axis movement accordingly. It's worth noting that different input devices, OSs and browsers can give you different results inside of these values, so if you're going to use the wheel, test, test and test your game!

Window Events

A few versions ago the input API changed so that Phaser now listens for DOM events on the browsers window object, as well as on the canvas. There is a very good reason for this, but it also has some side-effects that you should be aware of, along with a way to disable it from happening.

One of the biggest issues I kept seeing reported over and over was with the Input API getting 'stuck' because the user had moused-down inside the canvas, then moved the mouse outside of the canvas and then released it. Perhaps on purpose to try and click something else on the page, or maybe because the game was a fast and vigorous one, and they didn't even realize they'd done it. Whatever the reason, it happened often, and when it happened the pointer that was currently 'down' within Phaser kept on thinking it was down. This didn't get reset until the player then moused back over the game again, and clicked once more, resetting the points state.

The opposite was also true. If the player was to mouse down outside of the canvas, and then move over it, the Phaser pointer would assume it was in an 'up' state, forcing the user to have to release the pointer and click again to put it back in sync again.

Although Phaser was technically doing nothing wrong, it still felt wrong to the end user, hence the issues and bug reports being filed. The reason it happened is that Phaser only listened for DOM events on the canvas object itself.

To combat this issue Phaser now listens for input events both on the canvas and on the window. If you mouse-up while outside of the canvas, Phaser now knows about this and reflects the change instantly in the Phaser Pointer. The opposite works as well. In the window handler Phaser would never call preventDefault on the event, it would only listen to it, meaning it would still happily trigger for any normal DOM elements on the page, so it wasn't an invasive action. All in all, it now feels right and does what you'd expect a game to do.

Of course, though, one-shoe never fits all. While in most cases this behavior is exactly what you'd expect and want your game to do, there is a use-case where it causes a problem and this occurs when you have DOM Elements positioned over the top of your game canvas. In this situation, the window listener would fire when you interact with the DOM element, and because it's over the canvas, it would potentially cause a mouse down event within your game too.

In this specific situation it may be beneficial to disable the window listeners entirely, which you can easily do via your game config with this simple flag:

image

Voila! Phaser will no longer listen for window events at all. You could also add this flag to save on some additional processing, if your game runs full-screen and fills the entire browser window, i.e. when there is no other 'window' space for an event to even occur on. Mostly though, you'll want it left on, which is why it's enabled by default.

Full Multi-Touch Support

Another nice side-effect of dropping the old queue event system is that 3.18 now handles multi-touch events fully. Previously, you may have noticed that things like the 'over' and 'out' events only worked for the first finger down in a multi-touch game, and additional active touch pointers were ignored. This has all changed and now any pointer, from any finger, no matter how many others are pressed down, dispatches all the same events as any other.

This means you can happily have all fingers dragging Game Objects around, or drawing in a multi-touch paint app, or tapping away furiously, with no limitations any longer (beyond the number of fingers you physically posses!). If you're on a touch-device, try the following touch demo out:

image

It may not be the grandest of pianos ever, but hopefully, you can still hear the results of proper multi-touch over support!

There's still some more work to be done on 3.18, specifically a few more input api updates (such as the rightButton handling) and finishing off the Spine plugin. Even with those needing to be done, I'm still confident we can release within a week and then set my sights on 3.19.

image

The June Code Bundle is now out for everyone who supports Phaser on Patreon or via PayPal. This month the bundle includes:

  • 13 new shaders for use in your games (these are all bundled into the single 'shader bundle' example.
  • 2 really nice shader mask effects (swirl and wave), both of which can work on any image and are easy to edit the glsl source for too.
  • A fun little tween effect I call the Jelly Tween. By just tweaking the scale and position of an object you can make it look like it's stretchy gum or dancing :)
  • The Toaster is a demo of using two tightly strung matter constraints to hold a body in place and what happens if you then destroy one of them!
  • The Bow and Arrow examples are 3 examples that show the evolution of a bow and arrow physics game. In the first iteration, you can click and drag back on the bow, with the bow rotating to the mouse and the drawstring pulling back realistically. All the bow data is exposed and then used in the second example, which creates an arrow-shaped matter body and launches it. Wind friction is applied to the arrow in order to keep the flight realistic (within reason!) and you can stick the arrow into the ground. In the final version targets are added and you can shoot arrows into them at will :) The code includes showing how to detect which side of the target is hit, how to not allow the arrow to stick should the angle or speed not be right and this could easily be evolved into a full game.
  • The final example is Bank Panic - which is actually complete game. You'll see I split the code up into different Scenes, rather than lumping it all together, so you can work through it more easily and see how Boot leads onto Preloader and so on. The game is a classic one: shoot the bandits, not the civilians, as they try to rob the bank! There are even amusing sound effects to go with it all :) Look through the source code to see how it all works, I leave comments in all over the place and use properties and method names that should be easy to digest.