From e87d921714d11ca3fccac4da4d090dca287038c7 Mon Sep 17 00:00:00 2001 From: cha0s Date: Fri, 28 Jun 2024 08:53:20 -0500 Subject: [PATCH] refactor: item --- app/ecs-components/inventory.js | 163 ++++++++++++++++------- app/ecs-components/plant.js | 1 - app/ecs-components/wielder.js | 61 +-------- app/react-components/ecs.jsx | 35 ++--- app/react-components/entity.jsx | 2 +- app/react-components/targeting-ghost.jsx | 4 +- app/react-components/targeting-grid.jsx | 8 +- public/assets/hoe/item.json | 12 +- public/assets/hoe/start.js | 6 +- public/assets/tomato-seeds/item.json | 16 +-- 10 files changed, 144 insertions(+), 164 deletions(-) diff --git a/app/ecs-components/inventory.js b/app/ecs-components/inventory.js index 198c294..ed98dff 100644 --- a/app/ecs-components/inventory.js +++ b/app/ecs-components/inventory.js @@ -20,61 +20,13 @@ export default class Inventory extends Component { } return super.insertMany(entities); } - mergeDiff(original, update) { - if (!update.slotChange) { - return super.mergeDiff(original, update); - } - const slotChange = { - ...original.slotChange, - }; - for (const index in update.slotChange) { - if (false === update.slotChange[index]) { - slotChange[index] = false; - } - else { - slotChange[index] = { - ...slotChange[index], - ...update.slotChange[index], - }; - } - } - return {slotChange}; - } instanceFromSchema() { const Instance = super.instanceFromSchema(); const Component = this; return class InventoryInstance extends Instance { - async item(slot) { - const {slots} = this; - if (!(slot in slots)) { - return undefined; - } - const {readAsset} = Component.ecs; - const chars = await readAsset([slots[slot].source, 'item.json'].join('/')) - const json = chars.byteLength > 0 - ? JSON.parse( - (new TextDecoder()).decode(chars), - ) - : {}; - const item = { - ...slots[slot], - ...json, - }; - const instance = this; - const proxy = new Proxy(item, { - set(target, property, value) { - slots[slot][property] = value; - if ('qty' === property && value <= 0) { - Component.markChange(instance.entity, 'slotChange', {[slot]: false}); - delete slots[slot]; - } - else { - Component.markChange(instance.entity, 'slotChange', {[slot]: {[property]: value}}); - } - return true; - }, - }); - return proxy; + $$items = {}; + item(slot) { + return this.$$items[slot]; } swapSlots(l, r) { const {slots} = this; @@ -98,6 +50,115 @@ export default class Inventory extends Component { } } } + async load(instance) { + const Component = this; + const {readAsset} = this.ecs; + const {slots} = instance; + class ItemProxy { + constructor(slot, json) { + this.json = json; + this.slot = slot; + } + project(position, direction) { + const {TileLayers: {layers: [layer]}} = Component.ecs.get(1); + const {projection} = this.json; + let startX = position.x; + let startY = position.y; + switch (direction) { + case 0: + startX += projection.distance[1]; + startY -= projection.distance[0]; + break; + case 1: + startX += projection.distance[0]; + startY += projection.distance[1]; + break; + case 2: + startX -= projection.distance[1]; + startY += projection.distance[0]; + break; + case 3: + startX -= projection.distance[0]; + startY -= projection.distance[1]; + break; + } + const projected = []; + for (const row in projection.grid) { + const columns = projection.grid[row]; + for (const column in columns) { + const targeted = projection.grid[row][column]; + if (targeted) { + let axe; + switch (direction) { + case 0: + axe = [column, row]; + break; + case 1: + axe = [-row, column]; + break; + case 2: + axe = [-column, -row]; + break; + case 3: + axe = [row, -column]; + break; + } + const x = startX + parseInt(axe[0]); + const y = startY + parseInt(axe[1]); + if (x < 0 || y < 0 || x >= layer.area.x || y >= layer.area.y) { + continue; + } + projected.push({x, y}); + } + } + } + return projected; + } + get qty() { + return slots[this.slot].qty; + } + set qty(qty) { + if (qty <= 0) { + Component.markChange(instance.entity, 'slotChange', {[this.slot]: false}); + delete slots[this.slot]; + } + else { + slots[this.slot].qty = qty; + Component.markChange(instance.entity, 'slotChange', {[this.slot]: {qty}}); + } + } + } + + for (const slot in slots) { + const chars = await readAsset([slots[slot].source, 'item.json'].join('/')) + const json = chars.byteLength > 0 + ? JSON.parse( + (new TextDecoder()).decode(chars), + ) + : {}; + instance.$$items[slot] = new ItemProxy(slots, json); + } + } + mergeDiff(original, update) { + if (!update.slotChange) { + return super.mergeDiff(original, update); + } + const slotChange = { + ...original.slotChange, + }; + for (const index in update.slotChange) { + if (false === update.slotChange[index]) { + slotChange[index] = false; + } + else { + slotChange[index] = { + ...slotChange[index], + ...update.slotChange[index], + }; + } + } + return {slotChange}; + } static properties = { slots: { type: 'map', diff --git a/app/ecs-components/plant.js b/app/ecs-components/plant.js index 7fa96e3..7a6df4f 100644 --- a/app/ecs-components/plant.js +++ b/app/ecs-components/plant.js @@ -31,7 +31,6 @@ export default class Plant extends Component { instance.growScriptInstance = await Script.fromCode((new TextDecoder()).decode(code), context); } }); - await readAsset(instance.mayGrowScript) .then(async (code) => { if (code.byteLength > 0) { diff --git a/app/ecs-components/wielder.js b/app/ecs-components/wielder.js index 73383fd..1f123ca 100644 --- a/app/ecs-components/wielder.js +++ b/app/ecs-components/wielder.js @@ -6,69 +6,14 @@ export default class Wielder extends Component { const {ecs} = this; const Instance = super.instanceFromSchema(); return class WielderInstance extends Instance { - async activeItem() { + activeItem() { const {Inventory, Wielder} = ecs.get(this.entity); return Inventory.item(Wielder.activeSlot + 1); } - project(position, projection) { - const {TileLayers: {layers: [layer]}} = ecs.get(1); - const {Direction: {direction}} = ecs.get(this.entity); - let startX = position.x; - let startY = position.y; - switch (direction) { - case 0: - startX += projection.distance[1]; - startY -= projection.distance[0]; - break; - case 1: - startX += projection.distance[0]; - startY += projection.distance[1]; - break; - case 2: - startX -= projection.distance[1]; - startY += projection.distance[0]; - break; - case 3: - startX -= projection.distance[0]; - startY -= projection.distance[1]; - break; - } - const projected = []; - for (const row in projection.grid) { - const columns = projection.grid[row]; - for (const column in columns) { - const targeted = projection.grid[row][column]; - if (targeted) { - let axe; - switch (direction) { - case 0: - axe = [column, row]; - break; - case 1: - axe = [-row, column]; - break; - case 2: - axe = [-column, -row]; - break; - case 3: - axe = [row, -column]; - break; - } - const x = startX + parseInt(axe[0]); - const y = startY + parseInt(axe[1]); - if (x < 0 || y < 0 || x >= layer.area.x || y >= layer.area.y) { - continue; - } - projected.push({x, y}); - } - } - } - return projected; - } - async useActiveItem(state) { + useActiveItem(state) { const entity = ecs.get(this.entity); const {Ticking} = entity; - const activeItem = await this.activeItem(); + const activeItem = this.activeItem(); if (activeItem) { ecs.readAsset([activeItem.source, state ? 'start.js' : 'stop.js'].join('/')) .then((code) => { diff --git a/app/react-components/ecs.jsx b/app/react-components/ecs.jsx index 5795d3d..789d5e8 100644 --- a/app/react-components/ecs.jsx +++ b/app/react-components/ecs.jsx @@ -1,5 +1,5 @@ import {Container} from '@pixi/react'; -import {useEffect, useState} from 'react'; +import {useState} from 'react'; import {RESOLUTION} from '@/constants.js'; import {useEcs, useEcsTick} from '@/context/ecs.js'; @@ -13,29 +13,8 @@ import TileLayer from './tile-layer.jsx'; export default function EcsComponent() { const [ecs] = useEcs(); const [entities, setEntities] = useState({}); - const [activeTool, setActiveTool] = useState(false); const [mainEntity] = useMainEntity(); - useEffect(() => { - if (mainEntity) { - ecs.get(mainEntity) - .Wielder.activeItem() - .then(({tool} = {}) => { - setActiveTool(tool); - }); - } - }, [ecs, mainEntity]); useEcsTick((payload) => { - if ( - mainEntity - && payload[mainEntity] - && (payload[mainEntity].Inventory || payload[mainEntity].Wielder) - ) { - ecs.get(mainEntity) - .Wielder.activeItem() - .then(({tool} = {}) => { - setActiveTool(tool); - }); - } const updatedEntities = {...entities}; for (const id in payload) { const update = payload[id]; @@ -58,6 +37,8 @@ export default function EcsComponent() { return false; } const entity = ecs.get(mainEntity); + const {Direction, Position, Wielder} = entity; + const projected = Wielder.activeItem()?.project(Position.tile, Direction.direction) const {Camera} = entity; const {TileLayers: {layers: [layer]}} = ecs.get(1); const [cx, cy] = [ @@ -70,17 +51,17 @@ export default function EcsComponent() { y={-cy} > - {activeTool && ( + {projected && ( )} - {activeTool && ( + {projected?.length > 0 && ( )} diff --git a/app/react-components/entity.jsx b/app/react-components/entity.jsx index ad3df2e..39793ce 100644 --- a/app/react-components/entity.jsx +++ b/app/react-components/entity.jsx @@ -36,7 +36,7 @@ function Entities({entity}) { } return ( {entity.Sprite && ( { const handle = setInterval(() => { @@ -43,8 +43,6 @@ export default function TargetingGhost({entity, projection, tileLayer}) { clearInterval(handle); }; }, []); - const {Position, Wielder} = entity; - const projected = Wielder.project(Position.tile, projection) const ghosts = []; const {area} = tileLayer; for (const {x, y} of projected) { diff --git a/app/react-components/targeting-grid.jsx b/app/react-components/targeting-grid.jsx index 068fd5a..01e26d5 100644 --- a/app/react-components/targeting-grid.jsx +++ b/app/react-components/targeting-grid.jsx @@ -69,9 +69,8 @@ const TargetingGridInternal = PixiComponent('TargetingGrid', { top.addChild(container, area); return top; }, - applyProps: ({children: [container]}, oldProps, {entity, radians}) => { + applyProps: ({children: [container]}, oldProps, {x, y, radians}) => { const pulse = (Math.cos(radians) + 1) * 0.5; - const {Position: {x, y}} = entity; const tileX = x - (x % tileSize.x); const tileY = y - (y % tileSize.y); const gridX = (tileSize.x * (radius / 2)); @@ -85,7 +84,7 @@ const TargetingGridInternal = PixiComponent('TargetingGrid', { }, }) -export default function TargetingGrid({entity, tileLayer}) { +export default function TargetingGrid({tileLayer, x, y}) { const app = useApp(); const [radians, setRadians] = useState(0); useEffect(() => { @@ -99,9 +98,10 @@ export default function TargetingGrid({entity, tileLayer}) { return ( ); } diff --git a/public/assets/hoe/item.json b/public/assets/hoe/item.json index 0282343..ab94794 100644 --- a/public/assets/hoe/item.json +++ b/public/assets/hoe/item.json @@ -1,10 +1,8 @@ { - "tool": { - "projection": { - "distance": [1, 0], - "grid": [ - [1] - ] - } + "projection": { + "distance": [1, 0], + "grid": [ + [1] + ] } } diff --git a/public/assets/hoe/start.js b/public/assets/hoe/start.js index c33e2cf..1c3245f 100644 --- a/public/assets/hoe/start.js +++ b/public/assets/hoe/start.js @@ -1,6 +1,6 @@ -const {Position, Wielder} = wielder -const projected = Wielder.project(Position.tile, item.tool.projection) -if (projected.length > 0) { +const {Direction, Position, Wielder} = wielder +const projected = Wielder.activeItem()?.project(Position.tile, Direction.direction) +if (projected?.length > 0) { const {Controlled, Emitter, Sound, Sprite} = wielder const {TileLayers} = ecs.get(1) diff --git a/public/assets/tomato-seeds/item.json b/public/assets/tomato-seeds/item.json index 40a12b2..8bc7b5f 100644 --- a/public/assets/tomato-seeds/item.json +++ b/public/assets/tomato-seeds/item.json @@ -1,12 +1,10 @@ { - "tool": { - "projection": { - "distance": [1, -1], - "grid": [ - [1, 1, 1], - [1, 1, 1], - [1, 1, 1] - ] - } + "projection": { + "distance": [1, -1], + "grid": [ + [1, 1, 1], + [1, 1, 1], + [1, 1, 1] + ] } }