feat: fill
This commit is contained in:
parent
649f5ce859
commit
ad0916727e
|
@ -1,10 +1,9 @@
|
|||
export default function floodwalk2D(b, data, [x, y, w, h]) {
|
||||
export default function floodwalk2D(eligible, data, [x, y, w, h]) {
|
||||
const n = data.length;
|
||||
let i = x + w * y;
|
||||
if (i < 0 || i >= n) {
|
||||
return [];
|
||||
}
|
||||
// const b = data[i];
|
||||
const points = [];
|
||||
const seen = [];
|
||||
seen[-1] = true;
|
||||
|
@ -13,7 +12,7 @@ export default function floodwalk2D(b, data, [x, y, w, h]) {
|
|||
while (todo.length > 0) {
|
||||
i = todo.pop();
|
||||
const v = data[i];
|
||||
if (!b.has(v)) {
|
||||
if (!eligible.has(v)) {
|
||||
// eslint-disable-next-line no-continue
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@ import {
|
|||
Stage,
|
||||
} from '@avocado/graphics';
|
||||
import {
|
||||
floodwalk2D,
|
||||
mod,
|
||||
randomNumber,
|
||||
Rectangle,
|
||||
Vector,
|
||||
} from '@avocado/math';
|
||||
|
@ -61,6 +64,7 @@ function TilesPage({
|
|||
const [mute, setMute] = useState(Array(layerCount).fill(false));
|
||||
const [selection, setSelection] = useState([0, 0, 16, 16]);
|
||||
const [tilesetMode, setTilesetMode] = useState(0);
|
||||
const [fillMode, setFillMode] = useState(0);
|
||||
const [viewport, setViewport] = useState([0, 0]);
|
||||
const onRef = useCallback((stage) => {
|
||||
setTilesetEvents(stage?.events());
|
||||
|
@ -107,7 +111,7 @@ function TilesPage({
|
|||
return undefined;
|
||||
}
|
||||
const tileSize = [16, 16];
|
||||
const stamp = (translated) => {
|
||||
const stamp = (origin) => {
|
||||
const position = Vector.div([selection[0], selection[1]], tileSize);
|
||||
const size = Vector.div([selection[2], selection[3]], tileSize);
|
||||
let [x, y] = position;
|
||||
|
@ -120,7 +124,7 @@ function TilesPage({
|
|||
x -= size[0];
|
||||
y += 1;
|
||||
}
|
||||
const where = Rectangle.compose(translated, size);
|
||||
const where = Rectangle.compose(origin, size);
|
||||
room.tiles[currentLayer].stampAt(where, stamp);
|
||||
room.tiles[currentLayer].emit('update', where);
|
||||
const {data} = room.tiles[currentLayer].toJSON();
|
||||
|
@ -137,25 +141,113 @@ function TilesPage({
|
|||
});
|
||||
}
|
||||
};
|
||||
const fill = (origin) => {
|
||||
const position = Vector.div([selection[0], selection[1]], tileSize);
|
||||
const size = Vector.div([selection[2], selection[3]], tileSize);
|
||||
const {width} = room.tiles[currentLayer];
|
||||
const {$$data} = room.tiles[currentLayer];
|
||||
const updates = floodwalk2D(
|
||||
new Set([$$data[width * origin[1] + origin[0]]]),
|
||||
room.tiles[currentLayer].$$data,
|
||||
Rectangle.compose(origin, room.tiles[currentLayer].area),
|
||||
);
|
||||
const [min, max] = [[Infinity, Infinity], [-Infinity, -Infinity]];
|
||||
for (let i = 0; i < updates.length; i++) {
|
||||
const update = updates[i];
|
||||
const [x, y] = [update % width, Math.floor(update / width)];
|
||||
const offset = Vector.sub([x, y], origin);
|
||||
if (x < min[0]) {
|
||||
min[0] = x;
|
||||
}
|
||||
else if (x > max[0]) {
|
||||
max[0] = x;
|
||||
}
|
||||
if (y < min[1]) {
|
||||
min[1] = y;
|
||||
}
|
||||
else if (y > max[1]) {
|
||||
max[1] = y;
|
||||
}
|
||||
let tileLocation;
|
||||
switch (fillMode) {
|
||||
case 0: {
|
||||
tileLocation = Vector.add(
|
||||
position,
|
||||
[
|
||||
mod(offset[0], size[0]),
|
||||
mod(offset[1], size[1]),
|
||||
],
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
tileLocation = Vector.add(
|
||||
position,
|
||||
[
|
||||
Math.floor(randomNumber(0, size[0])),
|
||||
Math.floor(randomNumber(0, size[1])),
|
||||
],
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
$$data[update] = (tileLocation[1] * (viewport[0] / tileSize[0])) + tileLocation[0];
|
||||
}
|
||||
const where = Rectangle.compose(min, Vector.add([1, 1], Vector.sub(max, min)));
|
||||
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 = (
|
||||
{
|
||||
position,
|
||||
type,
|
||||
},
|
||||
) => {
|
||||
const origin = Vector.floor(Vector.div(position, tileSize));
|
||||
switch (type) {
|
||||
case 'touchstart':
|
||||
case 'mousedown': {
|
||||
const translated = Vector.floor(Vector.div(position, tileSize));
|
||||
stamp(translated);
|
||||
switch (tilesetMode) {
|
||||
case 0: {
|
||||
stamp(origin);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
fill(origin);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
setIsHoldingPaint(true);
|
||||
break;
|
||||
}
|
||||
case 'touchmove':
|
||||
case 'mousemove': {
|
||||
if (isHoldingPaint) {
|
||||
const translated = Vector.floor(Vector.div(position, tileSize));
|
||||
stamp(translated);
|
||||
switch (tilesetMode) {
|
||||
case 0: {
|
||||
stamp(origin);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
fill(origin);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -291,9 +383,14 @@ function TilesPage({
|
|||
<option value={1}>Fill</option>
|
||||
</select>
|
||||
{1 === tilesetMode && (
|
||||
<select>
|
||||
<option>Tiling</option>
|
||||
<option>Random</option>
|
||||
<select
|
||||
defaultValue={fillMode}
|
||||
onChange={(event) => {
|
||||
setFillMode(parseInt(event.target.value, 10));
|
||||
}}
|
||||
>
|
||||
<option value={0}>Tiling</option>
|
||||
<option value={1}>Random</option>
|
||||
</select>
|
||||
)}
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue
Block a user