Published on 26th August 2024
Welcome to Phaser World Issue 194
In today's newsletter, you'll find cool games to play, tutorials on how to make interesting games yourself, and the usual crop of Dev Logs explaining our progress. Let's dive in!
Game of the Week
Forest Tiles
You have full control over the pieces in this Tetris inspired puzzle game.
Birdfood
Collect food, dodge spikes and repeat in this frustrating but oh-so addictive game.
Txtaria
A platformer that gives a whole new meaning to text-adventure.
Creating a Pac-Man game in Phaser 3
A YouTube tutorial featuring a well-known 3rd party tool.
Aseprite tutorial from Saultoons
Learn to create pixel art with Aseprite!
Creating Zuma with Phaser Part Two
Emanuele Feronato continues his tutorial series on creating a Zuma style game in Phaser.
Rich: Greetings all!
I don't have a huge amount to write about because I had the last week off as a holiday. So, instead, I will focus on what's coming down the pipe in the next few weeks.
Phaser v3.85 is still being worked on by Zeke and myself. Yesterday I was exploring how to improve the Phaser audio handling and learning all about the OfflineAudioContext, which seems like a superb way of detecting if the browser is audio-locked, or not, without triggering a console warning! It's also a super-fast way of decoding audio, too. I don't want to do a complete overhaul of the sound API (although it badly needs it), yet I do want to allow for both HTML Audio and WebAudio together in a single game - because WebAudio is perfect for sound effects and such like, but HTML Audio is much better for audio streams or longer duration audio, such as background music. So, it makes a lot of sense to no longer split the audio system and allow them both to co-exist.
Outside of this, Zeke has been working through merging all of our new examples and documentation in. There is a heck of a lot to do here - and it's a tedious and painstaking process, but the end result will be more than worth it. It's the kind of task you wish AI could automate, but it just can't :)
Once the docs are in and I've closed off a couple of final audio issues, v3.85 will be ready for release. I'll likely publish a Beta 3 this week to give you all the time to test the audio updates.
We've also got a brand new Phaser website inching closer to release. It's a drastic departure from the current style - but still retains the Phaser charm. John and Simon have been working flat-out on this, and I can't wait until we finally unleash it.
Pete has been working on Zeus, our new physics engine. It's still too early to show off, but I'll update you on progress over the next few weeks. Suffice to say, it's a big project, but if we get it right, it will underpin the physics in Phaser for the rest of its 2D lifespan.
Francisco: Hello everyone.
This week I don't have much to share since I've been focused on researching how we could make it easier for people starting out in the world of JS to use Phaser, without having to deal with the complex task of installing many packages that may seem unnecessary when you're just starting to create your awesome game.
Richard provided me with some points that we need to address in order to solve this problem, and I have been doing several tests to see if this new application can be built with Tauri and Rust.
All the tests I'm doing with Rust and Tauri seem to be working very well, but there are still some things I need to investigate about the Tauri API before proceeding to create this application. Stay tuned for more updates on this cool new tool.
Arian: Hello friends!
What can I tell you? We are still working on a Trial for the desktop version of the editor. It is almost ready! I think it is something that will be very useful for you to get a better idea of what the editor can do for you. How will this Trial work? You create an account on Phaser.io. In your account, you have a section for the editor downloads. You download the latest version. You install it on your PC and run it. The first time, the editor will ask you to authenticate with your Phaser user, and it will give you a trial period. I cannot give you many more details at the moment, I only invite you to follow us on the #phaser-editor channel of our Discord. Greetings!
Ben: 2024-08-24
How can we be sure we're making the best possible game engine? Well, one way is to make all the wrong choices, and by a process of elimination, wind up at the right solution. That's how my week went!
The objective: One quad tilemaps. A tilemap currently consists of hundreds of quads, one for each tile, and this can be quite expensive to render. It's not the GPU; it's computing all those individual tiles to send to the GPU. A one quad tilemap instead draws a single quad, which renders all the tiles inside the fragment shader.
This is only possible when the tilemap meets certain criteria. The tilemap must be orthogonal, a simple grid layout; it must not have any overlap; and it must not change. In other words, given a coordinate on the screen, we can easily calculate where in the grid that is, which tile is at that point, and which texel in that tile we should sample. Tile variants such as isometric maps don't work with this system, because they can draw overlapping tiles.
Given all this, we can convert the layer data into a texture, and use that to determine which tile we're looking at when we render. Seems pretty straightforward! Tileset textures are laid out on a strict grid, so if we treat each texel in the layer texture as a tile ID, we can easily find the frame we need to render.
(WebGL 1 doesn't support arbitrary data buffers like more recent graphics APIs. Textures are the only way to pass extra data into a shader.)
But there's one small problem: animated tiles. Things like water, computer panels etc can have multiple frames assigned to a single tile type. Phaser hasn't supported animated tiles until now, but the data is available. So I made regular TilemapLayers able to use them.
The one quad solution runs into a problem, however. Each tile ID in the layer is a single number. You can't animate a single number... can you?
Well, that number is actually 32 bits of data. So we decided to split it up to describe all the necessary tile properties. We need to know the tile ID, the flipX and flipY flags, and how to animate it.
My first attempt made several compromises. I broke the 32-bit number up into a 16-bit tile ID, 1 bit each for the flip flags, 7 bits for the animation frame count, and 7 bits for the animation duration. Given a time input, we could compute an offset from the base ID, generating a new ID.
This had the advantage that frame lookup was uniform: we could always generate an index from a single lookup. However, it also meant we had to build a second data texture, where every animation contained frame data in a row. We had to do this second lookup for every tile, even if it wasn't animated. Furthermore, the bits assigned to each property were quite small, limiting us to just 128 frames and 128 duration steps. And there was no support for variable duration lengths, which is a common feature in tile animations.
So I went back to the drawing board. I looked at Tiled, the preeminent tilemap editor on which Phaser's tilemap support is based. Tiled documents its format well, and its IDs are 32-bit numbers. The top 4 bits are used for flip flags and other metadata, leaving a 28-bit tile ID. Critically, two of those top 4 bits aren't used in orthogonal maps, so we can use them for our own purposes.
I implemented a variant encoding. The top 4 bits now define flipX, flipY, animation, and emptiness. The other 28 bits are the tile ID.
This was much simpler. Now, a simple static tile is just the tile ID: one texture sample. If the animation flag is set, that ID now points to an optional second data texture, which contains the animation data. Here, data is stored in pairs of texels: one for duration, one for frame. We can step through this texture, sample by sample, until we get a duration that matches the current duration; take the frame; and use that to render.
This seems like a dangerous thing to do in a shader. In fact, it's a little difficult just to get it compiling! You can't use while loops, and you can't use for loops with variable iteration length. But we can use a for loop with a fixed iteration length, and just break out of it when we're done. We can compile the shader to match the actual maximum number of animation frames in a tileset, using the preprocessor systems I discussed last week.
As a result, we can now render tilemaps with perfectly animated tiles in a single quad. Initial results are promising; it frees up a lot of CPU time, and the GPU is quite happy to do all this extra work, once we figured out how to define the problem!
This isn't the only reversal I did this week. Every choice turned out to have downsides. Can I render one-quad tile layers in batches? Technically yes, but there are so many variables that it's never going to be worth it, as I discovered through implementation. And so forth.
I'm working towards finalizing the tilemaps now. Lighting still needs to be implemented, and texture filtering around tile boundaries has a lot of potential for improvement. But pretty soon, we'll have tiles that are faster and prettier than ever!
Phaser Releases
Phaser 3.85.0 Beta 2 released 23rd July 2024.
Phaser Editor 4.2 released 7th August 2024.
Phaser CE 2.20.0 released 13th December 2022.
Have some news you'd like published? Email support@phaser.io or tweet us.
Missed an issue? Check out the Back Issues page.
©2024 Phaser Studio Inc | 548 Market St PMB 90114, San Francisco CA 94104