Scene and Entity Serialization
Currently, when working with Phatty, you probably maintain models next to your entities which hold initial data, state or configuration, such as:
class Ball {
constructor(public x: number, public y: number) {}
}
and use these models to build a scene:
const ball = new Ball(10, 20)
const ballEntity = this.entities.create()
ballEntity.components.add(TransformComponent, ball.x, ball.y)
It would be great to be able to serialize and deserialize (i.e. save and load) certain/all entities of a scene and let phatty do the job of setting up a scene once (e.g. in a level designer), saving that state and loading the state later:
// load the initial state of a scene
const level = scene.entities.load(serializedScene)
// later, save the game state
const savegame = scene.entities.save()
// or make a prefab
const prefab = ballEntity.save()
// load a prefab
scene.entities.add(prefab)
On top of that, serialization would allow a proper visual entity editor.
How would that work?
This issue is a first sketch of the public facing API and some thoughts about how to get there.
Internally, we need a place where all used components are stored. You may register your components with a defineComponents function:
import { defineComponents } from 'phatty'
defineComponents({
TransformComponent,
EnemyComponent,
PathfindingComponent
})
The Component class would need an overhaul. In the style of Unity, public properties which are of a certain type (numbers and strings first? or properties marked as serializable with a @serialize class property decorator? bring your own serializer?) are serialized, meaning this is how a TransformComponent would look like:
import { Component } from 'phatty'
export class TransformComponent extends Component {
@serialize()
public x = 0
@serialize()
public y = 0
public container!: Phaser.GameObjects.Container
create() {
this.container = this.entity.scene.add.container(this.x, this.y)
}
public destroy(): void {
this.container.destroy()
}
}
We can serialize this (roughly) as follows:
const constructor = getConstructorFromComponentMap(transformComponentInstance)
// → 'TransformComponent'
const data = {}
Object.keys(serializableKeysOfConstructor(constructor)).forEach((key) => {
data[key] = serialize(transformComponentInstance[key])
})
// → { x: 0, y: 0 }
Internally, a serialized version of this would be:
const serializedComponent = {
constructor: 'TransformComponent', // the key in the component map
data: {
x: 0,
y: 0,
}
}
and it would be loaded like this:
const componentInstance = new componentMap[serializedComponent.constructor]()
Object.entries(serializedComponent).forEach(([key, value]) => {
componentInstance[key] = deserialize(value)
})
The serialization of an entity is just an array of serialized components:
{
"components": [
{
"constructor": "TransformComponent",
"data": {
"x": 0,
"y": 0
}
},
{
"constructor": "RigidBodyComponent",
"data": {
"shape": "circle",
"radius": 35
}
}
]
}
Now because we cannot really make use of constructor arguments, a constructor is not allowed in components and create is the new constructor (as seen above); all public properties have been assigned at this point. This isn't the best DX but it's as good as it gets.
Now iterating over all entities of a scene and serializing all components of each entity gives us a proper scene representation. Iterating over a single entity and serializing that outputs a prefab, neat!
Visual editing
Now that we know how to create entities including components and their data, we can make use of that and offer visual editing in the style of a scene outline showing all entities and an inspector, offering an editing experience just like the unity editor which allows you to create entities, add components to them and edit the public/serialized properties of a component. It's much work for sure but serialization is the first step towards that.
Scene and Entity Serialization
Currently, when working with Phatty, you probably maintain models next to your entities which hold initial data, state or configuration, such as:
and use these models to build a scene:
It would be great to be able to serialize and deserialize (i.e. save and load) certain/all entities of a scene and let phatty do the job of setting up a scene once (e.g. in a level designer), saving that state and loading the state later:
On top of that, serialization would allow a proper visual entity editor.
How would that work?
This issue is a first sketch of the public facing API and some thoughts about how to get there.
Internally, we need a place where all used components are stored. You may register your components with a
defineComponentsfunction:The
Componentclass would need an overhaul. In the style of Unity, public properties which are of a certain type (numbers and strings first? or properties marked as serializable with a@serializeclass property decorator? bring your own serializer?) are serialized, meaning this is how aTransformComponentwould look like:We can serialize this (roughly) as follows:
Internally, a serialized version of this would be:
and it would be loaded like this:
The serialization of an entity is just an array of serialized components:
{ "components": [ { "constructor": "TransformComponent", "data": { "x": 0, "y": 0 } }, { "constructor": "RigidBodyComponent", "data": { "shape": "circle", "radius": 35 } } ] }Now because we cannot really make use of constructor arguments, a constructor is not allowed in components and
createis the new constructor (as seen above); all public properties have been assigned at this point. This isn't the best DX but it's as good as it gets.Now iterating over all entities of a scene and serializing all components of each entity gives us a proper scene representation. Iterating over a single entity and serializing that outputs a prefab, neat!
Visual editing
Now that we know how to create entities including components and their data, we can make use of that and offer visual editing in the style of a scene outline showing all entities and an inspector, offering an editing experience just like the unity editor which allows you to create entities, add components to them and edit the public/serialized properties of a component. It's much work for sure but serialization is the first step towards that.