Move to Kaplay

This commit is contained in:
MeowcaTheoRange 2024-06-01 01:31:08 -05:00
parent 5b2aa4dc8b
commit 30ac08e50f
7 changed files with 7184 additions and 127 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,114 +1,160 @@
import "./leaflet.js"; // window.L
const options = {
lang: "en_US",
offs: 0,
viewportPadding: 20,
boundsPadding: 0.1,
}
const defaultPolyStyling = {
color: "#000000",
opacity: 1,
fill: true,
fillOpacity: 0.25,
weight: 3
import kaplay from "./modules/kaplay.js";
const map = document.querySelector("map");
class KaplayMap {
kp;
opts = {
minZoomLevel: 0,
maxZoomLevel: 3,
};
function moveBounds(polys, xoff = 0, yoff = xoff) {
return polys.map(([x, y]) => [y + yoff, x + xoff]);
#zoomLevel = 0;
#scaleTween = null;
startMousePos = null;
startCamPos = null;
prevCamPos = null;
moveVelocity = null;
moveFriction = 0.25;
moveDead = 1;
#moveTween = null;
constructor(kp, opts) {
this.kp = kp;
this.opts = {
...this.opts,
...opts,
};
// Zooming
this.kp.onScroll((delta) => {
const scrollDist = -delta.y / 120;
this.zoomTo(this.zoomLevel + scrollDist, this.kp.mousePos());
});
// Dragging
this.kp.onUpdate(() => {
const curCamPos = this.kp.camPos();
const camScale = 1 / this.kp.camScale().y;
// ||| Completely unintelligible to the average person |||
// vvv Sorry y'all xwx vvv
if (this.kp.isMousePressed()) {
this.startMousePos = this.kp.mousePos();
this.startCamPos = this.kp.camPos();
} else if (this.kp.isMouseReleased() && this.prevCamPos != null) {
this.moveVelocity = this.prevCamPos.sub(curCamPos).scale(1 / camScale);
}
// Get tile data
async function getTileData(floor) {
let tileDataReq = await fetch(`/data/${options.lang}/map/${floor}`);
let tileData;
if (tileDataReq.ok)
tileData = await tileDataReq.json();
return tileData.map((room) =>
L.polygon(moveBounds(room.poly, options.offs), defaultPolyStyling)
if (this.kp.isMouseDown()) {
this.prevCamPos = this.kp.camPos();
this.kp.camPos(
this.startCamPos.sub(
this.kp.mousePos().sub(this.startMousePos).scale(camScale)
)
);
}
} else if (this.moveVelocity?.x != 0 && this.moveVelocity?.y != 0)
this.kp.camPos(curCamPos.sub(this.moveVelocity?.scale(camScale) ?? 0));
// Get floor data
// ^^^ Completely unintelligible to the average person ^^^
// ||| Sorry y'all xwx |||
async function getFloorData() {
let floorDataReq = await fetch(`/data/${options.lang}/map/`);
let floorData;
if (floorDataReq.ok)
floorData = await floorDataReq.json();
if (this.moveVelocity == null) return;
// Add to Leaflet
if (
this.moveVelocity.x <= this.moveDead &&
this.moveVelocity.x >= -this.moveDead
)
this.moveVelocity.x = 0;
if (
this.moveVelocity.y <= this.moveDead &&
this.moveVelocity.y >= -this.moveDead
)
this.moveVelocity.y = 0;
const floors = await Promise.all(floorData.map(async (data) => {
const tileData = await getTileData(data.id);
const floorPoly = L.polygon(moveBounds(data.poly, options.offs), defaultPolyStyling)
return L.featureGroup([
floorPoly,
...tileData
]);
}));
return {
layers: floorData,
floors: floors
}
}
// Create map
async function createMap() {
const data = await getFloorData();
let map = L.map('leaflet-map', {
center: [0, 0],
zoom: 2,
crs: L.CRS.Simple
});
const mainLayer = L.tileLayer('', {
maxZoom: 4,
minZoom: 1,
attribution: 'Test data'
}).addTo(map);
const floor = data.floors[0].addTo(map);
const layerBounds = floor.getBounds();
const blb = layerBounds.pad(options.boundsPadding);
map.setMaxBounds(blb);
map.fitBounds(layerBounds, { padding: [options.viewportPadding, options.viewportPadding] });
const entries = Object.fromEntries(data.floors.map((floor, i) => [
`${data.layers[i].name}`,
floor
]));
let layerControl = L.control.layers(entries).addTo(map);
return {
floors: data.floors,
map,
mainLayer
};
}
async function mainFunction() {
const { floors, map, mainLayer } = await createMap();
map.on('baselayerchange', ({ layer, name }) => {
const layerBounds = layer.getBounds();
const blb = layerBounds.pad(options.boundsPadding);
map.setMaxBounds(blb);
map.fitBounds(layerBounds, { padding: [options.viewportPadding, options.viewportPadding] });
this.moveVelocity = this.moveVelocity.scale(1 - this.moveFriction);
});
}
mainFunction();
get zoomLevel() {
return this.#zoomLevel;
}
set zoomLevel(newZoom) {
const cameraZoom = this.kp.camScale().y;
let addLinear = newZoom;
if (addLinear < this.opts.minZoomLevel) addLinear = this.opts.minZoomLevel;
if (addLinear > this.opts.maxZoomLevel) addLinear = this.opts.maxZoomLevel;
let linearToLog = Math.pow(2, addLinear);
this.#zoomLevel = addLinear;
if (this.#scaleTween != null) {
this.#scaleTween.finish();
}
this.#scaleTween = this.kp.tween(
cameraZoom,
linearToLog,
0.25,
this.kp.camScale,
this.kp.easings.easeOutQuad
);
this.#scaleTween.then(() => {
this.#scaleTween = null;
});
}
zoomTo(newZoom, position) {
const curCamPos = this.kp.camPos();
const camScale = 1 / this.kp.camScale().y;
const diff = this.kp.center().sub(position).scale(camScale);
this.zoomLevel = newZoom;
let newZoomLog = 1 / Math.pow(2, newZoom);
const newDiff = this.kp.center().sub(position).scale(newZoomLog);
if (newZoom < this.opts.minZoomLevel) return;
if (newZoom > this.opts.maxZoomLevel) return;
if (this.#moveTween != null) {
this.#moveTween.finish();
}
this.#moveTween = this.kp.tween(
curCamPos,
curCamPos.sub(diff).add(newDiff),
0.25,
this.kp.camPos,
this.kp.easings.easeOutQuad
);
this.#moveTween.then(() => {
this.#moveTween = null;
});
}
}
const kp = kaplay({
canvas: map,
focus: true,
loadingScreen: false,
crisp: false,
debug: false,
global: false,
maxFPS: 120,
background: "404040",
});
const kaplaymap = new KaplayMap(kp, {});
const bean = kp.loadBean();
kp.add([kp.sprite("bean"), kp.pos(kp.center())]);

7
assets/styles/style.css Normal file
View file

@ -0,0 +1,7 @@
body, html {
margin: 0;
height: 100vh;
width: 100vw;
box-sizing: border-box;
overflow: hidden;
}

View file

@ -1,16 +0,0 @@
body, html {
margin: 0;
height: 100vh;
width: 100vw;
box-sizing: border-box;
overflow: hidden;
}
#leaflet-map {
background-color: #404040;
display: inline-block;
box-sizing: border-box;
height: 100%;
width: 100%;
}

View file

@ -8,17 +8,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""
/>
<link
rel="stylesheet"
href="/assets/styles/styles.css"
href="/assets/styles/style.css"
/>
</head>
<body>
<div id="leaflet-map"></div>
<canvas id="map"></canvas>
<script src="/assets/scripts/script.js" type="module"></script>
</body>
</html>

View file

@ -39,6 +39,37 @@ app.get('/data/:lang/events', async (req, res) => {
return res.send(merged);
})
app.get('/data/:lang/events/:layer', async (req, res) => {
// Get events
let eventsReq = await fetch(new URL("events/events.json", config.data_url));
let events;
if (eventsReq.ok)
events = await eventsReq.json();
else
return res.status(400).send("Bad Request");
// Get localization
let l10nReq = await fetch(new URL(`localization/${req.params.lang}.json`, config.data_url));
let l10n;
if (l10nReq.ok)
l10n = await l10nReq.json();
else
return res.status(404).send("Localization not found!");
const clippedEvents = events.filter((event) => event.where.layer == req.params.layer);
// Merge events and localization
const merged = events.map(event => {
const localizationKey = l10n.__events[event.id];
return {
...event,
...localizationKey
};
});
return res.send(merged);
})
app.get('/data/:lang/map', async (req, res) => {
// Get layers
let layersReq = await fetch(new URL("map/layers.json", config.data_url));