Due to the rapid pace of change some links or details may no longer be correct.
JSDocs, Tween Manager completed and Deferred Lighting.
It was yet another busy week of development on Phaser. It started out with me focusing on more feedback from the Alpha release. A few of you had spotted bugs that I fixed, which is always a nice feeling. I also spent a lot of time in the first few days experimenting with more ways of generating the Phaser 3 documentation. I tried all kinds of packages, lots of which didn't work, some of which worked in part but didn't give me the results I needed.
However, the parsing of the docs and generation of the resulting documentation is still undecided. I have some quite specific requirements from the v3 docs, which don't appear to be readily served by the packages out there. I need the docs to generate a single JSON file, which is something JSDoc can do. I need them to pull in external files written in markdown and merge those with the output, so I can include extended examples in the source without having to embed them all in the code files. I also want to be able to output the docs as single markdown files, one per class. Lots of the more modern packages appear to favor outputting just one single, massive, HTML or markdown file, that you jump around via anchors. This is no good to me due to the sheer scale of the Phaser 3 docs. I would also very much like the ability to output the docs into publishing ready formats like PDF or ePub. I need the doc generator to recognize only changed files, and not have to republish the whole lot again just because I edit one source file. Finally, I am pretty sure I'm going to need to have my own custom jsdoc tags to help define TypeScript definitions. Because there is no way we want to be doing this by hand again. I need to be able to generate the TS defs from source.
The conclusion I'm coming to is that no package out there provides all of this. I will spend a bit more time investigating but I'm not hopeful. It may well transpire that I need to create my own documentation generator. I can still use lots of the tools that already exist, like esprima, to do the grunt work, but I was really hoping there would be something I could use off the shelf. If you know of anything please drop me a line (firstname.lastname@example.org).
Tween Manager Completion
As well as docs I also spent the week completing the Tween Manager. This was a brand new system for Phaser 3. I had already worked on it a lot but the manager itself was missing some final features in order for me to be able to mark it off as 100% complete. I also created some performance tests for it. Literally throwing tens of thousands of tweens around and checking it didn't blow-up the profiler or leak memory anywhere.
Each Scene in your game has its own Tween Manager, and each Tween Manager has its own global time scale. By setting the time scale on a global basis all tweens being processed by the manager are scaled immediately. This allows you to create 'slow-mo' or 'speed-up' effects for a specific Scene, without impacting any other scene that may be running in parallel:
The above example has a bunch of independent tweens running, but all are impacted by the change in global time scale initiated by the buttons.
You can also change the timescale of an individual tween
Here we have a single tween updating 5 different sprites. The arrows control the time scale of the tween itself, allowing you to speed it up or slow it down. This example also demonstrates another new feature. The ability for a tween to flip a Game Object when it yo-yo's or repeats. If you look at the example you'll notice the fish flip horizontally as they reach the edge of the screen. This is caused by a new optional config setting:
If you set flipX (or flipY) in the config then it'll flip the sprite for you automatically. There are cases when you will need more complex logic that controls when a sprite flips or not, but for simple tweens like this one it works really well and avoids you having to define callbacks.
I've also implemented all of the tween callbacks. There are 6 in total covering the following events: onStart, onUpdate, onYoyo, onRepeat, onLoop and onComplete. These can be set either in the tween configuration or via the Tween.setCallback method. The Tween Manager uses callbacks rather than events because in all likely hood you are going to be creating hundreds of tweens that never need any kind of callback or event listener. Yet in an event based system, those events get dispatched anyway, regardless if there is anything listening to them or not. But with a callback, it is never invoked unless there is an active listener. So by using callbacks, we avoid un-necessary event creation and you get the same flexibility as before. It also keeps our tween system in-line with others like TweenMax. There are lots of callback examples in the labs if you'd like to take a look at how they are structured.
Tween Manager Helpers
I had a list of functions I wanted to add to the Tween Manager before I would be happy it had all that was needed, and these are now in place. The new features are all to do with tween inspection and control and include:
▪ getAllTweens ▪ getTweensOf ▪ isTweening ▪ killAll ▪ killTweensOf ▪ pauseAll ▪ resumeAllLots of the above take either a single Game Object as their argument, or an array of them. You can easily pause or resume all running tweens, kill off certain tweens, or just get tweens from a given object. I also completed the shutdown and destroy methods, rounding the Tween Manager off nicely.
It was important to me that Phaser 3 tweens performed far better than v2 but also were powerful enough that you didn't need to think about using an alternative. I'm happy to have achieved this now and created a few performance tests to demonstrate it (to myself as much as anyone else!).
The example above demonstrates the creation of unique endlessly running tweens. It's using a Blitter object for drawing the sprites, but the real test is in the running of thousands of tweens in parallel. I could comfortably push it into the tens of thousands before even noticing it on the performance chart, and at that point, you're into the realms of the rendering causing issues as well.
In the next test, I monitored what would happen if I created and destroyed thousands of tweens over a long period:
I always wanted the Phaser 3 tween system to be highly disposable. By that I mean I wanted you to be able to just fire off tweens left, right and center without really caring about it, and that Phaser would gracefully manage their creation and destruction, without any negative impact on your game.
This is what the test above is for. It creates a brand new tween every 10ms that has a random duration of between 500ms to 1000ms and then dies. Using a timer this is repeated 10,000 times. This means there are approximately 90 active tweens at any one time, but as the timer progresses thousands upon thousands of them are destroyed. So it's a good test of impact on gc and memory. Thankfully both cope very well. I left Chrome Profiler running on the above test for 1 minute and over all of that time Major GC accounted for only 0.3% (9.4ms total). The biggest activity was, of course, the Animation Frame Fired, taking 74% time, but out of that Minor GC was so tiny it didn't even register, at 0.0%. This lead to a JS Heap fluctuation of just 1.4 MB, and remember that includes all of Phaser (not just the Tweens), all the work the browser is doing, and all the work the Profile is doing as well. In short, I'm very happy that things are clearing up properly and we can all use tweens in our games with reckless abandon (to a degree, anyway!)
Deferred Lighting Lands
Last issue I showed you the new Light Layer that Felipe had added into v3. This used a Forward Rendering technique, which limits you to how many lights you can have in a scene before it really starts to kick performance in the nuts. Last week he implemented the deferred lighting system.
Deferred works differently to Forward in that it dramatically reduces the fragment count by performing the lighting calculations on the pixels on the screen, rather than each visible fragment. It requires the browser to support the WebGL Draw Buffers extension, which not all do, so the Light Layer will create the shader it requires based on browser support. You can also check the maximum number of lights possible by calling LightLayer.getMaxLights.
The maximum light constraints are enforced via a Consts file that is built into Phaser. We kept this separate from the source to allow you to easily change the values and then rebuild Phaser without needing to touch the code itself. Because of the way the LightLayer objects are created this isn't something you can set in the Game Config I'm afraid. The defaults are sensible best-guesses but are there to be changed as required. Lights are powerful things, creating a whole different look over the scene with very little code, but they come at a cost. Especially when shadows are introduced.
That's all for this week. There will be another shorter Dev Log in issue 94 next week, and then we're taking a week off for a well earned holiday. On our return, we'll be heading for the first Beta release.
Phaser 3 Labs
Visit the Phaser 3 Labs to view the new API structure in depth, read the FAQ, previous Developer Logs and contribution guides. You can also join the Phaser 3 Google Group. The group is for anyone who wishes to discuss what the Phaser 3 API will contain.