djtoon/sunburst_isle
GitHub: djtoon/sunburst_isle
一款基于 three.js 的全程序化生成 3D 平台跳跃游戏,专注于实现任天堂级别的角色操控手感与动作系统。
Stars: 1 | Forks: 1
# 阳光岛屿
这是一款基于 three.js 的 3D 平台跳跃游戏,旨在追求任天堂第一方平台游戏的手感——例如《超级马力欧:奥德赛》、《超级马力欧银河》和《超级马力欧兄弟:惊奇》。一切都是程序化生成的:没有模型文件,没有纹理下载,也没有音频采样。整个游戏在启动时即可自动生成。
催生本项目的原始需求位于 [PROMPT.md](PROMPT.md) 中。
```
npm install
npm run dev # http://127.0.0.1:5188/
```
在期待听到声音之前,请先点击一次页面——浏览器会阻止音频播放,直到你与之交互。
## 操作
| 输入 | 动作 |
|---|---|
| **WASD** / 左摇杆 | 移动。支持模拟量——轻推摇杆即是慢走 |
| **空格键** / A键 | 跳跃。在移动状态下落地时快速再次按下即可实现连锁:跳跃 → 二段跳 → 三段跳 |
| **Shift** / X键 | 俯冲(滞空时) · 翻滚(地面时) |
| **Ctrl** / RB键 | 臀击 |
| **Q** / **E** / 右摇杆 | 旋转视角 |
| **S** + **空格键** | 后空翻 |
| 奔跑 + **S** + **空格键** | 远跳 |
| 翻滚中按 **空格键** | 远跳 |
| **R** · **F1** · **Esc** | 重生 · 调试统计 · 暂停 |
在滞空状态下 *冲向* 墙壁即可实现滑墙;再次跳跃可借力蹬墙跳。
## 路线
关卡每次只传授一个机制,随后再将它们组合起来。金币轨迹始终标示着既定路线——金币是构成关卡语法的核心。
1. **海滩平原** —— 奔跑、地面手感、收集第一批金币
2. **踏脚石** —— 练习带有柔和落水惩罚的跳跃间距
3. **移动平台** —— 练习时机把握,以及适应脚下移动的表面
4. **斜坡 + 冰坡** —— 练习动量与不同表面的差异(弹跳蘑菇是失败后的恢复路线)
5. **蹬墙跳烟囱** —— 唯一的高难度垂直技巧,在独立环境中教学
6. **旋转挑战** —— 时机 + 敌人 + 真实的坠落风险
7. **顶峰** —— 从出生点即可看见,上方有一颗星星
## 实际包含的内容
### 游戏手感
这是决定一款平台游戏成败的关键,因此经过了最刻意的设计。
重力与起跳初速度是 **根据期望的最高点高度和达到最高点的时间推导得出的**,而不是凭空捏造的冲量,因此改变“跳多高”绝不会悄无声息地改变“滞空感”:
```
const JUMP1 = arc(2.55, 0.335); // 2.55m apex, reached in 0.335s
```
除此之外:
- **土狼时间** (~0.105秒,当你高速冲出边缘时会延长——因为玩家此时最确信自己本该能跳过去)
- **跳跃缓冲** (~0.133秒) —— 落地前提前按下,会在落地的瞬间触发跳跃
- **非对称重力** —— 下落速度比上升速度更快
- **可变跳跃高度** —— 提前松开按键会缩短跳跃弧度,且重新按键无法恢复
- **最高点滞空** —— 在跳跃最高点降低重力 *并* 增强空中控制力,这正是玩家瞄准的时机点
- **独立的加速 / 刹车 / 转向速率** —— 急速反向时的咬合力比普通转向要硬朗得多,这种干脆感正是该类型的标志性特征
- **转向速率随速度增加而降低** —— 全速冲刺时身体只能划出弧线而非瞬间转身,这正是产生“重量感”的主要来源
- **顿帧** 会根据冲击力缩放 —— 大约两三帧的时间,作为一种暂停感几乎察觉不到,但作为一种重量感却绝对错不了
模拟以 **固定 120 Hz** 运行并进行渲染插值,因为在土狼时间上哪怕只有一帧的差异都是能被感知的,而且只有当时间步长恒定时这种差异才有实际意义。
动作集包括:三段跳、远跳、后空翻、俯冲、翻滚、臀击、蹬墙跳和滑墙,以及它们之间的连锁动作(俯冲 → 翻滚 → 远跳),这让整套动作系统感觉像是一门语言。
### 动画
完全程序化生成——姿势根据物理状态进行计算,绝不从动画剪辑中采样。在这种剪影复杂度下,这是一种优势而非妥协:每一个姿势都由真实的速度、坡度、滞空时间和转向速率 *持续* 驱动,因此绝不会出现那种让角色与自身控制器脱节的动画剪辑混合泥泞感。
分层设计:每个状态的基础姿势 → 由加速度和转向产生的附加倾斜 → 挤压与拉伸 → 次级运动(围巾、尾巴、耳朵作为 verlet 链运行) → 面部(眨眼、扫视、眉毛情绪表达、视线追踪)。
挤压与拉伸使用 **弹簧而非固定曲线** —— 冲击力必须产生过冲并最终沉淀,否则看起来会像橡胶一样虚假。体积保持不变:Y 轴增加的量会从 XZ 平面中扣除。
### 视角
这是一个游戏玩法系统,而非单纯的视觉表现细节。糟糕的视角会让一个完美的控制器显得无比糟糕。
- 在枢轴上设置 **柔和死区**,因此微小的移动完全不会晃动视角——这能消除那种令人作呕的低频抖动,正是这种抖动让手持式风格的视角令人感到晕眩
- **非对称垂直跟随**:向上时显得慵懒(你可以看到离开的地面),向下时则非常迅速(你需要看清脚下的路),并且枢轴会锁定在起跳高度,从而避免普通跳跃导致地平线上下泵动
- **速度前瞻** —— 奔跑时让视角揭示前方的路况,而不是停留在身后
- 支臂碰撞会 **快速拉回,缓慢推出**;在墙壁被清空的瞬间立刻向外弹回,是业余视角设计中最常见的暴露点
### 渲染
三点光照设置——温暖的主太阳光、强烈的冷色调天空补光、地面反射光——因为平淡的环境光是业余渲染器最大的败笔。**阴影呈现蓝色,而不是死黑。** 阴影视锥体会跟随玩家移动,并按纹素步长进行量化,从而避免贴图在滑动时产生闪烁。
所有纹理均在运行时于 canvas 上生成,具有双重尺度的变化(大面积的风化斑块加上精细的颗粒)以及一张用于打破明显平铺感的宏观贴图。
### 音频
每个声音都在运行时通过 WebAudio 进行合成。没有采样。
最重要的好处是:金币的琶音、跳跃的短促音和音乐全部 **锁定在同一个五声音阶上**,因此无论发生什么,游戏都绝不会产生刺耳的不协和音程。连续收集金币会使音阶爬升;连续跳跃每次都会升高一个音级,因此你的耳朵能听到进展。
音乐是生成式且自适应的——编曲密度会根据玩家的动量和高度发生变化。
## 项目结构
```
src/
core/ Time.js fixed timestep + interpolation, damping helpers
Input.js buffering, edge latching, gamepad, radial deadzone
player/ PlayerController.js the game-feel core
PlayerModel.js procedural rig ("Pip", an original mascot)
PlayerAnimator.js procedural animation state machine
camera/ CameraRig.js
world/ Collision.js capsule vs convex primitives + triangle meshes
Level.js builders that emit mesh and collider together
CourseOne.js the course layout
Materials.js procedural textures
Lighting.js sky shader, three-light rig, shadow management
fx/ Particles.js instanced pools; every emitter answers a player question
enemies/ Enemies.js telegraph-first AI
gameplay/ Collectibles.js
ui/ HUD.js
tools/
shoot.mjs fast smoke/regression capture
critique.mjs dense capture for quality review
diag.mjs axis-mapping tests + frame-budget profiler
probe.mjs runtime state dump
```
关卡构建器总是会同时生成可视网格及其碰撞体,从而确保几何体与物理表现不会产生脱节。
## 开发工具
游戏暴露了 `window.__game` 钩子,以便进行无头模式驱动。这使得自动化审查成为可能——审查者基于游戏实际渲染的画面进行工作,而不是去阅读源代码。
```
node tools/diag.mjs # axis tests + frame budget + A/B toggles
node tools/shoot.mjs --out=shots/x --clean # scripted scenario stills
node tools/critique.mjs --out=shots/r1 # dense review capture at 1920x1080
```
`diag.mjs` 是其中最实用的工具:它首先验证摇杆到世界坐标轴的映射是否正确(反向轴在截图中是不可见的,只有当真人游玩时才会暴露出来),然后包装热点方法以报告帧时间到底消耗在了哪里,最后对阴影、水面、草地和分辨率进行 A/B 切换测试。
## 已知缺陷
在此坦诚说明,而非掩盖:
- **帧率低于 60**:在开发机器上以 1600×900 分辨率运行时。性能分析与优化正在进行中;目前场景中携带的独特材质数量远超实际所需,这是主要的性能开销。
- **只有一个关卡。** 教学结构已经存在,但整体游戏流程偏短。
- **没有 Boss、没有道具强化、没有收集要素的元游戏层。**
- 这 **并不** 是在超级马力欧:奥德赛那个级别,不应做出任何不切实际的夸大宣称。本项目的目标仅仅是将 *手感* 的基础环节做到真正到位,并在 WebGL 的合理能力范围内尽可能提升表现力。
## 致谢
角色、世界、音效和音乐均为原创且通过程序化生成。未使用或复刻任何任天堂资产。本项目基于 [three.js](https://threejs.org/) 构建。
标签:3D平台游戏, MITM代理, Three.js, Web游戏, 数据可视化, 游戏开发, 程序化生成, 自定义脚本