refactor: less magic
This commit is contained in:
parent
9bae378ac7
commit
45cb158f2a
|
@ -1,3 +1,7 @@
|
|||
export default {
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class Animation extends Component {
|
||||
static properties = {
|
||||
frame: {type: 'uint16'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
export default {
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class AreaSize extends Component {
|
||||
static properties = {
|
||||
x: {type: 'uint16'},
|
||||
y: {type: 'uint16'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
export default {
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class Camera extends Component {
|
||||
static properties = {
|
||||
x: {type: 'uint16'},
|
||||
y: {type: 'uint16'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
export default {
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class Controlled extends Component {
|
||||
static properties = {
|
||||
locked: {type: 'uint8'},
|
||||
moveUp: {type: 'float32'},
|
||||
moveRight: {type: 'float32'},
|
||||
|
@ -6,3 +9,4 @@ export default {
|
|||
moveLeft: {type: 'float32'},
|
||||
changeSlot: {type: 'int8'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
export default {
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class Direction extends Component {
|
||||
static properties = {
|
||||
direction: {type: 'uint8'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
export default {
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class Ecs extends Component {
|
||||
static properties = {
|
||||
path: {type: 'string'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import Schema from '@/ecs/schema.js';
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default function(Component) {
|
||||
return class Emitter extends Component {
|
||||
export default class Emitter extends Component {
|
||||
mergeDiff(original, update) {
|
||||
const merged = {};
|
||||
if (update.emit) {
|
||||
|
@ -23,9 +22,4 @@ export default function(Component) {
|
|||
}
|
||||
};
|
||||
}
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: {},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1 +1,3 @@
|
|||
export default {};
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class Engine extends Component {}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
export default {
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class Forces extends Component {
|
||||
static properties = {
|
||||
forceX: {type: 'float32'},
|
||||
forceY: {type: 'float32'},
|
||||
impulseX: {type: 'float32'},
|
||||
impulseY: {type: 'float32'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
export default {
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class Health extends Component {
|
||||
static properties = {
|
||||
health: {type: 'uint32'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,37 +1,14 @@
|
|||
import Component from '@/ecs/component.js';
|
||||
import Schema from '@/ecs/schema.js';
|
||||
import gather from '@/util/gather.js';
|
||||
|
||||
const specificationsAndOrDecorators = gather(
|
||||
const Gathered = gather(
|
||||
import.meta.glob('./*.js', {eager: true, import: 'default'}),
|
||||
);
|
||||
|
||||
const Components = {};
|
||||
for (const componentName in specificationsAndOrDecorators) {
|
||||
// TODO: byKey, byId, ...
|
||||
if (Number.isInteger(+componentName)) {
|
||||
continue;
|
||||
}
|
||||
const specificationOrDecorator = specificationsAndOrDecorators[componentName];
|
||||
if ('function' === typeof specificationOrDecorator) {
|
||||
Components[componentName] = specificationOrDecorator(
|
||||
class Decorated extends Component {
|
||||
for (const componentName in Gathered) {
|
||||
Components[componentName] = class Named extends Gathered[componentName] {
|
||||
static componentName = componentName;
|
||||
}
|
||||
);
|
||||
if (!Components[componentName]) {
|
||||
throw new Error(`Component ${componentName} decorator returned nothing`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Components[componentName] = class WrappedComponent extends Component {
|
||||
static componentName = componentName;
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: specificationOrDecorator,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default Components;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import Schema from '@/ecs/schema.js';
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default function(Component) {
|
||||
return class Inventory extends Component {
|
||||
export default class Inventory extends Component {
|
||||
insertMany(entities) {
|
||||
for (const [id, {slotChange}] of entities) {
|
||||
if (slotChange) {
|
||||
|
@ -95,9 +94,7 @@ export default function(Component) {
|
|||
};
|
||||
return Instance;
|
||||
}
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: {
|
||||
static properties = {
|
||||
slots: {
|
||||
type: 'map',
|
||||
value: {
|
||||
|
@ -108,7 +105,5 @@ export default function(Component) {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
export default {};
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class MainEntity extends Component {}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import Schema from '@/ecs/schema.js';
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default function(Component) {
|
||||
return class Wielder extends Component {
|
||||
export default class Position extends Component {
|
||||
instanceFromSchema() {
|
||||
const Instance = super.instanceFromSchema();
|
||||
const Component = this;
|
||||
|
@ -18,12 +17,8 @@ export default function(Component) {
|
|||
});
|
||||
return Instance;
|
||||
}
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: {
|
||||
static properties = {
|
||||
x: {type: 'float32'},
|
||||
y: {type: 'float32'},
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export default {};
|
|
@ -1,7 +1,6 @@
|
|||
import Schema from '@/ecs/schema.js';
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default function(Component) {
|
||||
return class Sound extends Component {
|
||||
export default class Sound extends Component {
|
||||
mergeDiff(original, update) {
|
||||
const merged = {};
|
||||
if (update.play) {
|
||||
|
@ -21,9 +20,4 @@ export default function(Component) {
|
|||
}
|
||||
};
|
||||
}
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: {},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
export default {
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class Speed extends Component {
|
||||
static properties = {
|
||||
speed: {type: 'float32'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import Component from '@/ecs/component.js';
|
||||
|
||||
import vector2d from "./helpers/vector-2d";
|
||||
export default {
|
||||
|
||||
export default class Sprite extends Component {
|
||||
static properties = {
|
||||
anchor: vector2d('float32', {x: 0.5, y: 0.5}),
|
||||
animation: {type: 'string'},
|
||||
elapsed: {type: 'float32'},
|
||||
|
@ -8,3 +12,4 @@ export default {
|
|||
source: {type: 'string'},
|
||||
speed: {type: 'float32'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import Schema from '@/ecs/schema.js';
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default function(Component) {
|
||||
return class Ticking extends Component {
|
||||
export default class Ticking extends Component {
|
||||
instanceFromSchema() {
|
||||
const Instance = super.instanceFromSchema();
|
||||
|
||||
|
@ -34,11 +33,7 @@ export default function(Component) {
|
|||
}
|
||||
return Instance;
|
||||
}
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: {
|
||||
static properties = {
|
||||
isTicking: {defaultValue: 1, type: 'uint8'},
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import Component from '@/ecs/component.js';
|
||||
|
||||
import vector2d from './helpers/vector-2d';
|
||||
|
||||
import Schema from '@/ecs/schema.js';
|
||||
|
||||
export default function(Component) {
|
||||
return class TileLayers extends Component {
|
||||
export default class TileLayers extends Component {
|
||||
insertMany(entities) {
|
||||
for (const [id, {layerChange}] of entities) {
|
||||
if (layerChange) {
|
||||
|
@ -86,9 +85,7 @@ export default function(Component) {
|
|||
};
|
||||
return Instance;
|
||||
}
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: {
|
||||
static properties = {
|
||||
layers: {
|
||||
type: 'array',
|
||||
subtype: {
|
||||
|
@ -106,7 +103,5 @@ export default function(Component) {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export default {};
|
|
@ -1,6 +1,10 @@
|
|||
export default {
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default class VisibleAabb extends Component {
|
||||
static properties = {
|
||||
x0: {type: 'float32'},
|
||||
x1: {type: 'float32'},
|
||||
y0: {type: 'float32'},
|
||||
y1: {type: 'float32'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export default {};
|
|
@ -1,7 +1,6 @@
|
|||
import Schema from '@/ecs/schema.js';
|
||||
import Component from '@/ecs/component.js';
|
||||
|
||||
export default function(Component) {
|
||||
return class Wielder extends Component {
|
||||
export default class Wielder extends Component {
|
||||
instanceFromSchema() {
|
||||
const Instance = super.instanceFromSchema();
|
||||
const Component = this;
|
||||
|
@ -66,11 +65,7 @@ export default function(Component) {
|
|||
}
|
||||
return Instance;
|
||||
}
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: {
|
||||
static properties = {
|
||||
activeSlot: {type: 'uint16'},
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,12 +7,8 @@ export default class Component {
|
|||
Instance;
|
||||
map = {};
|
||||
pool = [];
|
||||
serializer;
|
||||
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: {},
|
||||
});
|
||||
static properties = {};
|
||||
static $$schema;
|
||||
|
||||
constructor(ecs) {
|
||||
this.ecs = ecs;
|
||||
|
@ -41,7 +37,8 @@ export default class Component {
|
|||
createMany(entries) {
|
||||
if (entries.length > 0) {
|
||||
const allocated = this.allocateMany(entries.length);
|
||||
const keys = Object.keys(this.constructor.properties);
|
||||
const {properties} = this.constructor.schema.specification;
|
||||
const keys = Object.keys(properties);
|
||||
for (let i = 0; i < entries.length; ++i) {
|
||||
const [entityId, values = {}] = entries[i];
|
||||
this.map[entityId] = allocated[i];
|
||||
|
@ -51,7 +48,7 @@ export default class Component {
|
|||
}
|
||||
for (let k = 0; k < keys.length; ++k) {
|
||||
const j = keys[k];
|
||||
const {defaultValue} = this.constructor.properties[j];
|
||||
const {defaultValue} = properties[j];
|
||||
if (j in values) {
|
||||
this.data[allocated[i]][j] = values[j];
|
||||
}
|
||||
|
@ -64,7 +61,7 @@ export default class Component {
|
|||
}
|
||||
|
||||
deserialize(entityId, view, offset) {
|
||||
const {properties} = this.constructor;
|
||||
const {properties} = this.constructor.schema.specification;
|
||||
const instance = this.get(entityId);
|
||||
const deserialized = this.constructor.schema.deserialize(view, offset);
|
||||
for (const key in properties) {
|
||||
|
@ -92,9 +89,10 @@ export default class Component {
|
|||
}
|
||||
|
||||
static filterDefaults(instance) {
|
||||
const {properties} = this.schema.specification;
|
||||
const json = {};
|
||||
for (const key in this.properties) {
|
||||
const {defaultValue} = this.properties[key];
|
||||
for (const key in properties) {
|
||||
const {defaultValue} = properties[key];
|
||||
if (key in instance && instance[key] !== defaultValue) {
|
||||
json[key] = instance[key];
|
||||
}
|
||||
|
@ -131,15 +129,15 @@ export default class Component {
|
|||
|
||||
instanceFromSchema() {
|
||||
const Component = this;
|
||||
const {specification} = Component.constructor.schema;
|
||||
const Instance = class {
|
||||
$$entity = 0;
|
||||
constructor() {
|
||||
this.$$reset();
|
||||
}
|
||||
$$reset() {
|
||||
const {properties} = Component.constructor;
|
||||
for (const key in properties) {
|
||||
const {defaultValue} = properties[key];
|
||||
for (const key in specification.properties) {
|
||||
const {defaultValue} = specification.properties[key];
|
||||
this[`$$${key}`] = defaultValue;
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +155,7 @@ export default class Component {
|
|||
this.$$reset();
|
||||
},
|
||||
};
|
||||
for (const key in Component.constructor.properties) {
|
||||
for (const key in specification.properties) {
|
||||
properties[key] = {
|
||||
get: function get() {
|
||||
return this[`$$${key}`];
|
||||
|
@ -182,8 +180,14 @@ export default class Component {
|
|||
return {...original, ...update};
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return this.schema.specification.properties;
|
||||
static get schema() {
|
||||
if (!this.$$schema) {
|
||||
this.$$schema = new Schema({
|
||||
type: 'object',
|
||||
properties: this.properties,
|
||||
});
|
||||
}
|
||||
return this.$$schema;
|
||||
}
|
||||
|
||||
serialize(entityId, view, offset) {
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
import {expect, test} from 'vitest';
|
||||
|
||||
import Schema from './schema.js';
|
||||
import Component from './component.js';
|
||||
|
||||
test('creates instances', () => {
|
||||
class CreatingComponent extends Component {
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: {foo: {defaultValue: 'bar', type: 'string'}},
|
||||
});
|
||||
static properties = {
|
||||
foo: {defaultValue: 'bar', type: 'string'},
|
||||
};
|
||||
}
|
||||
const ComponentInstance = new CreatingComponent();
|
||||
ComponentInstance.create(1);
|
||||
|
@ -18,10 +16,9 @@ test('creates instances', () => {
|
|||
|
||||
test('does not serialize default values', () => {
|
||||
class CreatingComponent extends Component {
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: {foo: {defaultValue: 'bar', type: 'string'}, bar: {type: 'uint8'}},
|
||||
});
|
||||
static properties = {
|
||||
foo: {defaultValue: 'bar', type: 'string'}, bar: {type: 'uint8'},
|
||||
};
|
||||
}
|
||||
const fakeEcs = {markChange() {}};
|
||||
const ComponentInstance = new CreatingComponent(fakeEcs);
|
||||
|
@ -35,10 +32,9 @@ test('does not serialize default values', () => {
|
|||
|
||||
test('reuses instances', () => {
|
||||
class ReusingComponent extends Component {
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: {foo: {type: 'string'}},
|
||||
});
|
||||
static properties = {
|
||||
foo: {type: 'string'},
|
||||
};
|
||||
}
|
||||
const ComponentInstance = new ReusingComponent();
|
||||
ComponentInstance.create(1);
|
||||
|
|
|
@ -2,26 +2,22 @@ import {expect, test} from 'vitest';
|
|||
|
||||
import Component from './component.js';
|
||||
import Ecs from './ecs.js';
|
||||
import Schema from './schema.js';
|
||||
import System from './system.js';
|
||||
|
||||
function wrapSpecification(name, specification) {
|
||||
function wrapProperties(name, properties) {
|
||||
return class WrappedComponent extends Component {
|
||||
static componentName = name;
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: specification,
|
||||
});
|
||||
static properties = properties;
|
||||
};
|
||||
}
|
||||
|
||||
const Empty = wrapSpecification('Empty', {});
|
||||
const Empty = wrapProperties('Empty', {});
|
||||
|
||||
const Name = wrapSpecification('Name', {
|
||||
const Name = wrapProperties('Name', {
|
||||
name: {type: 'string'},
|
||||
});
|
||||
|
||||
const Position = wrapSpecification('Position', {
|
||||
const Position = wrapProperties('Position', {
|
||||
x: {type: 'int32', defaultValue: 32},
|
||||
y: {type: 'int32'},
|
||||
z: {type: 'int32'},
|
||||
|
@ -117,7 +113,7 @@ test('inserts components into entities', () => {
|
|||
});
|
||||
|
||||
test('ticks systems', () => {
|
||||
const Momentum = wrapSpecification('Momentum', {
|
||||
const Momentum = wrapProperties('Momentum', {
|
||||
x: {type: 'int32'},
|
||||
y: {type: 'int32'},
|
||||
z: {type: 'int32'},
|
||||
|
@ -220,7 +216,7 @@ test('schedules entities to be deleted when ticking systems', () => {
|
|||
test('adds components to and remove components from entities when ticking systems', () => {
|
||||
let addLength, removeLength;
|
||||
const ecs = new Ecs({
|
||||
Components: {Foo: wrapSpecification('Foo', {bar: {type: 'uint8'}})},
|
||||
Components: {Foo: wrapProperties('Foo', {bar: {type: 'uint8'}})},
|
||||
Systems: {
|
||||
AddComponent: class extends System {
|
||||
static queries() {
|
||||
|
|
|
@ -2,21 +2,17 @@ import {expect, test} from 'vitest';
|
|||
|
||||
import Component from './component.js';
|
||||
import Query from './query.js';
|
||||
import Schema from './schema.js';
|
||||
|
||||
function wrapSpecification(name, specification) {
|
||||
function wrapProperties(name, properties) {
|
||||
return class WrappedComponent extends Component {
|
||||
static name = name;
|
||||
static schema = new Schema({
|
||||
type: 'object',
|
||||
properties: specification,
|
||||
});
|
||||
static properties = properties;
|
||||
};
|
||||
}
|
||||
|
||||
const A = new (wrapSpecification('A', {a: {type: 'int32', defaultValue: 420}}));
|
||||
const B = new (wrapSpecification('B', {b: {type: 'int32', defaultValue: 69}}));
|
||||
const C = new (wrapSpecification('C', {c: {type: 'int32'}}));
|
||||
const A = new (wrapProperties('A', {a: {type: 'int32', defaultValue: 420}}));
|
||||
const B = new (wrapProperties('B', {b: {type: 'int32', defaultValue: 69}}));
|
||||
const C = new (wrapProperties('C', {c: {type: 'int32'}}));
|
||||
|
||||
const Components = {A, B, C};
|
||||
Components.A.createMany([[2], [3]]);
|
||||
|
@ -70,7 +66,7 @@ test('can deindex', () => {
|
|||
});
|
||||
|
||||
test('can reindex', () => {
|
||||
const Test = new (wrapSpecification('Test', {a: {type: 'int32', defaultValue: 420}}));
|
||||
const Test = new (wrapProperties('Test', {a: {type: 'int32', defaultValue: 420}}));
|
||||
Test.createMany([[2], [3]]);
|
||||
const query = new Query(['Test'], fakeEcs({Test}));
|
||||
query.reindex([2, 3]);
|
||||
|
|
Loading…
Reference in New Issue
Block a user