save code

This commit is contained in:
xsl
2026-05-24 12:35:35 +08:00
parent af3a23520d
commit b3384499e3
6 changed files with 121 additions and 167 deletions
+24 -7
View File
@@ -52,10 +52,10 @@ class GameEngine {
if (!el) return;
const H = {
idle: '',
notification: '单击 播放 · 双击 跳过',
ringing: '单击 接听 · 左滑 拒接',
notification: '单击 播放 · 双击/左滑 跳过',
ringing: '单击/右滑 接听 · 左滑/双击 拒接',
playing: '双击 跳过 · 长按 重播',
choosing: '→温暖 ←冷淡 ↑追问 ↓沉默',
choosing: '单击回应 · →温暖 ←冷淡 ↑追问 ↓沉默 · 双击跳过',
responding: '双击 跳过',
reacting: '双击 跳过',
paused: '单击 继续 · 三指点击 退出',
@@ -286,9 +286,13 @@ class GameEngine {
this._skipRequested = false;
// 文字消息(TTS 朗读)
// 文字消息(TTS 朗读,不可用时播放提示音
if (msg.type === 'wechat_text' && msg.text) {
await TTS.speak(msg.text);
const ok = await TTS.speak(msg.text);
if (!ok) {
SFX_UI.notify();
await sleep(600);
}
}
// 语音消息
else if (msg.audio?.length > 0) {
@@ -546,6 +550,9 @@ class GameEngine {
this._playMessage(this.currentMsg);
} else if (s === 'choosing') {
this._handleChoice('tap');
} else if (s === 'idle') {
SFX_UI.error();
Haptic.error();
}
}
@@ -598,6 +605,11 @@ class GameEngine {
this._skipChoice();
return;
}
if (s === 'idle') {
SFX_UI.error();
Haptic.error();
}
}
_onSwipe(dir) {
@@ -626,6 +638,11 @@ class GameEngine {
this._handleChoice(dir);
return;
}
if (s === 'idle') {
SFX_UI.error();
Haptic.error();
}
}
// ── 长按:重播 / 状态广播 ──
@@ -642,13 +659,13 @@ class GameEngine {
if (this.currentMsg.audio?.length > 0) {
this._playVoiceAsync(this.currentMsg.audio);
} else if (this.currentMsg.type === 'wechat_text' && this.currentMsg.text) {
TTS.speak(this.currentMsg.text);
TTS.speak(this.currentMsg.text).then(ok => { if (!ok) SFX_UI.notify(); });
}
return;
}
// idle/notification → 广播未读数
TTS.speak(`当前未读${this.vars.UNREAD}条消息`);
TTS.speak(`当前未读${this.vars.UNREAD}条消息`).then(ok => { if (!ok) SFX_UI.error(); });
}
// ── 暂停 ──
-3
View File
@@ -19,9 +19,6 @@ const Haptic = {
// 拒绝 / 挂断
reject() { this._v([100, 50, 100, 50, 100]); },
// 进入细回复模式
detailMode() { this._v([30, 30, 60]); },
// 选项选中
select() { this._v(80); },
+15 -12
View File
@@ -31,23 +31,26 @@ async function main() {
}
}
// 防止双重启动
let _started = false;
function startGame(el) {
if (_started) return;
_started = true;
el.style.transition = 'opacity 0.8s';
el.style.opacity = '0';
setTimeout(() => { el.style.display = 'none'; }, 800);
main();
}
// 触摸启动(手机)
document.getElementById('start').addEventListener('touchend', async function onStart(e) {
document.getElementById('start').addEventListener('touchend', function(e) {
e.preventDefault();
this.removeEventListener('touchend', onStart);
this.style.transition = 'opacity 0.8s';
this.style.opacity = '0';
setTimeout(() => { this.style.display = 'none'; }, 800);
await main();
startGame(this);
}, { once: true });
// 鼠标点击(电脑调试)
document.getElementById('start').addEventListener('click', async function onClick() {
this.removeEventListener('click', onClick);
this.style.transition = 'opacity 0.8s';
this.style.opacity = '0';
setTimeout(() => { this.style.display = 'none'; }, 800);
await main();
document.getElementById('start').addEventListener('click', function() {
startGame(this);
}, { once: true });
// 防止页面滚动/缩放
+2 -19
View File
@@ -12,28 +12,11 @@ class ProfileTracker {
}
}
// 漏接电话
onMissedCall() { this.add({ avoidance: 2 }); }
// 单点回"嗯"
onSimpleReply() { this.add({ avoidance: 1 }); }
// 双指上滑已读不回
onReadNoReply() { this.add({ avoidance: 2 }); }
// 进入细回复
onDetailReply() { this.add({ engagement: 2 }); }
// 细回复选"主动追问"engagement 方向)
onEngage() { this.add({ engagement: 2 }); }
// 细回复选"分享自己"
onShare() { this.add({ engagement: 1, nostalgia: 1 }); }
// 反复重听同一条
onReplay() { this.add({ nostalgia: 2 }); }
// 听完长语音未回应
onListenNoReact(){ this.add({ avoidance: 1, nostalgia: 1 }); }
// 获取最终画像标签
get label() {
const s = this.scores;
if (s.engagement >= s.avoidance && s.engagement >= s.nostalgia) return 'engagement';
if (s.nostalgia >= s.avoidance) return 'nostalgia';
if (s.engagement > s.avoidance && s.engagement >= s.nostalgia) return 'engagement';
if (s.nostalgia > s.avoidance) return 'nostalgia';
return 'avoidance';
}
}
+4 -2
View File
@@ -22,15 +22,17 @@ const TTS = {
return this._voices.find(v => v.lang.startsWith('zh') || v.name.includes('Chinese'))
|| this._voices[0] || null;
},
get available() { return !!window.speechSynthesis; },
speak(text, { rate = 0.85, volume = 0.8 } = {}) {
return new Promise(resolve => {
if (!window.speechSynthesis) { resolve(); return; }
if (!window.speechSynthesis) { resolve(false); return; }
speechSynthesis.cancel();
const u = new SpeechSynthesisUtterance(text);
u.lang = 'zh-CN'; u.rate = rate; u.volume = volume;
const v = this._pick();
if (v) u.voice = v;
u.onend = resolve; u.onerror = resolve;
u.onend = () => resolve(true);
u.onerror = () => resolve(false);
speechSynthesis.speak(u);
});
},