From 0f0e61a5149f96a263acf15ad2501aac4ef48016 Mon Sep 17 00:00:00 2001 From: cha0s Date: Mon, 4 Apr 2022 12:34:24 -0500 Subject: [PATCH] feat: tile painting --- .../persea/room-sides/tiles-side/index.jsx | 74 +++++++++++++++++-- .../room-sides/tiles-side/index.module.scss | 3 + packages/topdown/src/resources/tiles.js | 3 +- 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/packages/topdown/src/persea/room-sides/tiles-side/index.jsx b/packages/topdown/src/persea/room-sides/tiles-side/index.jsx index d2819f0..6a1f822 100644 --- a/packages/topdown/src/persea/room-sides/tiles-side/index.jsx +++ b/packages/topdown/src/persea/room-sides/tiles-side/index.jsx @@ -10,6 +10,7 @@ import { Rectangle, Vector, } from '@avocado/math'; +import {useJsonPatcher} from '@avocado/resource/persea'; import { classnames, hot, @@ -47,11 +48,13 @@ function TilesPage({ room, roomRenderable, }) { + const patch = useJsonPatcher(); const layerCount = resource.tiles.length; const [currentLayer, setCurrentLayer] = useState(0); const [tilesetEvents, setTilesetEvents] = useState(); const [solo, setSolo] = useState(Array(layerCount).fill(false)); const [incident, setIncident] = useState([0, 0]); + const [isHoldingPaint, setIsHoldingPaint] = useState(false); const [isHolding, setIsHolding] = useState(false); const [mute, setMute] = useState(Array(layerCount).fill(false)); const [selection, setSelection] = useState([0, 0, 16, 16]); @@ -90,15 +93,70 @@ function TilesPage({ if (!events) { return undefined; } + const tileSize = [16, 16]; + const stamp = (translated) => { + const position = Vector.div([selection[0], selection[1]], tileSize); + const size = Vector.div([selection[2], selection[3]], tileSize); + let [x, y] = position; + const stamp = []; + for (let yy = 0; yy < size[1]; ++yy) { + for (let xx = 0; xx < size[0]; ++xx) { + stamp.push((y * (viewport[0] / tileSize[0])) + x); + x += 1; + } + x -= size[0]; + y += 1; + } + const where = Rectangle.compose(translated, size); + room.tiles[currentLayer].stampAt(where, stamp); + room.tiles[currentLayer].emit('update', where); + const {data} = room.tiles[currentLayer].toJSON(); + if (!data) { + patch({ + op: 'remove', + path: `/tiles/${currentLayer}/data`, + }); + } + else { + patch({ + path: `/tiles/${currentLayer}/data`, + value: data, + }); + } + }; const onValue = ( - // { - // clientX, - // clientY, - // deltaY, - // target, - // type, - // }, + { + clientX, + clientY, + target, + type, + }, ) => { + switch (type) { + case 'touchstart': + case 'mousedown': { + const {left, top} = target.getBoundingClientRect(); + const translated = Vector.floor(Vector.div([clientX - left, clientY - top], tileSize)); + stamp(translated); + setIsHoldingPaint(true); + break; + } + case 'touchmove': + case 'mousemove': { + if (isHoldingPaint) { + const {left, top} = target.getBoundingClientRect(); + const translated = Vector.floor(Vector.div([clientX - left, clientY - top], tileSize)); + stamp(translated); + } + break; + } + case 'touchend': + case 'mouseup': { + setIsHoldingPaint(false); + break; + } + default: + } }; events.onValue(onValue); return () => { @@ -169,7 +227,7 @@ function TilesPage({ // eslint-disable-next-line react/no-array-index-key