feat: water

This commit is contained in:
cha0s 2024-06-28 16:38:49 -05:00
parent 49e48d55c2
commit 2376b5b1c3
11 changed files with 247 additions and 5 deletions

View File

@ -0,0 +1,10 @@
import Component from '@/ecs/component.js';
export default class Water extends Component {
static properties = {
water: {
type: 'map',
value: {type: 'uint8'},
},
};
}

13
app/ecs-systems/water.js Normal file
View File

@ -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};
}
}

View File

@ -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,

View File

@ -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}
>
<TileLayer tileLayer={layer} />
<Water tileLayer={layer} water={water} />
{projected && (
<TargetingGrid
tileLayer={layer}

View File

@ -0,0 +1,51 @@
import {Graphics} from '@pixi/react';
import {forwardRef, useCallback, useEffect, useRef, useState} from 'react';
const WaterTile = forwardRef(function WaterTile({height, width}, ref) {
const draw = useCallback((g) => {
g.clear();
g.beginFill(0x000000);
g.drawRect(
0,
0,
width,
height
);
}, [height, width]);
return <Graphics alpha={0} draw={draw} ref={ref} />
});
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(
<Graphics
x={tx * tileLayer.tileSize.x}
y={ty * tileLayer.tileSize.y}
alpha={Math.floor(water[tileIndex]) / (256 * 2)}
key={tileIndex}
geometry={waterTile.current}
/>
);
}
}
return (
<>
<WaterTile
height={tileLayer.tileSize.y}
ref={waterTile}
width={tileLayer.tileSize.x}
/>
{waterTiles}
</>
);
}

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

View File

@ -0,0 +1,10 @@
const filtered = []
for (let i = 0; i < projected.length; ++i) {
const tile = layer.tile(projected[i])
if ([7].includes(tile)) {
filtered.push(projected[i])
}
}
return filtered

View File

@ -0,0 +1,120 @@
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, 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;
}

Binary file not shown.

View File

@ -0,0 +1,11 @@
{
"icon": "/assets/watering-can/icon.png",
"projectionCheck": "/assets/watering-can/projection-check.js",
"projection": {
"distance": [1, 0],
"grid": [
[1]
]
},
"start": "/assets/watering-can/start.js"
}