Description
Problem
The current code for level serialization is messy and not comfortable to use (involves a lot of hacks and tricks, see levelparse.js) and doesn't allow for extension (if a new game version will release, we would have to go through a lot of steps to adapt for the new content).
Solution
I propose a cleaner architecture that benefits from the use of TypeScript that can be easily extended and composed, if needed (GD's level format involves a lot of composition, for example trigger properties). The idea is to implement an abstract GDObject
class that has GDProperty
inherited properties (Vector2
, ZLayer
) as well as serialize()
abstract method.
GDObject
As mentioned previously, GDObject
is an abstract class with ZLayer
and Vector2
fields and an abstract serialize()
method. This is how it could look in TypeScript code:
abstract class GDObject {
public position: Vector2;
public zLayer: ZLayer;
public constructor(position: Vector2, zLayer: ZLayer) {
this.position = position;
this.zLayer = zLayer;
}
abstract serialize(): string;
}
Then, it gets inherited by GDBlock
and GDTrigger
classes that implement the abstract serialize()
method, that will be explained later.
GDProperty
Just like GDObject
, GDProperty
is an abstract class, but it only defines a single abstract serialize()
method.
Here's how it can look in code:
abstract class GDProperty {
abstract serialize(): string;
}
As mentioned previously, Vector2
and ZLayer
classes extend a GDProperty
, and are used as properties of GDObject
.
Vector2
Pretty obvious, its a two component structure with X and Y coordinates. This is how it can be implemented:
class Vector2 extends GDProperty {
public x: number;
public y: number;
public constructor(x: number, y: number) {
super();
this.x = x;
this.y = y;
}
serialize(): string {
// do the actual serialization to the GD key/value format.
return "";
}
}
It can also implement other methods, for example dot()
or length()
, if we will need them.
ZLayer
Again, its in the name. It only contains a number value index
:
class ZLayer extends GDProperty {
public index: number;
public constructor(index: number) {
super();
this.index = index;
}
serialize(): string {
// do the actual serialization to the GD key/value format.
return "";
}
}
And so on, for every property type we'd like to have.
GDTrigger
Triggers are interesting ones as OOP approach will render them pretty messy. This is why I think we could compose GDProperty
together in a properties
array.
class GDTrigger extends GDObject {
private properties: GDProperty[];
public constructor(position: Vector2) {
super(position);
}
public addProperty(property: GDProperty) {
this.properties.push(property);
}
serialize(): string {
let result: string;
this.properties.forEach(property => {
result += property.serialize();
});
return result;
}
}
GDBlock
Extends GDObject
but adds properties like color, etc. needed for a block.
In practice
In the actual editor backend the level will look like an array of GDObject
, and when its time to save the level in GD's format it will be pretty easy to do so:
function serializeLevel(): void {
let result: string;
objects.forEach(object => {
result += object.serialize();
});
}
Benefits
With this approach, its trivial to add more types of objects and properties, resulting in much cleaner code. However, we should also consider that level format might change, so we should somehow combat that as well.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status