-
-
Notifications
You must be signed in to change notification settings - Fork 103
Prefabs
Status: In Progress
Each component will need a method called serialize, which serializes the component into plain data, which can be converted to JSON
For example for pos, it would serialize the position, rotate the angle:
add([pos(0, 100), rotate(90), sprite("bean")]).serialize();would serialize its components so you get
{
components: {
pos: { pos: { x: 0, y: 100 },
angle: { angle: 90 },
sprite: { sprite: "bean" },
}
}Note
Components serialized data should always be the most verbose possible pos: { pos: { x: 0, y: 100 } } instead of pos: { x: 0, y: 100 } makes easy later serialize future pos component data
We register a function that deserializes the component using its data:
registerFactory("pos", data => { return pos(data.pos); });
registerFactory("rotate", data => { return rotate(data.angle); });so addPrefab(data) will read all fields, finds "pos", calls the factory method and passes data["pos"], thus obtaining the component and adding it to a list and finally returns add(list).
When calling serialize on an object, it will serialize all its components, as well as its children
obj = add([pos(100, 100)]);
obj.add([pos(0, 100), rotate(90), sprite("bean")]);
obj.serialize()Would give
{
pos: {x: 100, y: 100},
children: [
{
pos: {x: 0, y: 100},
rotate: { angle: 90 },
sprite: { sprite: "bean" }
}
]
}Children are serialized and placed in a field called "children".
{
components: {
pos: { pos: { x: 0, y: 100 } },
rotate: { angle: 90 },
sprite: { sprite: "bean" },
},
children: [
{
components: {
pos: { pos: { x: 0, y: 100 } },
rotate: { angle: -90 },
sprite: { sprite: "cat" }
}
}
]
}Tags are serialized in a tag field.
{
components: {
pos: { pos: { x: 0, y: 100 } },
rotate: { angle: 90 },
sprite: { sprite: "bean" },
},
tags: ["bean"]
}loadPrefab(name, uri);Loads an object hierarchy serialized and converted to json and converts it to javascript data in order to use it as deserialization data for a prefab.
addPrefab(name | data)
GameObj.addPrefab(name | data)Adds a prefab by deserializing all the objects, and returns the new root object of the prefab.
addPrefab(name | data, Comp[])
GameObj.addPrefab(name | data, Comp[])Advanced usage, in order to customize a prefab
addPrefab("hexagon", [pos(200, 200), color(BLUE)]);Note
An object added as a prefab, will serialize as a prefab or modified prefab. It retains its prefab-ness. This means that if the prefab is modified, by repositioning it for example, only a reference to the prefab and the new position is stored when serializing. (We may need to add an option to "flatten" the object at creation if this behavior would not be desired).
{
prefab: "hexagon",
pos: { x: 0, y: 100 }
}If a prefab has children nodes, for which some are modified, we may store these modifications as follows
{
prefab: "hexagon",
pos: { x: 0, y: 100 },
children: [
{}, // no change
{ color: { 255, 0, 255 } }
]
}However, if the prefab would be modified to have a different amount of children, or the order changes, this wouldn't work. It may therefore be better to use named objects.
createPrefab(obj)Serializes the object and its children and returns javascript data.
createPrefab(name, obj)Serializes the object and its children, registers the prefab as asset and returns javascript data.
{
"info": {
"name": "Hexagon",
"creator": "Amy",
"exporter": "KAPLAYGROUND"
},
"data": {
"components": {
"color" : { "color": {"r": 255, "g": 255, "b": 255} },
"anchor" : { "anchor": "center" },
"polygon": { "pts": [] }
},
"tags": ["Goodbye", "Hello"],
"children": [
{
"components": {
"color" : { "color": {"r": 255, "g": 255, "b": 255} },
"anchor" : {"anchor": "center"},
"sprite" : { "sprite": "kat" }
},
"tags": ["Goodbye", "Hello"]
}
]
}
}When a game or scene is saved, all assets are saved too.
{
"info": {
"name": "Hexagon game",
"creator": "Amy",
"exporter": "KAPLAYGROUND"
},
"assets": {
"sprite": [
{ "name": "bean", "uri": "sprites/bean.png" },
{ "name": "kat", "uri": "sprites/kat.png" }
],
"canvas": [
{ "name": "canvas", "width": 320, "height": 200 }
],
"prefab" : [
{ "name": "hexagon", "uri": "prefabs/hexagon.kaprefab" }
]
}
"data": {
"components": {
"color" : { "color": {"r": 255, "g": 255, "b": 255} },
"anchor" : { "anchor": "center" },
"polygon": { "pts": [] }
"drawon" : { "canvas": "canvas" }
},
"tags": ["Goodbye", "Hello"],
"children": [
{
"components": {
"color" : { "color": {"r": 255, "g": 255, "b": 255} },
"anchor" : {"anchor": "center"},
"sprite" : { "sprite": "kat" }
},
"tags": ["Goodbye", "Hello"]
},
{
"prefab" : { "name": "hexagon" },
"components": {
"color" : { "color": {"r": 255, "g": 255, "b": 255} },
"anchor" : {"anchor": "center"},
},
"tags": ["Goodbye", "Hello"]
}
]
}
}In order to serialize custom behavior, you need to add a custom named component with a serialize method. For example, a state component's events can be initializes in the add event callback of a custom component.
function enemy() {
id: "enemy",
add() {
const player = get("player");
this.onStateEnter("attack", () =>
{
this.play("attackAnim", {
onEnd: () => this.enterState("idle", rand(1, 3)),
});
checkHit(this, player);
});
this.onStateEnter("idle", (time) =>
{
this.play("idleAnim");
wait(time, () =>
this.enterState("move"));
});
this.onStateUpdate("move", () => {
this.follow(player);
if (this.pos.dist(player.pos) < 16) {
this.enterState("attack");
}
});
},
serialize() {
return {};
}
}
registerFactory("enemy", data => { return enemy(); });
const enemyObj = add([
pos(80, 100),
sprite("robot"),
state("idle", ["idle", "attack", "move"]),
enemy()
]);
createPrefab("enemy", enemyObj);- References to textures (for uvquad, particles).
-
Event callbacks-> use custom components - Customizing prefab children from addPrefab. For example using
addPrefab("button", [pos(200, 50)], {"button_text": [text("Options")]})to customize the text on child called button_text. Or
addPrefab("button", { children: { "0": [text("Options")] } });by index.
- If a file called enemy.js or enemy.ts in kaplayground is created, exporting a component method and factory, add it to the "add component" menu.
- Scene behavior. Serialized object behavior can be customized using components, but what about global events? We could use object scoped global events, and use components on said object, but isn't there a better way?
