diff --git a/app/ecs-components/sprite.js b/app/ecs-components/sprite.js index e8322c3..6d72dcd 100644 --- a/app/ecs-components/sprite.js +++ b/app/ecs-components/sprite.js @@ -3,6 +3,9 @@ import Component from '@/ecs/component.js'; import vector2d from "./helpers/vector-2d"; export default class Sprite extends Component { + async load(instance) { + instance.$$sourceJson = await this.ecs.readJson(instance.source); + } static properties = { anchor: vector2d('float32', {x: 0.5, y: 0.5}), animation: {type: 'string'}, diff --git a/app/ecs-systems/calculate-aabbs.js b/app/ecs-systems/calculate-aabbs.js index c904df8..b58a70f 100644 --- a/app/ecs-systems/calculate-aabbs.js +++ b/app/ecs-systems/calculate-aabbs.js @@ -9,12 +9,24 @@ export default class CalculateAabbs extends System { } tick() { - for (const {Position: {x, y}, VisibleAabb} of this.ecs.changed(['Position'])) { + for (const entity of this.ecs.changed(['Position'])) { + const {Position: {x, y}, Sprite, VisibleAabb} = entity; if (VisibleAabb) { - VisibleAabb.x0 = x - 32; - VisibleAabb.x1 = x + 32; - VisibleAabb.y0 = y - 32; - VisibleAabb.y1 = y + 32; + let size = undefined; + if (Sprite) { + const frame = Sprite.animation + ? Sprite.$$sourceJson.animations[Sprite.animation][Sprite.frame] + : ''; + size = Sprite.$$sourceJson.frames[frame].sourceSize; + } + /* v8 ignore next 3 */ + if (!size) { + throw new Error(`no size for aabb for entity ${entity.id}(${JSON.stringify(entity.toJSON(), null, 2)})`); + } + VisibleAabb.x0 = x - ((size.w ) * (Sprite.anchor.x)); + VisibleAabb.x1 = x + ((size.w ) * (1 - Sprite.anchor.x)); + VisibleAabb.y0 = y - ((size.h ) * (Sprite.anchor.y)); + VisibleAabb.y1 = y + ((size.h ) * (1 - Sprite.anchor.y)); } } } diff --git a/app/engine.js b/app/engine.js index af6941e..0ed78e9 100644 --- a/app/engine.js +++ b/app/engine.js @@ -15,6 +15,7 @@ export default class Engine { connections = []; connectedPlayers = new Map(); + connectingPlayers = []; ecses = {}; frame = 0; handle; @@ -53,7 +54,7 @@ export default class Engine { }); } - acceptActions() { + async acceptActions() { for (const [ entity, payload, @@ -103,21 +104,28 @@ export default class Engine { } async connectPlayer(connection, id) { - const entityJson = await this.loadPlayer(id); - if (!this.ecses[entityJson.Ecs.path]) { - await this.loadEcs(entityJson.Ecs.path); + this.connectingPlayers.push([connection, id]); + } + + async connectPlayers() { + for (const [connection, id] of this.connectingPlayers) { + const entityJson = await this.loadPlayer(id); + if (!this.ecses[entityJson.Ecs.path]) { + await this.loadEcs(entityJson.Ecs.path); + } + const ecs = this.ecses[entityJson.Ecs.path]; + const entity = await ecs.create(entityJson); + this.connections.push(connection); + this.connectedPlayers.set( + connection, + { + entity: ecs.get(entity), + id, + memory: new Set(), + }, + ); } - const ecs = this.ecses[entityJson.Ecs.path]; - const entity = await ecs.create(entityJson); - this.connections.push(connection); - this.connectedPlayers.set( - connection, - { - entity: ecs.get(entity), - id, - memory: new Set(), - }, - ); + this.connectingPlayers = []; } createEcs() { @@ -146,7 +154,7 @@ export default class Engine { Position: {x: 100, y: 100}, Sprite: { anchor: {x: 0.5, y: 0.8}, - source: '/assets/shit-shack/shit-shack.png', + source: '/assets/shit-shack/shit-shack.json', }, VisibleAabb: {}, }); @@ -290,19 +298,22 @@ export default class Engine { } start() { - this.handle = setInterval(() => { + const loop = async () => { + await this.connectPlayers(); + await this.acceptActions(); const elapsed = (Date.now() - this.last) / 1000; this.last = Date.now(); - this.acceptActions(); this.tick(elapsed); this.update(elapsed); this.setClean(); this.frame += 1; - }, 1000 / TPS); + this.handle = setTimeout(loop, 1000 / TPS); + }; + loop(); } stop() { - clearInterval(this.handle); + clearTimeout(this.handle); this.handle = undefined; } diff --git a/app/react-components/entities.jsx b/app/react-components/entities.jsx index 706b3d8..6e6ce50 100644 --- a/app/react-components/entities.jsx +++ b/app/react-components/entities.jsx @@ -34,6 +34,9 @@ export default function Entities({entities}) { }, [entities, ecs, mainEntity]); const renderables = []; for (const id in entities) { + if ('1' === id) { + continue; + } const isHighlightedInteraction = id == willInteractWith; renderables.push( { + g.clear(); + g.lineStyle(0.5, 0xff00ff); + g.moveTo(-0.25, -0.25); + g.lineTo(x1 - x0, 0); + g.lineTo(x1 - x0, y1 - y0); + g.lineTo(0, y1 - y0); + g.lineTo(0, 0); + }, [x0, x1, y0, y1]); + return ( + + ); +} + function Crosshair({x, y}) { const draw = useCallback((g) => { g.clear(); @@ -52,6 +67,14 @@ function Entity({entity, ...rest}) { {debug && entity.Position && ( )} + {debug && ( + + )} ); } diff --git a/app/react-components/sprite.jsx b/app/react-components/sprite.jsx index 5814398..315b91d 100644 --- a/app/react-components/sprite.jsx +++ b/app/react-components/sprite.jsx @@ -8,12 +8,11 @@ export default function Sprite({entity, ...rest}) { return false; } let texture; - if (asset.textures) { - const animation = asset.animations[entity.Sprite.animation] - texture = animation[entity.Sprite.frame]; + if (asset.data.animations) { + texture = asset.animations[entity.Sprite.animation][entity.Sprite.frame]; } else { - texture = asset; + texture = asset.textures['']; } return ( = 4" } }, - "node_modules/image-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz", - "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==", - "dev": true, - "dependencies": { - "queue": "6.0.2" - }, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=16.x" - } - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -15161,15 +15145,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/queue": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", - "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "dev": true, - "dependencies": { - "inherits": "~2.0.3" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", diff --git a/package.json b/package.json index 7f4e734..db4ac1f 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,6 @@ "eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "image-size": "^1.1.1", "storybook": "^8.1.6", "vite": "^5.1.0", "vitest": "^1.6.0" diff --git a/public/assets/shit-shack/shit-shack.json b/public/assets/shit-shack/shit-shack.json new file mode 100644 index 0000000..addc256 --- /dev/null +++ b/public/assets/shit-shack/shit-shack.json @@ -0,0 +1 @@ +{"frames":{"":{"frame":{"x":0,"y":0,"w":110,"h":102},"spriteSourceSize":{"x":0,"y":0,"w":110,"h":102},"sourceSize":{"w":110,"h":102}}},"meta":{"format":"RGBA8888","image":"./shit-shack.png","scale":1,"size":{"w":110,"h":102}}} \ No newline at end of file