第二批反馈:引擎改造(限幅/SoundTouch不变调变速/长按快进/跳句/iOS闪光降级) + 6游戏状态BGM与试玩测试全绿
This commit is contained in:
+60
-1
@@ -2,6 +2,7 @@
|
||||
* gesture.js — 6 手势识别(触摸 + 鼠标双支持),对齐 Android GestureEngine 行为。
|
||||
*
|
||||
* 手势集合:'up' | 'down' | 'left' | 'right' | 'tap' | 'doubletap'
|
||||
* | 'longpress' | 'longpressend'
|
||||
*
|
||||
* 判定规则(与 Android 版 GestureConfig 一致):
|
||||
* - 滑动:累积位移 >= swipeMinDistance(默认 64px ≈ 64dp@160dpi)
|
||||
@@ -10,6 +11,12 @@
|
||||
* - 单击/双击:位移 < tapSlop 视为点按;双击窗口 doubleTapWindow(默认 300ms)。
|
||||
* **单击回调有约 300ms 延迟**(要等双击窗口关闭才能确定不是双击),
|
||||
* 即时反馈类操作请绑定滑动或双击,单击只用于非即时操作。
|
||||
* - **长按**:按住不动 >= longpressMs(默认 450ms)触发 'longpress',
|
||||
* 松开触发 'longpressend';长按期间不触发 tap;位移超 tapSlop 取消
|
||||
* (已激活的长按会先补发 'longpressend',之后滑动照常判定)。
|
||||
* 长按触发/结束同时派发 window 事件 'soundgame:longpress' /
|
||||
* 'soundgame:longpressend'——audio.js 内置监听:voice 播放中长按 =
|
||||
* 旁白临时 1.7 倍速(不变调),松开恢复设置语速,游戏代码零改动。
|
||||
*
|
||||
* 用法:
|
||||
* import { attachGestures } from '../engine/gesture.js';
|
||||
@@ -32,8 +39,17 @@ export const DEFAULT_GESTURE_CONFIG = {
|
||||
swipeMinVelocity: 400, // px/s,平均速度阈值(位移 / 拖动时长)
|
||||
doubleTapWindow: 300, // ms,双击判定窗口(单击因此延迟 ~300ms 回调)
|
||||
tapSlop: 24, // px,位移小于此值才算点按
|
||||
longpressMs: 450, // ms,按住不动超过此值触发 longpress
|
||||
};
|
||||
|
||||
/** 长按引擎事件:audio.js 监听它实现"长按=旁白临时倍速"。 */
|
||||
function _dispatchLongpress(type) {
|
||||
if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function'
|
||||
&& typeof CustomEvent === 'function') {
|
||||
window.dispatchEvent(new CustomEvent(`soundgame:${type}`));
|
||||
}
|
||||
}
|
||||
|
||||
export function attachGestures(element, onGesture, config = {}) {
|
||||
const cfg = { ...DEFAULT_GESTURE_CONFIG, ...config };
|
||||
|
||||
@@ -42,6 +58,10 @@ export function attachGestures(element, onGesture, config = {}) {
|
||||
let startX = 0, startY = 0, startTime = 0;
|
||||
let moved = false; // 位移是否已超 tapSlop(超过则本次不可能是点按)
|
||||
|
||||
// 长按状态
|
||||
let longPressTimer = null;
|
||||
let longPressActive = false;
|
||||
|
||||
// 点按状态
|
||||
let lastTapTime = 0;
|
||||
let pendingTapTimer = null;
|
||||
@@ -56,22 +76,57 @@ export function attachGestures(element, onGesture, config = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
function cancelLongPress() {
|
||||
if (longPressTimer !== null) {
|
||||
clearTimeout(longPressTimer);
|
||||
longPressTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** 长按已激活后收尾(松开/滑动取消):补发 longpressend。 */
|
||||
function endLongPress() {
|
||||
if (!longPressActive) return;
|
||||
longPressActive = false;
|
||||
_dispatchLongpress('longpressend');
|
||||
onGesture('longpressend');
|
||||
}
|
||||
|
||||
function handleDown(x, y) {
|
||||
tracking = true;
|
||||
moved = false;
|
||||
startX = x;
|
||||
startY = y;
|
||||
startTime = performance.now();
|
||||
cancelLongPress();
|
||||
longPressTimer = setTimeout(() => {
|
||||
longPressTimer = null;
|
||||
if (!tracking || moved) return;
|
||||
// 触发长按:作废等待中的单击
|
||||
cancelPendingTap();
|
||||
longPressActive = true;
|
||||
_dispatchLongpress('longpress');
|
||||
onGesture('longpress');
|
||||
}, cfg.longpressMs);
|
||||
}
|
||||
|
||||
function handleMove(x, y) {
|
||||
if (!tracking) return;
|
||||
if (Math.hypot(x - startX, y - startY) > cfg.tapSlop) moved = true;
|
||||
if (Math.hypot(x - startX, y - startY) > cfg.tapSlop) {
|
||||
moved = true;
|
||||
cancelLongPress(); // 滑动取消长按判定
|
||||
endLongPress(); // 已激活的长按被滑动终止(之后滑动照常判定)
|
||||
}
|
||||
}
|
||||
|
||||
function handleUp(x, y) {
|
||||
if (!tracking) return;
|
||||
tracking = false;
|
||||
cancelLongPress();
|
||||
if (longPressActive) {
|
||||
endLongPress();
|
||||
lastTapTime = 0;
|
||||
return; // 长按后不触发 tap/doubletap
|
||||
}
|
||||
|
||||
const dx = x - startX;
|
||||
const dy = y - startY;
|
||||
@@ -115,6 +170,8 @@ export function attachGestures(element, onGesture, config = {}) {
|
||||
|
||||
function handleCancel() {
|
||||
tracking = false;
|
||||
cancelLongPress();
|
||||
endLongPress();
|
||||
}
|
||||
|
||||
// ---- 触摸 ----
|
||||
@@ -178,6 +235,8 @@ export function attachGestures(element, onGesture, config = {}) {
|
||||
|
||||
return function detach() {
|
||||
cancelPendingTap();
|
||||
cancelLongPress();
|
||||
endLongPress();
|
||||
element.removeEventListener('touchstart', onTouchStart, opts);
|
||||
element.removeEventListener('touchmove', onTouchMove, opts);
|
||||
element.removeEventListener('touchend', onTouchEnd, opts);
|
||||
|
||||
Reference in New Issue
Block a user