Skip to content

Instantly share code, notes, and snippets.

@clarabstract
Last active January 29, 2020 01:34
Show Gist options
  • Select an option

  • Save clarabstract/eae1a20dc8518b0a4628d1b0a1d21c2f to your computer and use it in GitHub Desktop.

Select an option

Save clarabstract/eae1a20dc8518b0a4628d1b0a1d21c2f to your computer and use it in GitHub Desktop.
doing the ecs
import PIXI from '/node_modules/pixi.js/dist/pixi.js';
window.addEventListener("AutoreloadClient.update", function(ev){
window.location.reload();
});
const app = new PIXI.Application();
document.body.appendChild(app.view);
let _lastId = 0;
const createEntity = () => {
return _lastId++;
}
const ENTITY_ARRAY_TYPE = Uint32Array;
const OBJECT_COMPONENT = Symbol("OBJECT_COMPONENT");
const SCALAR_COMPONENT = Symbol("SCALAR_COMPONENT");
const objectComponent = (size) => {
return {
type: OBJECT_COMPONENT,
data: new Array(size),
entities: new ENTITY_ARRAY_TYPE(size),
lastIdx: -1,
entityMap: new Map(),
};
return newComponent;
}
const scalarComponent = (size, type, getter, setter) => {
const data = new type(size);
return {
type: SCALAR_COMPONENT,
data,
entities: new ENTITY_ARRAY_TYPE(size),
getter,
setter,
scalars: Object.keys(getter(data, 0)).length,
lastIdx: -1,
entityMap: new Map(),
};
}
const addComponent = (entityId, component, o) => {
const idx = ++component.lastIdx;
set(component, idx, o);
component.entities[idx] = entityId;
component.entityMap.set(entityId, idx);
}
const get = (component, idx) => {
if (component.type === OBJECT_COMPONENT) {
return component.data[idx];
} else {
return component.getter(component.data, idx * component.scalars);
}
}
const set = (component, idx, o) => {
if (component.type === OBJECT_COMPONENT) {
component.data[idx] = o;
} else {
component.setter(component.data, idx * component.scalars, o)
}
}
const component = (entityId, component) => get(component, component.entityMap.get(entityId));
const removeComponent = (entityId, component) => {
const idx = component.entityMap.get(entityId);
const {data, entities} = component;
if (component.type === OBJECT_COMPONENT) {
entities[idx] = entities[component.lastIdx];
data[idx] = data[component.lastIdx--];
} else {
entities[idx] = entities[component.lastIdx];
const idxOfLastBlock = component.lastIdx - component.scalars;
for (var i = 0; i < component.scalars; i++) {
data[idx + i] = data[idxOfLastBlock + i];
}
component.lastIdx -= component.scalars;
}
component.entityMap.delete(entityId);
}
const MAX_ENTITIES = 10000;
const positions = scalarComponent(MAX_ENTITIES, Float32Array,
(l, i) => ({
x: l[i],
y: l[i+1],
}),
(l, i, o) => {
l[i] = o.x;
l[i+1] = o.y;
}
);
const renderable = objectComponent(MAX_ENTITIES);
for (var i = 0; i < 100; i++) {
const e = createEntity();
addComponent(e, positions, {x: Math.random() * 400, y: Math.random() * 400});
const shape = new PIXI.Graphics();;
shape.beginFill(0x5cafe2);
shape.drawCircle(0,0,5)
app.stage.addChild(shape);
addComponent(e, renderable, shape);
}
function renderSystem(td) {
for (var i = 0; i <= positions.lastIdx; i++) {
const {x,y} = get(positions, i);
// if visible...
const entity = positions.entities[i];
const shape = component(entity, renderable);
shape.x = x;
shape.y = y;
}
}
function physicsSystem(td) {
for (var i = 0; i <= positions.lastIdx; i++) {
const pos = get(positions, i);
pos.x += Math.random() - 0.5
pos.y += Math.random() - 0.5
set(positions, i, pos)
}
}
const txt = new PIXI.Text("Test", {fill: 0xffffff})
app.stage.addChild(txt)
let lastTs = 0;
const mainLoop = (ts) => {
let td = ts - lastTs;
lastTs = ts;
txt.text = 1000 / td // fps
physicsSystem(td);
renderSystem(td);
requestAnimationFrame(mainLoop)
}
requestAnimationFrame(mainLoop);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment