minigame 2 just begin1.4

This commit is contained in:
2026-04-30 19:18:47 +00:00
parent 8e8c051956
commit f06130deb8
48 changed files with 50 additions and 28 deletions
+25 -11
View File
@@ -2655,6 +2655,19 @@ function gauntletLaserVerticalSpanFromMap(md) {
return { y0, y1 };
}
/**
* แถว grid ของ lane obstacle: แถวเท้า (ขอบล่าง footprint; แถวบนของตัว = player y)
* — สูงกว่าแบบ top+ch หนึ่งช่อง (ไม่ให้ลงเกินพรม)
*/
function gauntletLaneGridRowFromPlayerTop(md, topY, h) {
const { ch } = getCharacterFootprintWHForMove(md);
const top = Math.floor(Number(topY));
if (!Number.isFinite(top) || top < 0 || top >= h) return null;
const lr = top + ch - 1;
if (lr < 0 || lr >= h) return null;
return lr;
}
function runGauntletTick(sid, space) {
const md = (space.mapId && maps.get(space.mapId)) || space.mapData;
if (!md || md.gameType !== 'gauntlet') {
@@ -2684,23 +2697,23 @@ function runGauntletTick(sid, space) {
for (let i = 0; i < gr.obstacles.length; i++) gr.obstacles[i].x -= 1;
gr.obstacles = gr.obstacles.filter((o) => o.x >= 0);
const occupiedY = new Set();
const laneSpawnRows = new Set();
space.peers.forEach((peer) => {
const fy = Math.floor(Number(peer.y));
if (Number.isFinite(fy) && fy >= 0 && fy < h) occupiedY.add(fy);
const lr = gauntletLaneGridRowFromPlayerTop(md, peer.y, h);
if (lr != null) laneSpawnRows.add(lr);
});
/* แถวที่ client แจ้ง (บอท preview อยู่บน client ไม่ใช่ peer) — ให้ spawn lane บนแถวบอทด้วย */
/* แถวบนที่ client แจ้ง (บอท preview) — แปลงเป็นแถว lane เดียวกับ peer */
const previewRows = space.gauntletPreviewRowsBySocket;
if (previewRows && previewRows.size) {
previewRows.forEach((set) => {
set.forEach((y) => {
const fy = Math.floor(Number(y));
if (Number.isFinite(fy) && fy >= 0 && fy < h) occupiedY.add(fy);
const lr = gauntletLaneGridRowFromPlayerTop(md, y, h);
if (lr != null) laneSpawnRows.add(lr);
});
});
}
/* lane obstacle เฉพาะแถวที่มีคน — ลบชิ้นที่ลอยในแถวว่าง */
gr.obstacles = gr.obstacles.filter((o) => o.kind !== 'lane' || occupiedY.has(o.y));
/* lane obstacle เฉพาะแถวที่ยังมีผู้เล่น/บอทในเลนนั้น — ลบชิ้นที่ไม่มีใครแล้ว */
gr.obstacles = gr.obstacles.filter((o) => o.kind !== 'lane' || laneSpawnRows.has(o.y));
gr.spawnAcc = (gr.spawnAcc || 0) + 1;
if (gr.spawnAcc >= (gr.nextSpawnIn || 3)) {
@@ -2711,8 +2724,8 @@ function runGauntletTick(sid, space) {
const span = gauntletLaserVerticalSpanFromMap(md);
gr.obstacles.push({ id: ++gr.nextObsId, kind: 'laser', x: w - 1, y0: span.y0, y1: span.y1 });
}
/* ประเภท 1: แยกเลน — เฉพาะแถวที่มีผู้เล่นยืนอยู่ (สุ่มแยกแถว) */
occupiedY.forEach((ly) => {
/* ประเภท 1: แยกเลน — แถวเท้า (ไม่ใช่แถวหัว; ไม่ใช่แถวใต้เท้าอีกช่อง) */
laneSpawnRows.forEach((ly) => {
if (Math.random() < GAUNTLET_LANE_ROW_SPAWN_CHANCE) {
gr.obstacles.push({ id: ++gr.nextObsId, kind: 'lane', x: w - 1, y: ly });
}
@@ -2720,6 +2733,7 @@ function runGauntletTick(sid, space) {
}
/* กระโดดข้ามสำเร็จ → เลื่อนผู้เล่นไปขวา แต่ไม่ลบ obstacle (ยังไหลต่อให้คนอื่น/รอบถัดไป) */
const { ch: gauntletCh } = getCharacterFootprintWHForMove(md);
space.peers.forEach((p) => {
let px = Math.floor(Number(p.x)) || 0;
let py = Math.floor(Number(p.y)) || 0;
@@ -2729,7 +2743,7 @@ function runGauntletTick(sid, space) {
let advanceX = false;
let hitBack = false;
for (const o of gr.obstacles) {
if (o.kind === 'lane' && o.x === px && o.y === py) {
if (o.kind === 'lane' && o.x === px && o.y >= py && o.y < py + gauntletCh) {
if (air) advanceX = true;
else hitBack = true;
}