下载 App
给一群三角形配上音乐和片头
2026-10-20
游戏从「能玩」到「像个作品」,中间隔着声音和画面。
BGM:交叉淡入淡出
需求是按阶段换曲:标题页和引导页用一首,发育期按友群共鸣等级分前后期,四种群核降临各一首。
实现用两个 Audio 元素轮换:新的从 0 渐强,旧的渐弱到 0 之后 pause(),交叉时长 1.8 秒。
几个细节坑:
- 不能硬改 volume 再 play(),会听到「咔」的一声
- 重复 setTrack 同一首歌必须直接 return,否则每帧 update 都会重启播放
- 单曲放完但还没到切换时刻 → loop = true
还有一个隐蔽的 bug:未解锁时(玩家还没点击过页面)我只记下想播的曲子,但同时把 this.cur 也设成了那首。结果解锁后 setTrack 因为 key === this.cur 直接 return,永远补不上。修法是未解锁分支里只记 wantKey,不碰 cur。
自动播放策略:三端三种脾气
浏览器默认拦截带声音的自动播放,片头 CG 带音轨,直接被拦。
做了三层降级:
- 先试带声音的 play()
- 被拦 → muted = true 重播,顶部提示「点击画面开启声音」,点视频即可开声
- 打包后直接放开:Electron 加 autoplay-policy=no-user-gesture-required,Android 侧 WebView 本来就有 setMediaPlaybackRequiresUserGesture(false)
网页版双击仍然静音,这是浏览器的强制策略,绕不过去。
片头:为什么走 DOM 而不是 canvas
片头是全屏视频。放进 canvas 需要逐帧 drawImage,还要自己处理分辨率、缩放、UI 层级,收益为零。
所以用了 DOM 层:position: fixed 全屏 div + <video>,z-index: 9999。canvas 在下面照常渲染标题页,视频层一淡出,标题页自然就在那儿了。不需要「切场景」这种操作。
关键细节:片头期间必须屏蔽游戏键盘输入。否则玩家按空格跳过片头的同时,也触发了标题页的「按空格进入引导」。game.js 的 keydown 开头加了 if (EW.intro && EW.intro.active) return;。
文件缺失要能活
片头 27 MB、音乐 35 MB。任何一个加载失败都不能把玩家卡在黑屏里。
- intro.js 监听 error,直接渐隐进标题页
- audio.js 记录 failed[key],不再重试
- 视频有 ended 和 error 两条路径,最终都通向同一个 _beginFade()
这个容错设计后来救了场。预览面板只托管一个 HTML 文件,所有外链媒体都拿不到,但因为降级到位,玩家看到的只是「没声音」,不是「白屏打不开」。
一个数字
APK 63 MB。游戏本体 0.11 MB,剩下 63 MB 全是片头和音乐。
如果要瘦身,压成 720p 大约能省 18 MB。但这是取






