Last active
January 29, 2020 01:34
-
-
Save clarabstract/eae1a20dc8518b0a4628d1b0a1d21c2f to your computer and use it in GitHub Desktop.
doing the ecs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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