It's 2021 somehow!
2020 was a whole year. That's all that'll be said on that front.
What happened for luxe since the last dev log? Quite a lot!
There's some big news below, keep reading!
Since the focus is solely on getting a preview build ready, a lot of the changes involve
breaking fixing things that would be harder to fix later, as we'll see. It also involved lots of testing, and fixing aspects that get in the way of workflow, making the engine usable.
Since the last dev log had these stats, here's the 2020/2021 movement on the main repos.
- module - 644 commits (2384 total), 853 files changed
- runtime - 563 commits (2435 total), 301 files changed
- editor - 334 commits (937 total), 165 files changed
I've mentioned the preview build before, this is the current focus for luxe. But what does it mean in practice? And how do we know when we're there?
what is it
The purpose of the preview is to be representative of what luxe is, to feel like luxe and behave like luxe. Not complete or perfect, but usable and nice to use, despite work in progress aspects. You should be able to use it to make a variety of games easily enough, even if some parts are more manual or less streamlined.
how to know when we're there
The only way to figure out when that goal has been reached is to make stuff with the engine! Typically within the bounds of what the engine's current focus is (e.g luxe is 2D first, but also pushing a little bit since there is overlap).
When making things, you can answer vital questions like: could you make what you wanted to, or were you blocked by something? Not that the engine will provide everything for you (not possible), just that you could do what you needed and get to your goal without luxe getting in the way.
A lot of times this leads to finding and fixing important bugs. A good example was Ronja using the UI system for a pixel art game, at pixel art scale. That means units are much smaller than the average UI... does it still work in all the ways it should? What prevents you from using it that way?
It also leads to finding and fixing important workflow issues. An example: doing a game jam with Mariana, who hadn't used the engine or editor before.
What were the big issues with workflow? One issue here was importing assets had a really awkward flow at the time, which became clear that it's a relevant issue to resolve for the preview build. A lot of quality of life/workflow issues can get resolved just from one jam!
so... are we there yet?
While there's always more work to do, the line has to be drawn at some point, and here it is.
The preview build is ready enough for a wider closed beta!
There's loose ends to wrap up but beyond that all the bigger tasks that I wanted done are done enough to enter the preview cycle. How can I tell when certain things are done enough? I wrote a twitter thread about "for now", and how I use it to make luxe.
An important factor is that the preview is not done and not perfect and doesn't have to be. What matters is that there's an engine that's usable, and is nice to use despite in progress parts, and will keep getting better over time. Especially with more feedback/use cases, those are key to solving issues quickly.
Some important points to reiterate:
- the primary focus is 2D first
- luxe is still a work in progress
- many things in development to improve/push things further
purpose and duration of the preview closed beta
Now that a lot of stuff is in place and you can make a variety of things, the biggest goal is to flush out any obvious bugs and issues and to make sure the on-boarding is good enough by throwing a bunch more users at it.
The closed beta will be a LOT shorter than the closed testing "dev" phase that came before it. I don't know exactly how short, but the goal here is much simpler. Once confidence in the baseline has been increased, we'll move into the next phase, whenever that is!
The plan is to start by adding a bunch of testers and see what breaks down or needs addressing, and ramp up soon after.
I'm interested in the closed beta!
Great! Please fill out this form.
I've updated the website to reflect current state + developments over time, add more images and clarify things.
I've also obtained this neat URL: createwith.luxe
You can use that one alongside the primary one of luxeengine.com
tutorials and samples
A big part of answering "can you make a certain type of game" is by making that certain type of game, and seeing what kind of problems you run into. Not a full scope/full content version of the game, just a sample, enough to answer the question.
Examples are a visual novel, point and click adventure, platformer, top down and a card game of sorts.
These samples will take a bit of time to be complete, but they're coming along. Some of them start as jam games! They offer a way to see how one might structure certain projects, and a foundation to make a game of that type from where you can adapt the sample to your needs. They can show idiomatic ways to go about solving certain problems too.
Making these also involves making modules that handle some of the specifics (since the engine shouldn't), like pathfinding in a point and click game is different from pathfinding in a platformer. The engine can provide the pathfinding foundations, but not the game specifics. Those go in modules you can drop in a project and use easily.
For these reasons, a new tutorial and sample games are in the works. They won't all be action games, won't all be pixel art, and will also help reveal workflow issues during the preview cycle.
While there will be several tutorials added over time, and there have been some basic ones before, I wanted to make a new better tutorial that teaches you more about the engine so that you know what kinds of tools are available to you to make your games.
The tutorial is more of a tour of the various systems in the engine, showing how they're used but also what they're useful for. The tutorial alternates between code and the editor to show how they complement each other, and each step is quick and easy. It covers making the scene below come to life.
I've also been working on a character for the tutorial which we'll see in motion a bit later:
2020+ in review
A lot of time has passed since the last dev log and a lot of stuff has happened, so let's take a look!
The new launcher has been in use for quite a while now. It's written in luxe itself and it manages projects, modules and installed engine or editor versions.
Here's a random video of it in motion with some lovely compression.
During 2020 there were several game jams that myself and some testers made stuff with luxe.
LD46 - April 2020
For LD I made a short platformer about carefully carrying a plant through some levels to an end goal. The jam went really well considering the time I had, and I managed to make a closed/replayable loop with some amount of content.
This also tested out the arcade physics module nicely (mentioned in the last dev log) and a lot of improvements went into the module as a result.
The link above includes a short post mortem on the jam entry and more. You can see it in motion below.
A screenshot of the one level in the tilemap editor.
Tilman decided to try making a giant robot that walks around that you can interact with and control. For all the details and wip gifs and implementation details go read the post mortem here.
This game has some interesting challenges like having a tilemap + collisions parented to a moving robot, which worked out. This is a great example of could you do it if you wanted to?
See it in action here:
7dfps - December 2020
For 7dfps I worked on a gravity flipping physics FPS game with quake 3 CPM style movement (strafe jumping, air control, etc).
The work done for the jam included a lot of work on getting the physics API more evolved (detailed later) as well as the transform system getting a lot of new helpful APIs for converting between spaces, rotating things in ways that behave nicer (slerp, etc) and a lot more.
I'm still working on levels but the first level and a physics playground are linked below. Note that the links below require webgl2 and webassembly!
Play in the physics playground
This is what the gameplay and the playground looks like.
The way it works is when you hold left mouse (which slows down time), you can then change which direction gravity is based on a surface you select. I used Crocotile to make parts of the playground level and then placed them in the luxe world editor.
Play the first level here
This is what the first level looks like.
Note: spoilers if you want to play it first.
01010111 was exploring various ideas like a spooky forest
Tilman was exploring a grappling hook and world space texturing
Tilman also explored this idea for Kenney Jam, twitter thread here.
At the end of the year our studio does a game jam and as mentioned above Mariana and I tried to make a game in around a day and a half, while we didn't get as far as we wanted we did get a lot done considering the time frame. I wrote a short twitter thread about it.
It was rewarding to focus 100% on game content and the workflow holding up enough to get that much done so quickly.
Along the way I 'll often indulge by working on things for myself (like 3D stuff) or take detours to keep momentum. Here's a look at some of the things done since last time!
One of the things enjoy working on is my render pipeline module that I use for my 3D games. This was mentioned in dev log 9 as well, but this time I worked on some additional visual effects which we'll see all combined below.
I added screen space reflections (SSR), and while doing so was chasing a couple interesting bugs to get it working. I posted a twitter thread of interesting glitches.
I also added indirect lighting via light probes, and reflections via reflection probes. If you look at the white cubes to the left they're picking up bounced lighting via the blue wall + red wall nearby. The second image shows the probes in the scene.
You can see an older version in motion here
I also redid the screen space ambient occlusion (SSAO) to use blue noise and fixed a couple bugs in the details. I posted a twitter thread about it.
I also redid the bloom and fixed several issues with it, making it much smoother and more stable.
I also added some color grading later on:
Here's all the changes combined and how they affect rendering!
And finally, I ported the render pipeline to WebGL2, which had no real changes to the pipeline itself, only some engine side fixes and assumptions resolved which were invalidated by WebGL being a lot more strict than desktop! This lead to several good bug fixes for all platforms. Here's a long twitter thread about porting it.
Here's some old builds from the first tests. These require webgl2 and webassembly as well.
Check console below the view for logging but here are the keys:
right mouse+ wasd to fly around (mouse wheel for speed)
1 - 7features (ssao, bloom, ssr, fog, shadows, lights, decals)
8- toggle lighting environment between 2 presets
9- hold + mouse x controls environment exposure
0- disables fog raymarching on the first scene
=to cycle render stage
rto reset physics in the second one
Since I maintain the Wren scripting language, there's also been updates on that front as well as work on the user facing side in luxe.
Note that some things in luxe aren't feasible in the main branch of Wren (yet) and aren't general purpose, they're specific to luxe.
One of the things I explored with Wren in luxe is VM-wide profiling, where every function can be profiled and the markers sent to a profiler app. I managed to get it working pretty well! This will come in handy later.
The other bigger thing I've been working on for Wren in luxe is IDE + code completion integration. This involves a lot of moving parts but we're now at a good point and have all the hard parts done.
The video shows completion data in Visual Studio Code which comes directly from the code which is annotated with Wren attributes.
There's all kinds of work in progress stuff, like optional type annotations, basic type inference and more that's being explored. It's possible to support quite a lot of the features vscode provides.
This is how the attributes for the first video above look in code
dev progress tour
There's been a lot of work done so we'll do a whirlwind tour of the biggest stuff!
Y+ is up in 2D
Speaking of fixing things that would be harder to fix later, this was a big change and required quite a bit of effort but it's well worth it. I should have questioned that early on but I went with what I knew where 0,0 was top left and y+ went downward.
It took me a while to make this decision but I'm certain it's the right one because of the many places it unifies and makes things consistent, even if it took me a bit of time to get used to.
With Y+ going upward and 0,0 being bottom left by convention, there are things like how trigonometry functions no longer need offsets to make sense, it matches the unit circle, so the math works out unmodified. It also matches the default 3D space, where y+ is up, so that you can trivially mix 2D and 3D worlds. Before it required inverting one of them somehow, leading to a lot of points of error.
Conceptually also, a ball going upward is increasing a value. If the animation editor didn't invert the Y axis (which makes other animations confusing, and conflicts with 3D being y+ up), then a bouncing ball animation like this would be upside down, because "more" is "down". There are other reasons, but I'm happy with the change.
render in world
Originally you were able to render the UI in luxe in 3D but it wasn't as flexible as needed, so I re-implemented it and made it able to handle all the input from any camera, handle all transforms as expected, as well as added render modes. One of the goals was that you could just attach UI to any entity and have it follow it around, which is now the case.
The one render mode is to render into an image, and then display that image (perfect for mixing UI in 3D space) and the other is to render in world space as is.
basic ui layout
While I still have some bigger plans for UI layout, it was necessary to have an option for it shorter term. So now we have a layout engine that you can opt into on a per UI basis and it'll handle flexible layouts for variable resolutions and such easily.
Not an exciting video, but you can see it in motion here.
Mentioned in previous dev logs, a prototype in luxe is a preconfigured set of entities with modifiers attached, which can be spawned in a world, a scene, or inside of another prototype.
Originally when I was exploring the ideas I implemented a stop-gap version that was a compile time "flattening" that flattened the scene into a single list of entities to spawn.
This didn't work out for a number of reasons, e.g if you change a prototype, all scenes that contain it need to be rebuilt. There's also no runtime information about the prototype connections between things, which is necessary for changes made to a prototype at runtime being reflected in all instances of it.
For example, if you had a lamp post prototype and placed many instances of it in the level, you'd expect to be able to change the color of the light in one place and all instances reflect that change (unless they override it).
Instead, I rewrote the prototypes to be a runtime system and while still on it's way to being fully realized, is much cleaner and simpler in the long run.
The other important factor of course is being able to edit and use prototypes in the editor properly which made a lot of progress during 2020. They're fairly usable now and I've been using them extensively in prototypes and a bigger game you'll see later.
This is a bit of a longer video (and the editor is outdated here), but this shows: creating a new prototype, spawning another prototype within it, overriding settings (the pink line to the left of a property). Then, spawning an instance of our new prototype in a scene, and overriding the settings for that particular instance. Nothing too surprising.
The animation editor has been rewritten so many times... It's been quite tricky to get it integrated nicely into different workflows and work is ongoing, but finally the tools are usable enough to be useful.
Here's a work in progress idle animation showing the new sprite animation track (and a fake transform track so curves are visible). The preview button shows the sprite track in isolation in the scene view so you can look closer and control time etc.
Due to rapid iteration times I hadn't gotten around to implementing any hot reloading yet, but during the jams it became clearer how much it would improve workflow (especially for others) in the editor, for assets in particular, like editing an image externally and having it reload vs restarting the editor.
Since the ground work for doing this for all assets isn't in place yet, I only implemented it for a few: images, meshes and shaders. This already goes a long way but obviously proper reloading will come in time.
images (affinity designer <-> editor)
meshes (blender <-> editor)
shaders (vscode <-> editor)
Something I hadn't implemented till recently was initial atlas support for packing images together.
You can specify a folder for an atlas asset, it'll pack the images from it into one big image, with optional trimming + rotating for better packing, and at runtime you can use that atlas with the Sprite modifier to display it. Later it'll be able to be used in tilemaps + animations too. This also added some useful tools for image manipulation when the engine is headless (no renderer running).
The content below for testing was thanks to Stefan. Blue ones are rotated and white outlined ones have extra pixels trimmed off for better packing.
As mentioned previously, importing assets in the editor before was a bit weird. Anywhere a material or image was assignable, it let you create one instead. This is nice and makes sense on it's own, but also meant in order to import an image your easiest option was to make an entity, add a sprite modifier, select the material, choose create material, then choose create image... not a very direct route.
Instead, I've now added an asset import shortcut which opens a selector for types, and have streamlined the process for the common 2D workflow of importing a sprite (which is an image as well as a material to display it with). Later we can support drag and drop and such from the asset management context but for now this is a big improvement.
physics fixes, materials + filters + callbacks
Part of the goal with 7dfps was to solve the outstanding tasks for the physics engine (bullet physics) and implement proper filtering and callbacks. I also implemented physics materials, so you can configure a body or collider to have different bounciness and friction settings. The nice thing is that these additions + fixes apply to the 2D physics as well.
There was also a variety of fun physics issues fixed that anyone familiar with implementing physics would recognize. One example of this is "inner" ghost collisions when using a 3D mesh as a collision mesh. Because the mesh has seams due to triangles, sometimes you'd collide with those seams and bounce upward a little. You can see this below, the first half shows the camera bobbing up and down due to collisions with the triangles, and the second half shows the fixed version where it's smooth.
These aren't hooked up to a UI yet, but you can see the idea in the asset data. The left hand side is per body settings, and the right hand side is the per collider physics material. The 'mode' options are min, max, average or multiply, where e.g if two physics objects collide you can choose how the response will be calculated.
For filtering, I implemented a simple model based on presets, where a body is given a tag like "trigger" or "player", and the presets determine what happens when a player and a trigger body interact.
The options are [ignore, overlap, collide] and the lowest response is chosen. ignore vs collide = ignore, overlap vs collide = overlap, collide vs collide = collide. This can be worded as: if any body is set to ignore, there is no response. If neither body is ignore and one is overlap, they will overlap. If both are set to collide, they will.
I really like this system and how easy it is to reason about, but also for workflow reasons, when you're building levels it's nice to just select a preset and know that it'll behave as intended with all existing configured interactions. I've had instances of finding a rock somewhere in the level later that happens to let you walk right through, or a tiny piece of foliage that blocks the player from walking, and this helps keep that simple.
The callbacks are nothing surprising, you can opt into notifications about when things collide or overlap! In the 7dfps game for example when you hit a wall in front or above you, I zero the velocity.
The video below may be a bit vague, but shows the callbacks printing information about the collisions happening in the scene. The scene shows the tag for the physics bodies being changed dynamically, which changes the ignore/overlap/collide responses, and the response + events are adapting on the fly.
Other fun stuff
LD46 side effects
As with any jam we might run into issues that can be resolved either during or just after, here's a few that were caused by ld46.
The arcade physics module received a bunch of work during the jam, including a dynamic broadphase spatial hash to keep it running smoothly in large levels. This means collisions only check things they're potentially in range of, rather than the whole world.
tile workflow improvements
While working on a bigger level in the tilemap editor, I had noticed a few workflow issues, and right after the jam added tools like select by visual, select by tag, select by depth. I also fixed multi tile property edits and made them simpler.
In the video below we can see two things happening, one is highlighting different types of queries (the teal/greenish color indicators), and then select all tiles with the matching visual (pink indicators), and we update the visual to a new one (from green to brown corner tile).
Being able to see where related tiles are without it affecting selection is pretty handy.
A little while later but still related, Eduardo suggested an improvement to tile painting that allows painting tiles faster and not having any gaps in the process. Previously it was a bit spotty if you went too fast.
I added a basic A* implementation to luxe (the generic wren version seen here) and I've shown it twice above, but here it is in motion.
The first is the LD game where I was testing it out. The second is pathfinding for the point and click module.
You can read about the implementation details for point and click pathfinding here here (which used the very old luxe alpha!). This video shows a different view of a path around arbitrary polygons, in the samples section above we saw pathing through a space made of polygons too.
animation curve maths
While working on the animation editor, I was trying to ensure that the curve remains valid, where only a single y value exists for every x value (x = time). The solution is pretty neat and I posted a twitter thread about it here, which covers how I approached solving it and the solution. Mikko Mononen also posted an interesting solution here.
In the video, the gray handles are the real handles, which are modified to respect the rules of the curve.
Since the engine is coming along well I've been working on a more substantial game called mossfield origins using luxe. It's a small cozy city-building-style game and I've been posting a relatively detailed dev log over here.
The gameplay has come together really rapidly, which is great considering I was only working on it a bit every day where possible during march. If you're interested in seeing it progress, seeing how I structure the game systems and content, the dev log is where you'll find that.
calming wind turbines:
A random video of the game in motion:
And with those 4600 words later, see you soon!
Read about the community conduct.
Join us on the luxe discord. We run polls, answer questions, post in progress details, and talk about the engine.
News in other forms
You can follow news about luxe on twitter @luxeengine or by subscribing to the rss feed or using the mailing list sign up on https://luxeengine.com/. Especially I'd highly recommend signing up for the mailing list.