home

You've successfully subscribed to luxe engine!

Subscribe to luxe engine

Get updates from luxe directly to your inbox.
We'll only email for important dev news or betas.

dev log #13 - scenes

luxe

We're back again, and as we start to wrap up for wider release we've got plenty to talk about - this is part 3 exploring what it feels like and looks like to use luxe to make games, in concrete detail. Get yet another cozy seat and see how Scenes, Prototypes and Templates work in luxe.

We'll begin with the basics, what is a scene exactly?

A container of entities!

Now that we know what modifiers look like, we need a way to store them in a scene we can load later, like a level file, or a chunk of the world. This is what a scene is for - it stores related entities together in a container that can be loaded, and unloaded, in one call.

A scene is just that - a container of entities. In luxe, we call this container an "Entity Context", e.g context when talking about the world stuff.

Entity assets

In a luxe scene, an entity is represented as a single file per entity. There's a dozen reasons for this - not least of which is working in teams where we avoid conflicts on big files everyone needs to touch - but it also affords a lot of other benefits.

This post isn't about all those details, but this is what an entity file looks like inside. Aha - we have found our modifiers!

A big goal with luxe is that all content is human friendly even if generated or editor created. Very often I tweak content without opening the editor as it's really easy to do so. It's easy to search and replace and so on.

This allows a lot of flexibility and custom scripting to happen as well, all using the intrinsic tools available in luxe. SO many times we've generated entities from blender, automated conversions, and plenty more because the format is really easy to do that kinda thing with. This is key!

Loading a scene

This is what it currently looks like to load a scene in code (an alias, Scene.load exists for clarity btw):

What does the variable scene contain?

The return value is actually an Entity!

More specifically, it returns the scene root. The scene root is an entity typically with a transform attached. This means you can attach modifiers to the scene itself, which is often handy for systems that manage the world.

When loading a scene, it also looks at any entities with a Transform, that aren't linked to anything else, and links them to the scene. This creates the expected behavior that we'd want - when you move the scene root using regular Transform - everything under it that is attached will follow.

This property is especially important for Prototypes, as we treat the contents as a single unit more often than not.

Scene Concepts

Scenes have some important properties worth mentioning as they exist for clarity of workflow, and clear expectations - these properties are intentional!

  • A scene can only be loaded into the same world, once
  • Multiple scenes can be loaded at any time, making them modular
  • Scenes have a script that follows the lifetime of the scene
  • The scene root is an entity, so destroying that root will unload the rest

Bonus image!

Scene are a tool

like most things in luxe...

Scene script

Mentioned above, the lifetime of the scene is typically a really useful boundary for when certain things should be running... And often times we'll have scene specific code that JUST needs to exist in this ONE area.

This is a big part of why scene scripts exist, they are a really good way to decouple one-off code cases from main systems and keep nuance separated. e.g We'll never have if(area == "area1") inside Door modifier, instead we handle the specific checks local to the scene inside the scene script.

A menu? Just a scene would work. Load it into the ui world, keep it resident there. Implement the menu code in the scene script. Hook up the ui buttons to the scene script via wires. This is how we do it in our game.

Like with modifiers, if you make a blank scene.wren it'll be populated for you with the following template:

Another reason this is useful, is for storing shared systems or logic. We can layer scenes like this because we have ...

Scene stacking

Scenes are a versatile tool, there's no one way to use them. There are however many cases where they make sense for the task, like if you're making a game with distinct levels like a puzzle game or platformer, they're a perfect fit.

But since they're just a tool, we can use them for other workflows.

If you have a tutorial inside an area of the game you'll spend time in or return to - we have scene/areas/area1 and scene/areas/area1.tutorial. We load both of those up the first time you play, and if you opt out of the tutorial, just don't load the second part. Or if you're returning, skip it.

Another concrete example is when making our game Mossfield Archives, we don't have to load in a really heavy scene just to tweak some camera triggers. I don't have to wait for long load times just to iterate on my corner of the world.

In game, we can load in any scenes on demand, like if the player enters a trigger, load the next part only if relevant. Here's an example from the intro area in archives, but only the first time through, opened in editor.

And one other example mentioned above - shared systems. If I'm making a content gym or test area for the game to iterate on game design, I don't need the entire world. I can make a tiny room, and load the foundations of the game into it, and then spawn just what I need in my own space.

This also is true for "persistent systems", like manager systems, or even the player. Often I'll load the player from a scene once off at the start of the game, and just teleport them around when changing levels. The player state is always resident that way and not caught up in unloading the world.

Needless to say there's no shortage of helpful ways to use them as a tool. If we're often dealing with multiple scenes, we'd also often want to open a group of scenes as one right?

Stage assets

For now we call this concept a stage. It is a very simple asset, it's just an array of scene references! When you load a stage, it loads all the scenes asked to. This is true in the editor as well, so you can make your own stages for your own iteration for common needs.

Scene contents

So a scene contains entity assets, one per entity, what does it look like on disk? It's just a folder!

If we have a scene called level1, on disk it is known as scene/level1.scene/. Inside this folder we keep the root entity definition, the scene script, and entities within that scene. You can also have folders inside of them (shown below in editor), which is how you'd group and organize the entities within it.

Here's what the entity assets look like inside a scene:

And here's a complete simple example scene from our game that manages fade in/out. It is resident and will draw a black screen sized rectangle over everything. Here's what it looks like on disk. We can see the scene root entity (.scene.lx) and we can see the scene.wren our scene script.

Prototypes

So scenes can only load into the same world once - what if you want to create an instance of something repeatedly? We'll that's what a Prototype is for. This is often called a prefab or similar, the idea is the same - it's a container of entities - but these can be spawned repeatedly.

A Prototype looks exactly like a scene on disk, it's a folder, contains entities, and is named (unsurprisingly) with a .prototype extension, like pickup.prototype/. They also return a root entity, and like with scenes, destroying the root entity takes down the rest. They also link transforms so they move as one.

We call an instance of a Prototype, an instance! Here's an example of one created inside of a scene:

Nesting + overrides

One very important difference from scenes, though, is that you can place a Prototype inside of another Prototype. This makes Prototypes different from scenes by design, as they are often used for creating a sort of blueprint of a thing you create multiple instances of (vs a scene, which are conceptually singular for clarity).

You'll also notice, that we have override files in here. When you spawn an instance of a Prototype, you can customize it. This is true if it's inside a scene, or inside another Prototype. This makes them handle variants pretty well too. When you reset a value in the editor, it resets to the Prototype (instead of the default for the field). Nothing surprising!

In our game we have a shared implementation of a character, but we customize each one to be specific. This is an example below: Andie is a character that customizes the avatar Prototype to be a distinct version of it, say by changing what animations will be fed into the blend graph for locomotion.

Another example from our other game Mossfield Origins is buildings, each building is a Prototype with a building nested inside it, and then the Prototype contains the actual visuals and modifiers for the distinct nature of it while still being fundamentally a building.

The other key factor of Prototypes, is they they're connected to the original version. If you change the Prototype, all instances of it will be changed unless they override it. This is obviously important for building games!

Entity Templates

There's one special case type of Prototypes that is important - we call them entity templates. These are created much like a Prototype would be but with one key difference: they cannot have other entities, just the root entity.

When they are created in the world, they copy the single entity into place instead, so no links to the original.

It's extremely common to have one shot style entities that are ready to go, but not really need them to be linked to a context or nestable - we just want to treat them as something we create in less clicks. This is an entity template.

Some obvious examples: a Sprite template - these include a Sprite, Transform and Tags so that as a new user I can make a sprite in one click. Or a text object in the world via the text template.

Some examples from our games: A sphere trigger. It comes prepared with the trigger pre-configured, the collider, as well as wires, so I can immediately connect it to a receiver. We also have stuff like dialog triggers, interactables, and so on. They speed up workflows!

Entity Contexts

And finally, an honorable mention in passing is the context concept that is shared by Scenes and Prototypes. For example, you can ask an entity what context it belongs to Entity.get_context(entity: Entity) : Entity - this will return the context responsible for creating the entity directly.

You can also ask for Entity.get_context_origin(entity: Entity) - this is the very top level context that is responsible for instantiating it indirectly. e.g the Scene is the origin, but the parent Prototype is the context. The tree is walkable, since you can nest Prototypes, it looks like origin -> context -> context -> context -> entity.

You can also query contexts. If you spawn a Scene or Prototype, you can pull specific entities out directly (if you want to) and a variety of other tools:

The context serves a lot of purposes, including addressing distinct entities via addresses in data and a lot more. This is more for documentation than intro posts, so now you know!

Bonus

Next time ... projects

We've created entities, we've made modifiers, we've stored them in scenes. The final part of what is it like to work in luxe is about projects, what they look like in practice.

Part 3: fin

Our journey in seeing what it looks like to use luxe continues! Below are links to the previous and next post in this series:

Join the luxe community

Get the latest news

All posts in this series:

dev log #11 - modifiers
Hello friends! As we start to wrap up for wider release we’ve got plenty to talk about. In the next few posts we’re gonna explore what it feels like and looks like to use luxe to make games, in concrete detail, so get a cozy seat and we’ll talk about
dev log 12 - custom modifiers
Hello again! As we start to wrap up for wider release we’ve got plenty to talk about - this is part 2 exploring what it feels like and looks like to use luxe to make games, in concrete detail, so get a cozy seat and we’ll talk even more about
dev log 13 - scenes
We’re back again, and as we start to wrap up for wider release we’ve got plenty to talk about - this is part 3 exploring what it feels like and looks like to use luxe to make games, in concrete detail. Get yet another cozy seat and see how Scenes,
dev log 14 - projects
Hello, Hi! as we start to wrap up for wider release we’ve got plenty to talk about - this is part 4, the final part for now exploring what it feels like and looks like to use luxe to make games, in concrete detail. Find another cozy seat and see