From ccc068cdf1a91aeeee04ac88db5a654b766e98ad Mon Sep 17 00:00:00 2001 From: giteaadmin Date: Fri, 24 Apr 2026 13:50:43 +0000 Subject: [PATCH] play: clamp preview bot position to footprint bounds; separate clumped bots Made-with: Cursor --- www/html/Game/public/js/play.js | 66 ++++++++++++++++++++++++++++++--- www/html/Game/public/play.html | 2 +- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/www/html/Game/public/js/play.js b/www/html/Game/public/js/play.js index 55ede92..0669e17 100644 --- a/www/html/Game/public/js/play.js +++ b/www/html/Game/public/js/play.js @@ -2091,6 +2091,12 @@ } else { stepPreviewBotAlongPath(o, w, h); } + clampPlayEntityFootprintToMap(o, mapData); + }); + separateClumpedPreviewBots(); + [...others.keys()].filter(isPreviewBotId).forEach((bid) => { + const ob = others.get(bid); + if (ob) clampPlayEntityFootprintToMap(ob, mapData); }); } @@ -5620,6 +5626,50 @@ return { cw: leg, ch: leg }; } + /** กันตัวละคร footprint ล้นออกนอกแมป — เดิมใช้ w-0.01 ทำให้ cw/ch>1 ชนขอบแล้วตรรกะเดินค้าง */ + function clampPlayEntityFootprintToMap(oEnt, md) { + if (!oEnt || !md) return; + const w = md.width || 20, h = md.height || 15; + const { cw, ch } = getCharacterFootprintWH(md); + const maxX = Math.max(0, w - cw + 0.999); + const maxY = Math.max(0, h - ch + 0.999); + if (!Number.isFinite(oEnt.x)) oEnt.x = 0.5; + if (!Number.isFinite(oEnt.y)) oEnt.y = 0.5; + oEnt.x = Math.max(0, Math.min(maxX, oEnt.x)); + oEnt.y = Math.max(0, Math.min(maxY, oEnt.y)); + } + + /** แยกบอท preview ที่ทับกันบนจุดเดียว (มักชนกันที่ขอบแมป) */ + function separateClumpedPreviewBots() { + if (!previewFillBots || !mapData) return; + const ids = [...others.keys()].filter(isPreviewBotId); + const minD = 0.52; + const pushAmt = MOVE_SPEED * 0.5; + for (let i = 0; i < ids.length; i++) { + for (let j = i + 1; j < ids.length; j++) { + const a = others.get(ids[i]); + const b = others.get(ids[j]); + if (!a || !b) continue; + let ddx = b.x - a.x, ddy = b.y - a.y; + let d = Math.sqrt(ddx * ddx + ddy * ddy); + if (d >= minD) continue; + if (d < 1e-5) { + ddx = (i + j * 2) % 2 === 0 ? 1 : -1; + ddy = ((i + j) % 3) - 1; + d = Math.sqrt(ddx * ddx + ddy * ddy) || 1; + } + const ux = -ddx / d, uy = -ddy / d; + const vx = ddx / d, vy = ddy / d; + const ax2 = a.x + ux * pushAmt, ay2 = a.y + uy * pushAmt; + const bx2 = b.x + vx * pushAmt, by2 = b.y + vy * pushAmt; + if (canWalkLikeLobbyForBot(ax2, ay2, a.x, a.y, a)) { a.x = ax2; a.y = ay2; } + if (canWalkLikeLobbyForBot(bx2, by2, b.x, b.y, b)) { b.x = bx2; b.y = by2; } + clampPlayEntityFootprintToMap(a, mapData); + clampPlayEntityFootprintToMap(b, mapData); + } + } + } + function quizTilesFootprintPlay(px, py) { const s = new Set(); if (!mapData) return s; @@ -5825,8 +5875,7 @@ if (Math.sqrt(ux * ux + uy * uy) > PATH_ARRIVE_THRESH) break; path.shift(); } - o.x = Math.max(0, Math.min(w - 0.01, o.x)); - o.y = Math.max(0, Math.min(h - 0.01, o.y)); + clampPlayEntityFootprintToMap(o, mapData); return; } const len = dist || 1; @@ -5870,8 +5919,7 @@ } } } - o.x = Math.max(0, Math.min(w - 0.01, o.x)); - o.y = Math.max(0, Math.min(h - 0.01, o.y)); + clampPlayEntityFootprintToMap(o, mapData); if (Math.abs(o.x - ox) > 1e-5 || Math.abs(o.y - oy) > 1e-5) { o.botIsWalking = true; o.botPathStuckTicks = 0; @@ -5953,10 +6001,16 @@ o.botWanderDy = d[1]; o.botWanderNextTurn = now + 200 + Math.floor(Math.random() * 600); } - o.x = Number.isFinite(o.x) ? Math.max(0, Math.min(w - 0.01, o.x)) : 0.5; - o.y = Number.isFinite(o.y) ? Math.max(0, Math.min(h - 0.01, o.y)) : 0.5; + if (!Number.isFinite(o.x)) o.x = 0.5; + if (!Number.isFinite(o.y)) o.y = 0.5; + clampPlayEntityFootprintToMap(o, mapData); if (Math.abs(o.x - ox) > 1e-5 || Math.abs(o.y - oy) > 1e-5) o.botIsWalking = true; }); + separateClumpedPreviewBots(); + [...others.keys()].filter(isPreviewBotId).forEach((bid) => { + const ob = others.get(bid); + if (ob) clampPlayEntityFootprintToMap(ob, mapData); + }); if (isQuizBattle() && quizBattlePathModeActive(mapData)) { others.forEach((o, id) => { if (!isPreviewBotId(id)) return; diff --git a/www/html/Game/public/play.html b/www/html/Game/public/play.html index 176227e..b557a0a 100644 --- a/www/html/Game/public/play.html +++ b/www/html/Game/public/play.html @@ -669,7 +669,7 @@ - +
v —