From 2376b5b1c37d2a4b3ac676e10506d2730bf1ee8b Mon Sep 17 00:00:00 2001 From: cha0s Date: Fri, 28 Jun 2024 16:38:49 -0500 Subject: [PATCH] feat: water --- app/ecs-components/water.js | 10 ++ app/ecs-systems/water.js | 13 ++ app/engine.js | 12 +- app/react-components/ecs.jsx | 4 +- app/react-components/water.jsx | 51 ++++++++ public/assets/tomato-plant/may-grow.js | 21 ++- public/assets/watering-can/icon.png | Bin 0 -> 683 bytes .../assets/watering-can/projection-check.js | 10 ++ public/assets/watering-can/start.js | 120 ++++++++++++++++++ public/assets/watering-can/water.wav | Bin 0 -> 150921 bytes public/assets/watering-can/watering-can.json | 11 ++ 11 files changed, 247 insertions(+), 5 deletions(-) create mode 100644 app/ecs-components/water.js create mode 100644 app/ecs-systems/water.js create mode 100644 app/react-components/water.jsx create mode 100644 public/assets/watering-can/icon.png create mode 100644 public/assets/watering-can/projection-check.js create mode 100644 public/assets/watering-can/start.js create mode 100644 public/assets/watering-can/water.wav create mode 100644 public/assets/watering-can/watering-can.json diff --git a/app/ecs-components/water.js b/app/ecs-components/water.js new file mode 100644 index 0000000..d289048 --- /dev/null +++ b/app/ecs-components/water.js @@ -0,0 +1,10 @@ +import Component from '@/ecs/component.js'; + +export default class Water extends Component { + static properties = { + water: { + type: 'map', + value: {type: 'uint8'}, + }, + }; +} diff --git a/app/ecs-systems/water.js b/app/ecs-systems/water.js new file mode 100644 index 0000000..20ba83e --- /dev/null +++ b/app/ecs-systems/water.js @@ -0,0 +1,13 @@ +import {System} from '@/ecs/index.js'; + +export default class Water extends System { + + tick(elapsed) { + const {Water} = this.ecs.get(1); + for (const tile in Water.water) { + Water.water[tile] = Math.max(0, Water.water[tile] - elapsed); + } + Water.water = {...Water.water}; + } + +} diff --git a/app/engine.js b/app/engine.js index debe448..980af9e 100644 --- a/app/engine.js +++ b/app/engine.js @@ -128,6 +128,7 @@ export default class Engine { } ], }, + Water: {water: {}}, }); const defaultSystems = [ 'ResetForces', @@ -142,6 +143,7 @@ export default class Engine { 'SpriteDirection', 'RunAnimations', 'RunTickingPromises', + 'Water', ]; defaultSystems.forEach((defaultSystem) => { const System = ecs.system(defaultSystem); @@ -162,9 +164,13 @@ export default class Engine { Forces: {}, Inventory: { slots: { - 1: { - qty: 10, - source: '/assets/potion/potion.json', + // 1: { + // qty: 10, + // source: '/assets/potion/potion.json', + // }, + 2: { + qty: 1, + source: '/assets/watering-can/watering-can.json', }, 3: { qty: 1, diff --git a/app/react-components/ecs.jsx b/app/react-components/ecs.jsx index 789d5e8..24a28df 100644 --- a/app/react-components/ecs.jsx +++ b/app/react-components/ecs.jsx @@ -9,6 +9,7 @@ import Entities from './entities.jsx'; import TargetingGhost from './targeting-ghost.jsx'; import TargetingGrid from './targeting-grid.jsx'; import TileLayer from './tile-layer.jsx'; +import Water from './water.jsx'; export default function EcsComponent() { const [ecs] = useEcs(); @@ -40,7 +41,7 @@ export default function EcsComponent() { 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 {TileLayers: {layers: [layer]}, Water: {water}} = ecs.get(1); const [cx, cy] = [ Math.round(Camera.x - RESOLUTION.x / 2), Math.round(Camera.y - RESOLUTION.y / 2), @@ -51,6 +52,7 @@ export default function EcsComponent() { y={-cy} > + {projected && ( { + g.clear(); + g.beginFill(0x000000); + g.drawRect( + 0, + 0, + width, + height + ); + }, [height, width]); + return +}); + +export default function Water({tileLayer, water}) { + const [mounted, setMounted] = useState(false); + useEffect(() => { + setMounted(true); + }, []); + const waterTile = useRef(); + const waterTiles = []; + if (mounted) { + for (const tileIndex in water) { + const tileIndexNumber = parseInt(tileIndex); + const tx = tileIndexNumber % tileLayer.area.x; + const ty = (tileIndexNumber - tx) / tileLayer.area.x; + waterTiles.push( + + ); + } + } + return ( + <> + + {waterTiles} + + ); +} diff --git a/public/assets/tomato-plant/may-grow.js b/public/assets/tomato-plant/may-grow.js index 3295946..33bdcee 100644 --- a/public/assets/tomato-plant/may-grow.js +++ b/public/assets/tomato-plant/may-grow.js @@ -1 +1,20 @@ -return 3 !== plant.stage +if (3 === plant.stage) { + return false +} + +const {TileLayers, Water} = ecs.get(1); +const layer = TileLayers.layer(0) +const {Position} = ecs.get(plant.entity); +const x = (Position.x - layer.tileSize.x * 0.5) / layer.tileSize.x +const y = (Position.y - layer.tileSize.y * 0.5) / layer.tileSize.y +const tileIndex = layer.area.x * y + x +if (!Water.water[tileIndex]) { + return false +} +if (Water.water[tileIndex] < 32) { + return false +} +if (Water.water[tileIndex] > 224) { + return false +} +return true diff --git a/public/assets/watering-can/icon.png b/public/assets/watering-can/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..879b70572cf9d92aa13acfd38ee09105d5254eaf GIT binary patch literal 683 zcmV;c0#yBpP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00I+9L_t(I%e9ofYZOrw#eZks z?1u=7z5jqsS}h_H&_a+DVLQPOki{-wCn9SK8$r;*W)-4fRxrULhzO!lNwbYbn)Eg) zMATri$-bR;Ep}!ztDgj zD;ALL^pTh;`ROay3I)qgpI}&okuQ``Ff(P3;vBSUup;g9wG$ z=gUa43_buG>PdYSl4!23(dl%UJ*NVA?%5KJ%e7%oRprLw$^gEnSorz&`rt$FJ&`N% zaODe0lJMi#PvkvGw_Eg5vRg~<+1&2%?bAC7R!Fk>_B!5s>XQ>RSJx<)%b66qJx8Td zAqkMMQ-C&JeIUkh_tJ&_pQlz7Qc<6r08o0zxf0GfA_GFdTQcL$qb8E<=F7K4A#i)< z3}&W$^P+KaalgOgoRF0Bu^)t8-{bm&Ce`X;8nv_JfkUbIdu>+^Q8pt#fZ# z9HJD%=QpqWV?Cl_W6z4Amtzi{gP{Ayt<`E}0Bvk+s9vvUIaL 0) { + + const {Controlled, Emitter, Sound, Sprite} = wielder + const {TileLayers, Water} = ecs.get(1) + const layer = TileLayers.layer(0) + + Controlled.locked = 1 + const [, direction] = Sprite.animation.split(':') + Sprite.animation = ['idle', direction].join(':'); + + const waterParticles = { + behaviors: [ + { + type: 'moveAcceleration', + config: { + accel: { + x: 0, + y: 1500, + }, + minStart: 0, + maxStart: 0, + rotate: false, + } + }, + { + type: 'moveSpeed', + config: { + speed: { + list: [ + { + time: 0, + value: 30 + }, + { + time: 1, + value: 0 + } + ] + } + } + }, + { + type: 'scale', + config: { + scale: { + list: [ + { + value: 0.25, + time: 0, + }, + { + value: 0.125, + time: 1, + }, + ] + } + } + }, + { + type: 'textureSingle', + config: { + texture: 'tileset/38', + } + }, + ], + lifetime: { + min: 0.25, + max: 0.25, + }, + frequency: 0.01, + emitterLifetime: 0.25, + pos: { + x: 0, + y: 0 + }, + rotation: 0, + }; + + Sound.play('/assets/watering-can/water.wav'); + for (let i = 0; i < 2; ++i) { + for (let i = 0; i < projected.length; ++i) { + Emitter.emit({ + ...waterParticles, + behaviors: [ + ...waterParticles.behaviors, + { + type: 'spawnShape', + config: { + type: 'rect', + data: { + x: projected[i].x * layer.tileSize.x, + y: projected[i].y * layer.tileSize.y - (layer.tileSize.y * 0.5), + w: layer.tileSize.x, + h: layer.tileSize.y, + } + } + } + ] + }) + } + await wait(0.25); + } + + for (let i = 0; i < projected.length; ++i) { + const tileIndex = layer.area.x * projected[i].y + projected[i].x + let w; + if (Water.water[tileIndex]) { + w = Water.water[tileIndex] + } + else { + w = 0 + } + Water.water[tileIndex] = Math.min(255, 64 + w); + } + + Controlled.locked = 0; + +} diff --git a/public/assets/watering-can/water.wav b/public/assets/watering-can/water.wav new file mode 100644 index 0000000000000000000000000000000000000000..a774d4c222c89f8c10d84f12b5fddea83fbed4d7 GIT binary patch literal 150921 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