feat: tiles

This commit is contained in:
cha0s 2024-06-11 15:06:43 -05:00
parent aef8a292d0
commit a31bc01911
9 changed files with 151 additions and 6 deletions

View File

@ -52,7 +52,7 @@ module.exports = {
// Node // Node
{ {
files: ['.eslintrc.cjs', 'server.js', 'vite.config.js', 'websocket.js'], files: ['.eslintrc.cjs', 'server.js', 'vite.config.js', 'websocket.js', 'public/assets/tileset.js'],
env: { env: {
node: true, node: true,
}, },

View File

@ -1,10 +1,14 @@
import {Sprite} from '@pixi/react'; import {Container, Sprite} from '@pixi/react';
import {useState} from 'react'; import {useState} from 'react';
import {RESOLUTION} from '@/constants.js' import {RESOLUTION} from '@/constants.js'
import Ecs from '@/engine/ecs.js'; import Ecs from '@/engine/ecs.js';
import usePacket from '@/hooks/use-packet'; import usePacket from '@/hooks/use-packet';
import TileLayer from './tile-layer';
const tiles = Array(100 * 100).fill(0).map(() => 1 + Math.floor(Math.random() * 4));
export default function EcsComponent() { export default function EcsComponent() {
const [ecs] = useState(new Ecs()); const [ecs] = useState(new Ecs());
const [entities, setEntities] = useState({}); const [entities, setEntities] = useState({});
@ -22,12 +26,14 @@ export default function EcsComponent() {
else { else {
updatedEntities[id] = ecs.get(id); updatedEntities[id] = ecs.get(id);
if (updatedEntities[id].MainEntity) { if (updatedEntities[id].MainEntity) {
if (!mainEntity) {
setMainEntity(ecs.get(id)); setMainEntity(ecs.get(id));
} }
} }
} }
}
setEntities(updatedEntities); setEntities(updatedEntities);
}, [entities]); }, [entities, mainEntity]);
if (!mainEntity) { if (!mainEntity) {
return false; return false;
} }
@ -46,8 +52,16 @@ export default function EcsComponent() {
); );
} }
return ( return (
<> <Container>
<TileLayer
size={{x: 100, y: 100}}
tiles={tiles}
tileset="/assets/tileset.json"
tileSize={{x: 16, y: 16}}
x={-cx}
y={-cy}
/>
{sprites} {sprites}
</> </Container>
) )
} }

View File

@ -0,0 +1,49 @@
import {useEffect, useState} from 'react';
import {PixiComponent} from '@pixi/react';
import '@pixi/spritesheet'; // NECESSARY!
import {CompositeTilemap} from '@pixi/tilemap';
import {Assets} from '@pixi/assets';
const TileLayerInternal = PixiComponent('TileLayer', {
create: () => new CompositeTilemap(),
applyProps: (tilemap, {tiles: oldTiles}, props) => {
const {asset, tiles, tileSize, size, x, y} = props;
const {textures} = asset;
tilemap.position.x = x;
tilemap.position.y = y;
if (tiles === oldTiles) {
return;
}
tilemap.clear();
let i = 0;
for (let y = 0; y < size.y; ++y) {
for (let x = 0; x < size.x; ++x) {
tilemap.tile(textures[tiles[i++]], tileSize.x * x, tileSize.y * y);
}
}
},
})
export default function TileLayer(props) {
const {tileset} = props;
const [asset, setAsset] = useState();
useEffect(() => {
const asset = Assets.get(tileset);
if (asset) {
setAsset(asset);
}
else {
Assets.load(tileset).then(setAsset);
}
}, [setAsset, tileset]);
if (!asset) {
return false;
}
return (
<TileLayerInternal
{...props}
asset={asset}
/>
);
}

41
package-lock.json generated
View File

@ -8,6 +8,8 @@
"dependencies": { "dependencies": {
"@msgpack/msgpack": "^3.0.0-beta2", "@msgpack/msgpack": "^3.0.0-beta2",
"@pixi/react": "^7.1.2", "@pixi/react": "^7.1.2",
"@pixi/spritesheet": "^7.4.2",
"@pixi/tilemap": "^4.1.0",
"@remix-run/express": "^2.9.2", "@remix-run/express": "^2.9.2",
"@remix-run/node": "^2.9.2", "@remix-run/node": "^2.9.2",
"@remix-run/react": "^2.9.2", "@remix-run/react": "^2.9.2",
@ -38,6 +40,7 @@
"eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.33.2", "eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"image-size": "^1.1.1",
"storybook": "^8.1.6", "storybook": "^8.1.6",
"vite": "^5.1.0", "vite": "^5.1.0",
"vitest": "^1.6.0" "vitest": "^1.6.0"
@ -3386,6 +3389,15 @@
"@pixi/sprite": "7.4.2" "@pixi/sprite": "7.4.2"
} }
}, },
"node_modules/@pixi/spritesheet": {
"version": "7.4.2",
"resolved": "https://registry.npmjs.org/@pixi/spritesheet/-/spritesheet-7.4.2.tgz",
"integrity": "sha512-YIvHdpXW+AYp8vD0NkjJmrdnVHTZKidCnx6k8ATSuuvCT6O5Tuh2N/Ul2oDj4/QaePy0lVhyhAbZpJW00Jr7mQ==",
"peerDependencies": {
"@pixi/assets": "7.4.2",
"@pixi/core": "7.4.2"
}
},
"node_modules/@pixi/text": { "node_modules/@pixi/text": {
"version": "7.4.2", "version": "7.4.2",
"resolved": "https://registry.npmjs.org/@pixi/text/-/text-7.4.2.tgz", "resolved": "https://registry.npmjs.org/@pixi/text/-/text-7.4.2.tgz",
@ -3420,6 +3432,11 @@
"@pixi/utils": "7.4.2" "@pixi/utils": "7.4.2"
} }
}, },
"node_modules/@pixi/tilemap": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@pixi/tilemap/-/tilemap-4.1.0.tgz",
"integrity": "sha512-jyc5JqpvPsdsowhkX0VURSMuUd1KdZmG0+Kh11EFGhkrraEKMqTOtU32TPwJb6G0jIqT2o7ynVrG3h5WRoasIg=="
},
"node_modules/@pixi/utils": { "node_modules/@pixi/utils": {
"version": "7.4.2", "version": "7.4.2",
"resolved": "https://registry.npmjs.org/@pixi/utils/-/utils-7.4.2.tgz", "resolved": "https://registry.npmjs.org/@pixi/utils/-/utils-7.4.2.tgz",
@ -11125,6 +11142,21 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/image-size": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz",
"integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==",
"dev": true,
"dependencies": {
"queue": "6.0.2"
},
"bin": {
"image-size": "bin/image-size.js"
},
"engines": {
"node": ">=16.x"
}
},
"node_modules/import-fresh": { "node_modules/import-fresh": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@ -14936,6 +14968,15 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/queue": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
"integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
"dev": true,
"dependencies": {
"inherits": "~2.0.3"
}
},
"node_modules/queue-microtask": { "node_modules/queue-microtask": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",

View File

@ -14,6 +14,8 @@
"dependencies": { "dependencies": {
"@msgpack/msgpack": "^3.0.0-beta2", "@msgpack/msgpack": "^3.0.0-beta2",
"@pixi/react": "^7.1.2", "@pixi/react": "^7.1.2",
"@pixi/spritesheet": "^7.4.2",
"@pixi/tilemap": "^4.1.0",
"@remix-run/express": "^2.9.2", "@remix-run/express": "^2.9.2",
"@remix-run/node": "^2.9.2", "@remix-run/node": "^2.9.2",
"@remix-run/react": "^2.9.2", "@remix-run/react": "^2.9.2",
@ -44,6 +46,7 @@
"eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.33.2", "eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"image-size": "^1.1.1",
"storybook": "^8.1.6", "storybook": "^8.1.6",
"vite": "^5.1.0", "vite": "^5.1.0",
"vitest": "^1.6.0" "vitest": "^1.6.0"

36
public/assets/tileset.js Normal file
View File

@ -0,0 +1,36 @@
import {writeFileSync} from 'node:fs';
import {basename, dirname, extname, join} from 'node:path';
import imageSize from 'image-size';
const tileset = process.argv[2];
const w = parseInt(process.argv[3]);
const h = parseInt(process.argv[4]);
const {width, height} = imageSize(tileset);
const json = {
frames: {},
meta: {
format: 'RGBA8888',
image: tileset,
scale: 1,
size: {w: width, h: height},
},
};
let i = 0;
for (let y = 0; y < height; y += h) {
for (let x = 0; x < width; x += w) {
json.frames[i++] = {
frame: {x, y, w, h},
spriteSourceSize: {x: 0, y: 0, w, h},
sourceSize: {w, h},
};
}
}
writeFileSync(
`${join(dirname(tileset), basename(tileset, extname(tileset)))}.json`,
JSON.stringify(json),
);

File diff suppressed because one or more lines are too long

BIN
public/assets/tileset.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

View File

@ -35,6 +35,7 @@ export default defineConfig({
], ],
}, },
server: { server: {
host: true,
https: { https: {
key: readFileSync(`${cacheDirectory}/localhost-key.pem`), key: readFileSync(`${cacheDirectory}/localhost-key.pem`),
cert: readFileSync(`${cacheDirectory}/localhost.pem`), cert: readFileSync(`${cacheDirectory}/localhost.pem`),