diff --git a/app/ecs-components/emitter.js b/app/ecs-components/emitter.js new file mode 100644 index 0000000..072fc2f --- /dev/null +++ b/app/ecs-components/emitter.js @@ -0,0 +1,31 @@ +import Schema from '@/ecs/schema.js'; + +export default function(Component) { + return class Emitter extends Component { + mergeDiff(original, update) { + const merged = {}; + if (update.emit) { + merged.emit = { + ...original.emit, + ...update.emit, + } + } + return merged; + } + instanceFromSchema() { + const Component = this; + const Instance = super.instanceFromSchema(); + return class EmitterInstance extends Instance { + emitting = []; + id = 0; + emit(specification) { + Component.markChange(this.entity, 'emit', {[this.id++]: specification}); + } + }; + } + static schema = new Schema({ + type: 'object', + properties: {}, + }); + } +} diff --git a/app/engine.js b/app/engine.js index 3671cf1..b21308d 100644 --- a/app/engine.js +++ b/app/engine.js @@ -167,6 +167,7 @@ export default class Engine { Controlled: {}, Direction: {direction: 2}, Ecs: {path: join('homesteads', `${id}`)}, + Emitter: {}, Forces: {}, Inventory: { slots: { diff --git a/app/react-components/ecs.jsx b/app/react-components/ecs.jsx index 5439ac6..a57ef5b 100644 --- a/app/react-components/ecs.jsx +++ b/app/react-components/ecs.jsx @@ -42,11 +42,18 @@ export default function EcsComponent() { } const updatedEntities = {...entities}; for (const id in payload.ecs) { - if (false === payload.ecs[id]) { + const update = payload.ecs[id]; + if (false === update) { delete updatedEntities[id]; } else { updatedEntities[id] = ecs.get(id); + if (update.Emitter?.emit) { + updatedEntities[id].Emitter.emitting = { + ...updatedEntities[id].Emitter.emitting, + ...update.Emitter.emit, + }; + } } } setEntities(updatedEntities); diff --git a/app/react-components/emitter.jsx b/app/react-components/emitter.jsx new file mode 100644 index 0000000..b74a0f8 --- /dev/null +++ b/app/react-components/emitter.jsx @@ -0,0 +1,52 @@ +import {Container} from '@pixi/display'; +import {PixiComponent} from '@pixi/react'; +import * as particles from '@pixi/particle-emitter'; + +const EmitterInternal = PixiComponent('Emitter', { + $$emitter: undefined, + $$raf: undefined, + create() { + return new Container(); + }, + applyProps(container, oldProps, newProps) { + if (!this.$$emitter) { + const {onComplete, particle} = newProps; + this.$$emitter = new particles.Emitter(container, particle); + this.$$emitter._completeCallback = onComplete; + let last = Date.now(); + const render = () => { + this.$$raf = requestAnimationFrame(render); + const now = Date.now(); + this.$$emitter.update((now - last) / 1000); + last = now; + }; + this.$$emitter.emit = true; + render(); + } + }, + willUnmount() { + if (this.$$emitter) { + this.$$emitter.emit = false; + cancelAnimationFrame(this.$$raf); + } + } +}); + +export default function Emitter({entity}) { + const {Emitter} = entity; + const emitters = []; + for (const id in Emitter.emitting) { + const particle = Emitter.emitting[id]; + emitters.push( + { + delete Emitter.emitting[id]; + }} + particle={particle} + /> + ); + } + return <>{emitters}; +} + diff --git a/app/react-components/entities.jsx b/app/react-components/entities.jsx index bcc9dd5..e392f72 100644 --- a/app/react-components/entities.jsx +++ b/app/react-components/entities.jsx @@ -3,6 +3,7 @@ import {useCallback} from 'react'; import {useDebug} from '@/context/debug.js'; +import Emitter from './emitter.jsx'; import Sprite from './sprite.jsx'; function Crosshair({x, y}) { @@ -40,9 +41,16 @@ export default function Entities({entities}) { - + {entity.Sprite && ( + + )} + {entity.Emitter && ( + + )} {debug && ( )} diff --git a/package-lock.json b/package-lock.json index e870090..baff630 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "name": "silphius-next", "dependencies": { "@msgpack/msgpack": "^3.0.0-beta2", + "@pixi/particle-emitter": "^5.0.8", "@pixi/react": "^7.1.2", "@pixi/spritesheet": "^7.4.2", "@pixi/tilemap": "^4.1.0", @@ -3419,6 +3420,26 @@ "@pixi/sprite": "7.4.2" } }, + "node_modules/@pixi/particle-emitter": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@pixi/particle-emitter/-/particle-emitter-5.0.8.tgz", + "integrity": "sha512-OzuZ4+esQo+zJ0u3htuNHHMAE8Ixmr3nz3tEfrTGZHje1vnGyie3ANQj9F0V4OM47oi9jd70njVCmeb7bTkS9A==", + "peerDependencies": { + "@pixi/constants": ">=6.0.4 <8.0.0", + "@pixi/core": ">=6.0.4 <8.0.0", + "@pixi/display": ">=6.0.4 <8.0.0", + "@pixi/math": ">=6.0.4 <8.0.0", + "@pixi/sprite": ">=6.0.4 <8.0.0", + "@pixi/ticker": ">=6.0.4 <8.0.0" + }, + "workspaces": { + "packages": [ + "./", + "test/pixi-v6-iife", + "test/pixi-v6-module" + ] + } + }, "node_modules/@pixi/prepare": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@pixi/prepare/-/prepare-7.4.2.tgz", diff --git a/package.json b/package.json index 0b1cbac..6f8ad12 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@msgpack/msgpack": "^3.0.0-beta2", + "@pixi/particle-emitter": "^5.0.8", "@pixi/react": "^7.1.2", "@pixi/spritesheet": "^7.4.2", "@pixi/tilemap": "^4.1.0",