Files
SoundGame/web/engine/haptics.js
T
SoundGame Dev cc0f8c008d HTML5 重写:6 款游戏 + 用户系统 + 全局设置 + 5 轮迭代重构
- 新增 web/ 纯音频 HTML5 平台:共享引擎(手势/WebAudio 三层/设置/震动)、
  Node 零依赖服务器(静态 + 注册登录 + 进度存档 API)
- 游戏:剑与声(RPG 新作)、声命线、暗室(重设计)、音序回响(重设计)、
  节拍行者(跟随领奏重构)、盲航(同向闪避重构);声东击西删除
- 全局功能:男声/女声双套 TTS 资产、三档语速、BGM 音量三档、
  震动反馈语言(10 种震型)、服务器进度同步
- 资产:899 ogg + 899 m4a(Qwen3-TTS 双性别语音、Stable Audio 3 音效、
  Mureka BGM 4+3 首),终检零缺失
- 文档:docs/design/ 13 篇设计审查文档、docs/audio/ 资产管线、
  web/server/README.md API 文档
2026-08-29 21:55:44 +08:00

67 lines
2.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* haptics.js — navigator.vibrate 震动反馈封装。
*
* 预定义震型:
* | 名称 | 震型 (ms) | 建议用途 |
* |-----------|----------------------|------------------------|
* | confirm | [20] | 点按确认 |
* | error | [60,40,60] | 操作错误 |
* | success | [100] | 过关/成功 |
* | warning | [30,50,30,50,30] | 警告/危险逼近 |
* | swipe | [10] | 滑动识别成功(最轻) |
* | heartbeat | [40,100,40] | 心跳/倒计时紧张感 |
* | pickup | [15] | 拾取/获得物品 |
* | hit | [80] | 受击/终结性失败 |
* | beat | [8] | 节拍锚点(最轻) |
* | danger | [25,40,25,40,25] | 危险逼近 |
*
* 特性检测:'vibrate' in navigator。不支持的平台(iOS Safari 等)
* 所有调用静默 no-op,不抛异常。
*
* 用法:
* import { vibrate } from '../engine/haptics.js';
* vibrate('confirm'); // 预定义名称
* vibrate([50, 30, 50]); // 自定义震型
*
* 注意:gesture.js 已内置基础反馈(滑动→swipe,tap/doubletap→confirm),
* 游戏逻辑层只需在语义事件(错误/成功/警告等)处自行调用。
*/
/** @type {Record<string, number[]>} */
export const HAPTIC_PATTERNS = {
confirm: [20],
error: [60, 40, 60],
success: [100],
warning: [30, 50, 30, 50, 30],
swipe: [10],
heartbeat: [40, 100, 40],
pickup: [15],
hit: [80],
beat: [8],
danger: [25, 40, 25, 40, 25],
};
/** 当前环境是否支持震动(iOS Safari 为 false)。 */
export const hapticsSupported =
typeof navigator !== 'undefined' && 'vibrate' in navigator;
/**
* 触发震动。不支持时静默 no-op。
* @param {keyof typeof HAPTIC_PATTERNS | number[]} pattern 预定义名称或毫秒数组
*/
export function vibrate(pattern) {
if (!hapticsSupported) return;
const p = typeof pattern === 'string' ? HAPTIC_PATTERNS[pattern] : pattern;
if (!p) {
console.warn('[haptics] 未知震型:', pattern);
return;
}
try {
navigator.vibrate(p);
} catch (_) {
// 某些平台调用即抛(极少见)→ 静默
}
}
export default vibrate;