优化问题

This commit is contained in:
truewhile
2026-09-17 14:17:09 +08:00
parent 9c1f9a6e7e
commit 30ca94c79b
5 changed files with 301 additions and 72 deletions
+40
View File
@@ -0,0 +1,40 @@
import {
LOCK_ZONE_HEIGHT,
LOCK_ZONE_WIDTH,
isPointerInLockZone,
} from './playerLockZone.ts'
function check(name: string, condition: boolean) {
if (!condition) throw new Error(`playerLockZone: ${name}`)
}
const H = 800
const MID = H / 2
// 命中:紧贴左边缘、垂直正中。
check('left edge at vertical center hits', isPointerInLockZone(0, MID, H))
check('inside the zone near the left hits', isPointerInLockZone(LOCK_ZONE_WIDTH - 1, MID, H))
check('top of the zone still hits', isPointerInLockZone(10, MID - LOCK_ZONE_HEIGHT / 2, H))
check('bottom of the zone still hits', isPointerInLockZone(10, MID + LOCK_ZONE_HEIGHT / 2, H))
// 未命中:右侧超出宽度、上下超出高度、中心之外。
check('beyond the width misses', !isPointerInLockZone(LOCK_ZONE_WIDTH + 1, MID, H))
check('just past the width edge misses', !isPointerInLockZone(LOCK_ZONE_WIDTH + 0.5, MID, H))
check('above the zone misses', !isPointerInLockZone(10, MID - LOCK_ZONE_HEIGHT / 2 - 1, H))
check('below the zone misses', !isPointerInLockZone(10, MID + LOCK_ZONE_HEIGHT / 2 + 1, H))
check('negative x misses', !isPointerInLockZone(-1, MID, H))
check('top-left corner misses', !isPointerInLockZone(0, 0, H))
check('right edge at center misses', !isPointerInLockZone(1200, MID, H))
// 不同画面高度下感应区跟着中心移动。
check('tracks center on a short stage', isPointerInLockZone(10, 300, 600))
check('short stage: off-center misses', !isPointerInLockZone(10, MID, 600))
// 脏数据一律不命中,避免锁在奇怪的位置冒出来。
check('NaN x misses', !isPointerInLockZone(Number.NaN, MID, H))
check('NaN y misses', !isPointerInLockZone(10, Number.NaN, H))
check('zero stage height misses', !isPointerInLockZone(10, 0, 0))
check('negative stage height misses', !isPointerInLockZone(10, 0, -100))
check('NaN stage height misses', !isPointerInLockZone(10, 0, Number.NaN))
console.log('playerLockZone.test.ts ok')
+27
View File
@@ -0,0 +1,27 @@
// 播放器「锁」按钮的几何判定。
//
// 锁按钮默认隐身:桌面端靠鼠标移到画面左侧中间把它唤出来,移动端靠点击画面。
// 这里用坐标判断鼠标是否落在感应区里,而不是在画面上摆一个透明的热区元素——
// 隐形热区会吃掉全景拖动的手势,也会挡住画面本身的单击。
/** 感应区宽度(像素),自画面左边缘向右展开。 */
export const LOCK_ZONE_WIDTH = 72
/** 感应区高度(像素),以画面垂直中心为基准上下各展开一半。 */
export const LOCK_ZONE_HEIGHT = 88
/**
* 判断鼠标位置(相对画面左上角)是否落在锁按钮的感应区内。
*
* 参数异常(NaN、画面高度为 0 等)一律返回 false:宁可锁不出现,也不要因为
* 拿到脏数据让它在莫名其妙的位置冒出来。
*/
export function isPointerInLockZone(
offsetX: number,
offsetY: number,
stageHeight: number,
): boolean {
if (!Number.isFinite(offsetX) || !Number.isFinite(offsetY)) return false
if (!Number.isFinite(stageHeight) || stageHeight <= 0) return false
if (offsetX < 0 || offsetX > LOCK_ZONE_WIDTH) return false
return Math.abs(offsetY - stageHeight / 2) <= LOCK_ZONE_HEIGHT / 2
}