修正又被穿透、不能拖曳也不能右鍵:點穿改用人物方框判定
根本原因: 點穿是逐像素讀 canvas 該點的 alpha 來決定,而 2.0.7 起每一幀都會重驗。 人物的手腳與邊緣會隨動畫在透明/不透明之間切換(實測小念 hover 時 idle+jumping 共 11 幀,只有 44% 的人物像素每一幀都不透明;running 也只有 56%),游標停在邊緣時點穿位元就跟著動畫高速切換,按下去那一瞬間剛好是 透明幀,滑鼠事件就穿到底下的視窗去了。hover 會觸發跳三下,正好是使用者 伸手要抓寵物的時候,最容易中。 影響: 游標明明在寵物身上,左鍵拖不動、右鍵沒有選單,點擊落到底下的視窗。 修法: 點穿與 hover 一樣改用人物方框(canvas 矩形)或氣泡矩形判定,狀態只取決於 游標位置,不再與動畫幀連動;移除 overSprite 與 tick 內的每幀重驗。這也是 Codex 的做法。README 對應段落與對照表同步更新。版號 2.0.10。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+8
-21
@@ -149,7 +149,7 @@ function startAnim(anim, now) {
|
||||
let bubbleTimer = null;
|
||||
let bubbleSticky = false;
|
||||
let ignoringMouse = true;
|
||||
let hovered = false; // 游標是否壓在人物的不透明像素上
|
||||
let hovered = false; // 游標是否在人物方框內
|
||||
let lastPoint = null; // 最後已知的游標位置(視窗相對),主程序輪詢或 mousemove 都會更新
|
||||
let pressed = null;
|
||||
let lastReported = "";
|
||||
@@ -555,9 +555,6 @@ function tick(now) {
|
||||
prevBase = base;
|
||||
|
||||
draw(anim);
|
||||
// 換格會改變游標底下的像素。游標沒移動時主程序不會再送座標,
|
||||
// 所以這裡自己重驗一次,否則會卡在點穿狀態動不了。
|
||||
if (lastPoint && overPetArea(lastPoint.x, lastPoint.y)) refreshHitTest();
|
||||
requestAnimationFrame(tick);
|
||||
}
|
||||
|
||||
@@ -630,21 +627,10 @@ function overBubble(x, y) {
|
||||
return x >= r.left && x <= r.right && y >= r.top && y <= r.bottom;
|
||||
}
|
||||
|
||||
// 壓在人物的不透明像素上(透明處要讓滑鼠穿過去)
|
||||
function overSprite(x, y) {
|
||||
const r = canvas.getBoundingClientRect();
|
||||
if (x < r.left || x >= r.right || y < r.top || y >= r.bottom) return false;
|
||||
const px = Math.floor((x - r.left) * (canvas.width / r.width));
|
||||
const py = Math.floor((y - r.top) * (canvas.height / r.height));
|
||||
try {
|
||||
return ctx.getImageData(px, py, 1, 1).data[3] > 20;
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// hover 判定用人物方框,不用逐像素 alpha:sprite 每一格的輪廓不同,逐像素會讓游標停著不動時
|
||||
// 也在 true/false 之間高速抖動。Codex 的 pet-area-hover 同樣是用矩形算的。
|
||||
// hover 與點穿都用人物方框,不用逐像素 alpha:sprite 每一格的輪廓不同,人物的手腳與邊緣
|
||||
// 會隨動畫在透明/不透明之間切換,逐像素會讓游標停著不動時也在 true/false 之間高速抖動;
|
||||
// 點穿跟著抖,按下去那一瞬間剛好是透明格,滑鼠事件就穿到底下的視窗去了(看起來就是
|
||||
// 「又被穿透了、不能拖曳也不能右鍵」)。Codex 的 pet-area-hover 同樣是用矩形算的。
|
||||
function overPetArea(x, y) {
|
||||
const r = canvas.getBoundingClientRect();
|
||||
return x >= r.left && x < r.right && y >= r.top && y < r.bottom;
|
||||
@@ -674,8 +660,9 @@ function setHovered(on) {
|
||||
function refreshHitTest() {
|
||||
if (!lastPoint || pressed || drag) return; // 拖曳中不要動點穿狀態
|
||||
const { x, y } = lastPoint;
|
||||
setHovered(overPetArea(x, y));
|
||||
setIgnore(!(overSprite(x, y) || overBubble(x, y)));
|
||||
const inArea = overPetArea(x, y);
|
||||
setHovered(inArea);
|
||||
setIgnore(!(inArea || overBubble(x, y)));
|
||||
}
|
||||
|
||||
function setIgnore(ignore) {
|
||||
|
||||
Reference in New Issue
Block a user