Scenes and prefabs
A scene is a whole world kept in a file: a level, a menu, a test
setup. A prefab is one entity’s components, kept in a file and spawned
as many times as you like: a tree, an enemy, a building. Both live in
assets/, both are JSON (so they diff well in git), and the editor,
agents and your own code write them like any other file.
#![allow(unused)]
fn main() {
fn beach(ctx: &mut Ctx) -> Result<(), String> {
ctx.world.reflect::<Palm>(); // components in files must be reflected
ctx.load_scene("levels/beach.json")?; // the level: its entities, ids kept
for i in 0..3 {
// three more palms, all alike, in a row
ctx.spawn_prefab("prefabs/palm.json", vec2(400.0 + i as f32 * 64.0, 400.0))?;
}
Ok(())
}
}
struct Palm { float height; };
static void beach(crabby::ctx& ctx) {
ctx.world().reflect<Palm>({crabby::field("height", &Palm::height)}); // components in files must be reflected
ctx.load_scene("levels/beach.json"); // the level: its entities, ids kept
for (int i = 0; i < 3; ++i) // three more palms, all alike, in a row
ctx.spawn_prefab("prefabs/palm.json", {400.0f + float(i) * 64, 400});
}
load_scenereplaces the world with the scene’s entities, which keep their ids, so components that refer to other entities still point at the right ones. Resources that are reflected load too.spawn_prefabputs the prefab’s position at the point you give and keeps its saved rotation and scale. A prefab without aTransform2Dgets one. The file is read once, then kept in memory, so spawning a thousand trees reads it once.- Only reflected components go in files: reflect your
types before loading or saving.
Transform2D,Spriteand the physics components are reflected already. A sprite names its image ("texture": "crab.png"), and loading the scene or prefab loads it. With 3D on,Transform3DandModelare reflected too: a model names its mesh’s glTF file ("mesh": "tree.glb"), loaded the same way. Scenes can also come from Unity (Importing from Unity). - Errors say what’s wrong and change nothing: a missing file lists the folders searched, and a component that isn’t reflected is named.
Saving
The inspector’s editor saves and loads scenes and places prefabs with the mouse. From code:
save_scene(path) writes the world (its reflected components and
resources) and save_prefab(entity, path) writes one entity, without its
position. Both write over the file in assets/ if it’s there, else create
it (and its folders). Web builds can’t save files.
#![allow(unused)]
fn main() {
ctx.save_scene("levels/beach.json")?;
ctx.save_prefab(palm, "prefabs/palm.json")?;
}
C++: ctx.save_scene(path) and ctx.save_prefab(e, path), which throw on
errors like the rest of the wrapper. C: crabby_ctx_load_scene,
crabby_ctx_save_scene, crabby_ctx_spawn_prefab and
crabby_ctx_save_prefab.
The files
A scene is the save format of world.save():
{
"format": "crabby-world",
"version": 1,
"entities": [
{ "entity": 0, "components": { "Transform2D": { "position": [0.0, 400.0] }, "Palm": { "height": 3.0 } } },
{ "entity": 1, "components": { "Transform2D": { "position": [200.0, 380.0] }, "Palm": { "height": 5.0 } } }
]
}
A prefab lists one entity’s components:
{
"format": "crabby-prefab",
"version": 1,
"components": {
"Transform2D": { "rotation": 0.1 },
"Palm": { "height": 4.0 }
}
}
Fields left out take their defaults (here the palm’s position and scale). Prefabs are single entities for now: a prefab can’t hold children.