Phaser World Issue 199
It’s been another busy week in the Phaser Studio offices. We’ve got a new release of Phaser Editor, great new tutorials and case studies to read, and, of course, new games to play. Plus, the team has been hard at work on lots of great projects - which you can catch up on in this week’s extensive Developer Logs.
🎮 Astrogon
Play solo or against the world in this hardcore precision platformer.
We sadly missed this awesome game upon release, so we’re covering it now! Created by Kosmoon Studios, Astrogon is a dynamic arcade game in an intergalactic synthwave universe. Jump and dash your way between walls and obstacles. Avoid touching what will kill you, and reach the teleport portal. Get precise and strategic, or die. Then, create an evil challenging level for the rest of the world on Steam, Google Play, or the App Store.
🌟 Phaser Editor 4.5 Released
The latest version of Phaser Editor includes Monaco built-in, an updated JavaScript ESM template, refactored Script Nodes and new drag-drop project support.
Today we published our weekly release of Phaser Editor. In 4.5 we continue to polish the details, to make the editor a simpler and more powerful tool for all users. This time we've got a new integrated editor, vastly improved handling of JavaScript ES Modules, new updates for Script Nodes and you can now even drag a whole project folder onto the Editor icon/window.
Read the full release notes for details about all of the improvements.
Subscribers can update to this version immediately. Just grab it from your account's Downloads page or pick ‘Check for Updates’ within Phaser Editor. If you don't have a subscription, we offer a 30-day trial.
🚀 How Phaser is used at OpenForge
Solving accessibility challenges with Phaser.
Phaser is a natural choice for games, but you can also use it for apps. OpenForge, a top-rated mobile app development company specializing in mobile and web solutions since 2016, uses Phaser to build its product, StartupWars. OpenForge kindly agreed to talk about their experience using Phaser.
💎 Creating Phaser games for Rune
Learn how to easily make a multiplayer Phaser game that can be enjoyed by millions of players on Rune.
Phaser is perfect for single-player games since physics and collision happen on the client side. But what if you want to create a multiplayer game? Enter Rune, a social gaming app with millions of people playing HTML5-based games together across iOS and Android.
Their mission is to make mobile gaming more social and enable indie game developers to get their games into the hands of millions of players. By leveraging the Rune SDK, developers can add multiplayer capabilities to their Phaser games and get access to tons of new players by adding their app to the Rune platform. Now that's a win-win!
Read the Phaser + Rune Tutorial
🎥 Twitch Stream Hackathon
Use your Phaser skills to build an app for streamers.
Twitch has announced a new hackathon, this time centered on building an app for streamers to collaborate with each other, their community, and enhance their streams. The goal is to build an application or Twitch Extension that uses Twitch authentication for application users, and the Twitch API or EventSub. For Phaser developers, two of the three submission categories stand out.
Read the Twitch Streamer Hackathon article.
👻 Ghosts in the Machine
A thrilling, puzzle-based adventure that blurs the line between the steampunk world and the supernatural.
The FocusFire team has released a great new Phaser game for GBJAM 12, a jam about making gameboy inspired games. In "Ghosts in the Machine," you find yourself as a restless ghost haunting a lonely mansion. Your mission is to scare away visitors as you outwit them on every stage with unique machines, traps, and, is that phonograph?
Phaser Studio Developer Logs
🧑💻 Rich
Last week, someone emailed Phaser support, asking what the status of Phaser v4 was. That's a valid question. Even though I have covered this quite a few times now, there is still a lot of material out there talking about v4 development from several years ago. So I figured I'd use my reply as my entry this week so everyone can be crystal clear on what is and isn't going to happen in Q4 2024:
As you know, the current version of Phaser is v3.85.2. We have spent all year working on our brand-new renderer, Phaser Beam. This was a complete rewrite from scratch, built in a modern way, with outstanding performance and a reduced memory footprint. We expect to finish development of this within the next month. You can track the development of Phaser Beam through all of our weekly Phaser World issues. We've been writing about its features and evolution all year, so there's plenty of juicy meat to pick from the Dev Log bones if you're interested.
Once the initial version of Phaser Beam is finished, we plan to merge it with Phaser v3.85. We will make other improvements at the same time, but the core API will remain largely the same. The improvements will nearly all be rendering-related, and this merge will form the Phaser v4.0.0 release.
After Phaser v4 is out we will focus on what can be done to modernize the API, i.e. move fully to using ESM Modules, ES6 classes, etc. But our priority is getting our powerful new renderer in place, and to us, that is Phaser 4.
Anything you may have read in old Dev Logs from 2021/22 re: Phaser 4 is no longer applicable. While we could have carried on down that path, it made no sense. It would have forced every single Phaser developer to start again from ground-zero and would have been entirely incompatible with Phaser 3. Instead, we are favoring an incremental upgrade roadmap rather than a 'nuke it all from orbit and start afresh' approach, which would have benefited no one.
I hope everyone reading this can clearly see how busy we've been this year. From constant updates to Phaser and Phaser Editor, to stacks of new templates, tutorials, a brand new renderer and a new physics system. And we're not done yet. The new docs site is imminent, as is a brand new web-site - and of course the release of Phaser v4. It's been quite the journey so far, but stick around because things are about to get really interesting 😊
🧑💻 Pete - Box2D
A short one this week: After finally fixing the bug that has been plaguing the box2d conversion (turned out to be 8 separate bugs spread through-out the code... or maybe it was just the last one, I wasn't going to put the other 7 back in to verify!) the project is moving forwards again at pace.
I've been expanding the testWorld
with new features and more and more objects to stress test the code and get an idea of where the strengths and weaknesses lie. It's very good at joints and objects including compound objects. It slows down significantly when you get a large heap of things all touching but not asleep.
I believe this is because the color graph code was part of the threaded system and it's been disabled where it hasn't been outright removed. I think the concept of colour groups is a brilliant optimisation, and there's no reason why it wouldn't work to a worthwhile degree on a single thread and without SIMD instructions. We should definitely look at implementing something similar. I don't recommend wasting any more time trying to modify the original though, the SIMD instructions and support code is incredibly tricky to remove and it is also tangled in with the multi-threading support.
I've been converting all the bespoke code for each effect into a set of tidy wrapper functions. That is going smoothly, and there are many more we could add which will add value for users... we'll probably have to triage them eventually, although it could be made into a longer-term support effort based on request frequency.
At the end of the week I restored a bunch of the older demos so they will work with the new helper functions. There's a handy 'switch' at the bottom of main.js now which lets us switch between them. I also added an 'image circle' and an 'image capsule' draw function to the debug draw code. This lets us load images and fit them to those shapes, for more attractive looking demos. See the image below for an example.
🧑💻 Francisco - Phaser Launcher
This week, I’ve been focusing on a new project that we believe will simplify the onboarding process for anyone interested in Phaser. The goal is to create something that lowers the barrier to entry, making it accessible for developers of all skill levels.
As part of this initiative, I’ve been testing Tauri’s potential to develop a lightweight editor. The idea is to allow users to load a folder directly into the editor and easily modify any JavaScript files they find. It’s a small but powerful tool that could greatly improve the workflow for developers working with Phaser.
The next step we’re aiming to test is generating a server with hot reload functionality, if possible. This would allow the tool to launch a small template with Phaser already installed, ready to work right out of the box. Thanks to everyone, and stay tuned to learn more about this exciting new tool!
🧑💻 Zeke - Phaser Docs
Hello and welcome to another weekly update on progress on the new Phaser Documentation site. This week I finished the following new sections:
- Maths functions
The documentation includes different aspects of mathematical operations and utilities available. Here’s a brief summary:
Basic Functions : Functions built on top of native JavaScript Math functions with its own Phaser.Math namespace to prevent conflicts. Used to calculate Average, Difference, Factorial, whether a number is even (IsEven) or is a power of 2 (`Pow2).
Minimum, Maximum : Functions to calculate a range of values between the minimum and maximum range.
Round To : Various rounding methods like CeilTo, FloorTo, RoundAwayFromZero, and RoundTo.
Distance : Calculate distance between points, including specialised methods like Chebyshev and Manhattan.
Angle : Calculate various angles and perform conversions between radians and degrees.
Random : Generate random values and vectors.
Color : Convert between different color formats, adjust color properties, and generate random colors.
Vector: Create and modify 2D, 3D and 4D vectors.
Curve : Creating and modifying curves and paths including lines, circles, ellipses, arcs, splines, and beziers.
- Geometry
Phaser comes with an extensive set of Geometry classes which are used internally by the physics and input systems. This document includes:
Geometry Classes : Listed the geometry classes on offer, including Circle, Ellipse, Line, Point, Polygon, Rectangle, Triangle, and the Mesh class.
Geometric Operations*: This includes:
Containment Checks : Check if a point is contained within various shapes.
Nearest Point : Find the nearest point on a shape to a given point.
Area and Perimeter : Calculate the area and perimeter of shapes.
Transformation** : Transform shapes by scaling, rotating, and translating.
- Intersection Functions : Test whether one shape intersects another.
- Graphics
How to draw primitive shapes in your game. Primitives include rectangles, circles, polygons, lines, arcs, curves and others. Graphics can be drawn using a specific line style, fill style or both. Here is a full list of shapes that can be drawn:
Arc : Draws an arc shape with a specified start and end angle.
Circle : Draws a circle shape.
Curve : Draws a curved shape.
Ellipse : Draws an ellipse shape.
Grid : Draws a grid based on the width, height, cellWidth and cellHeight.
IsoBox : An 'isometric' rectangle where each face has a different fill color.
IsoTriangle : An 'isometric' triangle like a pyramid where each face has a different fill color.
Line : Draws a line between two points.
Polygon : Draws a polygon from a list of points.
Rectangle : Draws a rectangle shape.
Star : Draws a star shape with 5 points by default. You can control the number of points, the inner and outer radius.
Triangle : Draws an triangle shape.
- Tweens
Tweens create smooth, time-based changes to object properties over a given duration of time. The documentation shows the following:
Creating a Tween : How to create tweens, set target properties, easing functions, duration, repeat, yoyo, and other configurations. Tween Property Expressions : Shows different ways to set tween target properties, including direct value assignment, relative value changes, random value generation, using an array of values or setting object properties.
Tween Callbacks : Lists events where callback functions can be triggered.
Tween Configurations : Details properties that can be used in tweens such as delay, yoyo, ease, duration and more.
Easing Equations : A list of available easing functions that affect how a tween progresses.
Tween Controls : Methods to control tweens include: pause(), resume(), complete(), stop(), play(), restart(), seek(amount), remove() and destroy().
Tween States : Use isPlaying() and isPaused() to check current tween states.
Tween Chains : Create and manage tween chains by adding, removing, pausing, resuming, and restarting the chain.
Tween Events: A full list of events dispatched throughout the lifecycle of a tween.
🧑💻 Arian - Phaser Editor
Hello!
A new week, a new Phaser Editor release! Check out Phaser News because a new version of the editor may be available. For this latest release, we've focused on improving the experience for those who don't have much experience with web development yet. What does this mean? We've updated the project templates to be based only on plain JavaScript. These templates now use modules, which follow how JavaScript is programmed today.
Something else we've done to make JavaScript newbies more comfortable is to incorporate a more advanced JavaScript editor, based on Monaco, the main component that Visual Studio Code uses in its editors. With this update, you'll have a decent set of features to code your game directly in Phaser Editor. However, if you want to go a bit further and use a more advanced toolchain, such as web bundlers, TypeScript, etc... it would be best to use Visual Studio Code. But if you're looking to get started with plain JavaScript, you're covered with Phaser Editor!
Something else we've added this week is a new way to open a project in Phaser Editor. This involves dragging your project folder onto the editor icon to open the project. This works on macOS only.
Another alternative is to drag the folder onto the editor's start page. This works for all platforms.
Keep in touch!
🧑💻 Can - Discord Activities
Kia ora!
Exciting times — Discord has made Activities public for all! This opens up a fantastic opportunity to bring your Phaser games directly into the Discord ecosystem, for the millions of players. In response, we've updated our templates and working on an app to simplify publishing your games as Discord Activities. The biggest update was a breaking change for the previous versions, which is about setting our url paths as "./proxy" for all HTTP requests we make. All our templates are updated and works in local too.
We can't wait to see you all coming up with cool games that reaches out to millions, a new era for the HTML5 games!
We have #discord-activities channel on our Discord. Come and join us, share your inspirations, issues or how can we help you to make your workflow easier!
Tales from the Pixel Mines
September 30th, 2024 by Ben Richards
This week, I've been trimming DynamicTexture
down to size. Its implementation under Beam will have a few changes, which I'm hoping will be convenient, but it's still worth explaining them.
Command Buffer
Projection Matrix
Everything is GameObjects
Repeat is TileSprite
Camera Enabled
Canvas Too
Texture Trimming
50% Off
DynamicTexture is an ordinary Texture, with built-in drawing tools so you can edit it at runtime. This is a great way to render accumulating visuals in a scene, such as damage on a battlefield, breaking holes in windows, or painting in the game world.
This post is mostly about WebGL rendering, because that's the focus of the new Beam renderer.
Command Buffer
The DynamicTexture now uses a "command buffer" similar to Graphics
. Instead of rendering whenever a drawing command is run, it puts the command in a buffer, along with all its parameters.
To execute the command buffer, call DynamicTexture.render()
. This will immediately run all buffered commands. This is more efficient than piecemeal rendering, because it is almost exactly the same as a regular render pass. This allows us to use the same rendering systems, with all the optimizations and capabilities that entails.
The main difference is that there are no camera effects (background color, flash, fade, shake) in a DynamicTexture. These generally make no sense, because a DynamicTexture isn't animated.
Performance of the command buffer render is excellent. It works just like regular rendering, so you can estimate a rendering budget based on what you're rendering.
Projection Matrix
The projection matrix is a piece of linear algebra used to map from game world coordinates to WebGL texture coordinates. This is necessary because WebGL is upside-down compared to how we normally think about screen coordinates!
2D game world coordinates are [0, 0] at the top-left, and might extend to [1280, 720] at the bottom-right.
WebGL texture coordinates are [0, 1] at the top-left, and [1, 0] at the bottom-right. So [0, 0] is at the bottom-left. It's flipped upside-down compared to the game world! Also, it's always square, even if it's drawing an area with a high aspect ratio.
(WebGL clip coordinates are another thing again. These are how WebGL draws to the screen. Here, the top-left is [-1, 1], and the bottom-right is [1, -1]. Confusing? Yes! Phaser does this all in the background for you.)
The projection matrix lets us draw in WebGL without worrying about stretching things into a space 1 unit across. We can keep coordinates in a sensible world system, and convert them to WebGL space in the vertex shader.
Sound complicated? It is! We had to make some decisions about which space to prioritize. Here's what we've settled on for Beam:
All textures and framebuffers have the top-left at [0, 0] in WebGL coordinates.
The main game canvas has the top-left at [0, 1] in WebGL coordinates.
This means that texture coordinates are in an intuitive top-left system.
It also means that everything is upside-down from WebGL's perspective, so when rendering to the main game canvas, we flip the projection matrix upside-down to put it right-side up. As a side effect, all textures appear upside-down in debug tools. This doesn't matter because the projection matrix corrects everything.
This is a new assertion for Phaser in Beam. Previously, this was mostly true: textures were upside-down, and the projection matrix is upside-down for the game canvas. But some systems didn't work that way. We're trying to make things simpler, so we're unifying coordinates. This could come back to bite us when I start work on FX shaders, so things could change; but I hope it works out.
Everything is GameObjects
Unification allows us to use standard rendering technology in more places. This brings us back to DynamicTexture, where we want to draw various items into a texture via a framebuffer.
Previously, we used various Pipelines to render textures to the framebuffer. These followed their own logic, separate to standard rendering.
With the command buffer, we take textures, apply them to a spare Stamp object, and render them with the regular rendering systems. This sounds simple, but it has some far-reaching consequences. Now, anything that can be rendered can also be rendered to a DynamicTexture, and will render exactly the same way.
This is part of a general drive towards consistency. Things should work the same wherever they are in the game.
Repeat is TileSprite
A DynamicTexture has the repeat
method, used to repeat a texture across a region. Because everything is GameObjects, we now render this by setting up a spare TileSprite
object and rendering it.
This means the repeat
method can take some extra parameters, allowing it to do everything TileSprite can do. The texture can be scrolled, scaled, and rotated. (Rotating TileSprites are new in Beam. Everything synergizes.)
DynamicTexture Camera Enabled
DynamicTexture has always had a Camera. This was originally just for rendering, and didn't actually do anything. Now, the camera can transform, which gives you more freedom to draw as you want. Note that camera effects are not rendered, and Stamp objects (including all drawing operations with raw textures and frames) are unaffected by camera transforms.
Canvas Too
All the changes to DynamicTexture work in the Canvas renderer too. This took a while to get working, mostly because I forgot that I was clearing my test texture, and spent too long trying to figure out why nothing was rendering. But the code was all running perfectly.
Texture Trimming
Here's another reason why consistency is good: it means we can keep complicated things to just one place, reducing the risk of mistakes.
Case in point: texture trimming was handled differently between Textures and GameObjects in DynamicTexture. But now that everything is GameObjects, the differences have disappeared.
What is texture trimming? It's a space-saving measure taken by texture packers. When packing several sprites into a single atlas, empty space around the edge of a sprite can be removed, and stored in the atlas data. When we come to use the sprite, we can make the GameObject the size of the original sprite; and then render just the smaller frame. The empty space around the edges is implicit.
Unfortunately, this means that a trimmed sprite doesn't have a single size. Here's a screenshot of me analyzing one particular example:
You can see how the trimmed region (yellow) is offset from the original region (red). Other sprites overlap the original region, but because of trim, we don't render these overlaps.
But if we use the wrong size to render the image, it will appear somewhere we don't expect. For example, DynamicTexture.draw(texture)
and DynamicTexture.draw(gameObject)
had different results, even though they were using exactly the same texture:
However, because everything is GameObjects, in Beam they both render with the original frame margin:
This is a change from the way things originally worked, but it provides more consistency. I hope that makes things easier to work with!
50% Off (Functions)
We've added the new render
method to DynamicTexture. However, because everything is GameObjects, we've also removed a whole lot of functionality from the class. (And by extension, those functions have also been removed from RenderTexture
which wraps DynamicTexture.) Right now, it looks like about half the functions have been removed.
These functions were mostly batch-oriented. They allowed you to manually start batching, add objects to a batch, and render a batch. However, why should you need to do that? Batching is pretty technical, and as the engine designers, we should take care of that for you. So we did!
And that's why I went to all that effort over the course of this week. Now, all you have to do is order a DynamicTexture to draw some things, and we'll take care of the rest. As it should be.
Coming Soon
I've still got some tidying up to do on DynamicTexture. After that, I'm finally moving on to the Box, my new design for handling FX, masks, and other framebuffer tasks. This should bring more of that delicious consistency to Phaser Beam. It's taken a while, but we're finally getting there, and I'm excited to put everything together!
Submit your Content
Created a game, tutorial, sandbox entry, video, or anything you feel Phaser World readers would like? Then please send it to us!
Until the next issue, happy coding!
Subscribe to my newsletter
Read articles from Richard Davey directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by