游戏重构

This commit is contained in:
xsl
2026-05-18 23:00:14 +08:00
parent b2a3d20761
commit b90238975f
7 changed files with 703 additions and 995 deletions
+62 -69
View File
@@ -1,128 +1,121 @@
// gestures.js — 触控手势检测器(单指操作
// gestures.js — 触控手势检测器(简化版
//
// 支持:单 · 双点 · 长按1s · 长按5s
// 左滑 · 右滑 · 上滑 · 下滑
// 支持 6 种手势:单 · 双击 · 左滑 · 右滑 · 上滑 · 下滑
// 无长按,无多指操作
class GestureDetector {
constructor(el) {
this._el = el;
this._handlers = {};
// 状态
this._startX = 0;
this._startY = 0;
this._startTime = 0;
this._tapTimer = null;
this._longTimer1 = null;
this._longTimer5 = null;
this._longFired = false;
this._tapCount = 0;
this._bind();
this._bindTouch();
this._bindMouse();
this._bindKeyboard();
}
on(evt, fn) { this._handlers[evt] = fn; return this; }
_emit(evt, data) {
_emit(evt) {
dbg(evt);
const fn = this._handlers[evt];
if (fn) fn(data);
if (fn) fn();
}
_bind() {
// ── 触摸事件 ──
_bindTouch() {
const el = this._el;
el.addEventListener('touchstart', e => this._onStart(e), { passive: false });
el.addEventListener('touchend', e => this._onEnd(e), { passive: false });
el.addEventListener('touchcancel', e => this._onCancel(e), { passive: false });
el.addEventListener('touchstart', e => {
e.preventDefault();
const t = e.touches[0];
this._startX = t.clientX;
this._startY = t.clientY;
this._startTime = Date.now();
}, { passive: false });
el.addEventListener('touchend', e => {
e.preventDefault();
const t = e.changedTouches[0];
this._process(t.clientX, t.clientY);
}, { passive: false });
el.addEventListener('touchcancel', () => this._reset(), { passive: false });
}
_onStart(e) {
e.preventDefault();
const t = e.touches[0];
this._startX = t.clientX;
this._startY = t.clientY;
this._startTime = Date.now();
this._longFired = false;
this._clearTimers();
// 1s长按
this._longTimer1 = setTimeout(() => {
this._longFired = true;
this._emit('longpress1s');
Haptic.detailMode();
}, 900);
// 5s长按(安全机制)
this._longTimer5 = setTimeout(() => {
this._longFired = true;
this._emit('longpress5s');
Haptic.reject();
}, 5000);
// ── 鼠标事件(桌面调试)──
_bindMouse() {
this._el.addEventListener('mousedown', e => {
this._startX = e.clientX;
this._startY = e.clientY;
this._startTime = Date.now();
});
this._el.addEventListener('mouseup', e => {
this._process(e.clientX, e.clientY);
});
}
_onEnd(e) {
e.preventDefault();
this._clearTimers();
// ── 键盘事件(桌面调试)──
_bindKeyboard() {
document.addEventListener('keydown', e => {
switch (e.code) {
case 'Space': e.preventDefault(); this._emit('singletap'); break;
case 'Enter': e.preventDefault(); this._emit('doubletap'); break;
case 'ArrowLeft': e.preventDefault(); this._emit('swipe_left'); break;
case 'ArrowRight': e.preventDefault(); this._emit('swipe_right'); break;
case 'ArrowUp': e.preventDefault(); this._emit('swipe_up'); break;
case 'ArrowDown': e.preventDefault(); this._emit('swipe_down'); break;
}
});
}
const t = e.changedTouches[0];
const dx = t.clientX - this._startX;
const dy = t.clientY - this._startY;
// ── 手势判定 ──
_process(endX, endY) {
const dx = endX - this._startX;
const dy = endY - this._startY;
const dist = Math.sqrt(dx * dx + dy * dy);
const dt = Date.now() - this._startTime;
if (this._longFired) return;
// ── 滑动判断 ──
const SWIPE_MIN = 35;
const SWIPE_ANG = 45;
if (dist > SWIPE_MIN) {
// 滑动:距离 > 35px
if (dist > 35) {
const angle = Math.abs(Math.atan2(dy, dx) * 180 / Math.PI);
let dir = null;
if (angle < SWIPE_ANG) dir = 'right';
else if (angle > 180 - SWIPE_ANG) dir = 'left';
if (angle < 45) dir = 'right';
else if (angle > 135) dir = 'left';
else if (dy < 0 && Math.abs(dy) > Math.abs(dx)) dir = 'up';
else if (dy > 0 && Math.abs(dy) > Math.abs(dx)) dir = 'down';
if (dir) {
this._tapCount = 0;
clearTimeout(this._tapTimer);
this._emit(`swipe_${dir}`);
Haptic.confirm();
return;
}
}
// ── 点击判断 ──
// 点击:距离 < 20px,时间 < 500ms
if (dist < 20 && dt < 500) {
this._tapCount++;
if (this._tapCount === 1) {
this._tapTimer = setTimeout(() => {
this._tapCount = 0;
this._emit('singletap');
Haptic.confirm();
}, 250);
} else if (this._tapCount === 2) {
} else if (this._tapCount >= 2) {
clearTimeout(this._tapTimer);
this._tapCount = 0;
this._emit('doubletap');
Haptic.confirm();
}
}
}
_onCancel(e) {
this._clearTimers();
this._longFired = false;
}
_clearTimers() {
_reset() {
clearTimeout(this._tapTimer);
clearTimeout(this._longTimer1);
clearTimeout(this._longTimer5);
this._tapTimer = null;
this._longTimer1 = null;
this._longTimer5 = null;
this._tapCount = 0;
}
}