下载 App

《变成黑洞》开发日志

10/192 浏览综合
日期:2026-10-19 本期构建序号:57 → 101(共 45 次构建) 代码规模:9068 行 / 14 个文件
horizontal linehorizontal line

一、本期进展

这一期的主线是把「引力」从数值表里真正做出来。 上一期把视野固定下来之后,引力第一次变成了「看得见、摸得着」的东西—— 也就第一次暴露出它在物理上一直是错的。

1. 引力的两处根本错误

用户提了两个问题,都指向同一个地方:
①「碎石都不受引力影响,那你其他引力正不正确?」
原来碎石被写成了双向免疫:它既不被别人吸,也不吸别人。 这是一个偷懒的近似——真实宇宙里没有这种东西,碎石同样受引力。 改成:碎石作为引力源强度约等于 0(massMul = 0), 但它依然受其他天体的引力影响。
这两件事必须分开:「不吸引别人」是合理的近似, 「不受别人吸引」是错的。原来的代码把两者绑在了一起。
②「中子星半径那么小,引力怎么会比类地行星弱?」
这是更严重的一处。原来的引力质量是视觉半径的立方:
GravityMass = r³          ← 错
于是:
阶段视觉半径旧引力质量物理事实
类地行星1785.6e6中等
中子星1031.1e6应该极重
黑洞1151.5e6应该极重
中子星和黑洞的引力比一颗普通行星还小——物理上完全反了。 根因是:视觉半径是「对数映射到屏幕」的美术量, 它把 26 个数量级的真实质量压扁了,压扁之后就不能再拿来算引力。
改成用真实质量承载:
真实质量 = realR³ × density          -- 横跨 26 个数量级
   ↓ 对数压缩 → 立方 → 按矮行星归一化
massMul                              -- 各阶段的固定数值
   ↓
GravityMass = massMul × MassScale    -- MassScale 是常量
MassScale 取矮行星视觉半径的立方(3959313), 这样 massMul = 1 的那一阶,引力与原来的调参逐位一致—— G、MassRef、PlayerPull、Softening 全部沿用旧值,不必重新调一遍手感。

2. 玩家真正「被引力推着走」

用户要求:「给玩家加一个受到周围引力影响可以加速减速偏转转弯」。
原来的玩家速度是单一分量,每帧朝输入目标趋近:
lua
p.vx = p.vx + (target - p.vx) * AccelLerp * dt
引力加速度加进去之后,下一帧就被当成「偏差」抹掉了。 稳态下引力最多只能贡献 a / AccelLerp ≈ 32——基础速度 260 的 12%。 玩家完全感觉不到被吸引、被偏转。
改成双分量:
分量含义行为
cvx / cvy操控分量跟手,系数不变
gvx / gvy引力分量独立累积,按 0.5/秒 缓慢衰减
vx / vy合速度= 操控 + 引力
这样掠过一个大天体时,引力攒下的速度会多滑一段, 才有「被甩了一下」的弹弓感。
标定过程:PlayerGravDamp 先按「中等天体在 d=600 处给 1.5 倍速」反推得 0.06, 用户随后要求再减半,最终定为 0.03。
关键的一道保险:引力分量必须有独立上限(GravityVelCapMul = 0.75)。 原因是稳态引力速度 = 加速度 / 衰减率,而黑洞近距离的加速度极大—— 不加这道限制,实测玩家从 900 单位外全力逃离,10 秒后仍被拖到 127 单位并吃掉。 限制到 0.75 后,全力逃离的净速度是基础速度的 25%,一定逃得掉,但有张力。

3. 玩家推不动高阶天体

用户反馈「我能推着高阶天体跑」。
根因有三层,一层比一层深:
层问题
1玩家无敌时直接改 e.x / e.y 并每帧加冲量 → 无敌期就是一台推土机
2改成「只推更轻的」,但用的是 MassOf(= r³)——半径小的黑洞被判成「轻」
3玩家吸 NPC 有两条路径(分片 + 逐帧),只改了一条
最终修法:无敌冲量只对低阶天体生效(eStage < p.stage), 玩家引力同样按阶段过滤。「能不能吃」和「推不推得动」现在用同一套判断。

4. 开局保护与永久无敌,一起删掉

  • SpawnInvincible:20 秒 → 0(用户要求去掉开局无敌)
  • 删掉永久增益 aegis「星尘护盾」:它给的 invincible = 9999 让 BuffValue("invincible") 恒为真,等于永久无敌
保留的只有复活自带的 5 秒——那是「刚复活时喘一口气」,性质不同。

5. 移速翻倍(只翻玩家)

用户要求「玩家移速翻倍」,并明确「NPC 不变」。
没有直接改共享的速度表(那会连 NPC 一起改),而是新增一个玩家专用入口:
lua
Config.PlayerSpeedOf(r, stage) = SpeedOf(r, stage) × PlayerSpeedMul
NPC 继续读 SpeedOf。PlayerSpeedMul = 2.0。

6. 12 阶全部从视野边缘刷新

用户要求「十二阶角色都改成从地图边缘刷出」。
原来的刷新是外围环带,改成按可见矩形边框随机取点: 沿矩形四边按长度随机,太近的沿径向推到安全距离之外。
诚实说明:用户说的是「地图边缘」,我实现的是可见视野的边框, 不是世界半径 20000 的真实边界。因为回收逻辑会在 2.8 × 视野 处回收天体, 真正刷在世界边界的天体下一帧就会被回收。这一点在交付时已说明。

7. 音效:第二版,碰撞与爆炸

用户指出方向错了:「宇宙里面的声音应该是碰撞声和爆炸声」。
重做了四个音,全部统一响度后接入:
事件素材时长听感
eat_small小陨石碰撞碎裂0.552s清脆
eat_big巨岩撞击崩落1.056s沉闷厚重
evolve超新星爆发1.848s爆发上扬
death毁灭性爆炸1.560s低沉终结
响度归一化是必须的:生成器原始输出相差可达 17dB (eat_small -30.9 vs eat_big -11.0), 不归一化会出现「吃小东西听不见、死亡却很响」。统一到 -13 ~ -18 dB。 旧素材备份在 assets/Sounds/_old/(已加入构建忽略)。

8. 一个真崩溃:Web 音频整数除零

真机(WebAssembly)报错:
Uncaught RuntimeError: divide by zero
  at SDL2.audio.scriptProcessorNode.onaudioprocess
上一期为了抗 BGM 卡顿,加了 audio:SetMode(250, 48000, true)。 回退这处调用后崩溃消失。
诚实说明:wasm 的 divide by zero 是整数除法 trap, 最可能来自混音里的 playback step = source frequency / mix rate, 但我没有引擎源码或符号来确认内部准确路径。 已确认的只有一件事:回退这一处调用后不再崩。 脚本层不要再碰 SetMode——混音参数交给引擎。

9. 屏幕内大质量碰撞的微震屏

用户要求「屏幕内触发大质量的碰撞时可以给屏幕加一点微小的震屏」。
三个条件同时满足才触发:
① 碰撞点落在屏幕内(含 15% 边缘余量)
② 质量 ≥ 门槛(r ≈ 60,小行星级以上)
③ 振幅按「质量 / 参考质量」封顶,再按离屏幕中心距离衰减
参数刻意保守:最大振幅 3.2 逻辑像素、时长 0.26 秒。 玩家日常吞的碎屑(r ≈ 5~15)远低于门槛——否则吃一口抖一下,屏幕会一直在晃。
偏移只写进渲染用的局部相机变量,不写真实的 camera.x/y, 所以 HUD 不跟着抖。

10. 黑洞的星光弧恢复 + 开普勒差动旋转

用户指出:参考图里黑洞周围那些被弯折的星光弧不见了。
排查发现当前代码里确实只有完整光子环,没有那圈短弧。 从历史备份里找到旧的 46 段实现,恢复回来,并按要求大幅提速:
项目改前改后
星光弧0.22 rad/s(29 秒一圈)3.9 rad/s(内圈约 1.6 秒)
吸积盘内环0.35 rad/s(18 秒一圈)1.6 rad/s(约 3.9 秒)
同时给两者加上开普勒差动——内圈比外圈快,比例遵循 ω ∝ r^(-3/2):
  • 星光弧:每段弧按自己的半径算角速度,外圈(rk=1.70)只有内圈的 0.46 倍
  • 吸积盘:三层不再共用一个相位,各按 r^(-3/2) 缩放,内环比外环快约 1.57 倍
改前三层同相,整盘像一块刚体转盘在转,不符合吸积流; 现在有了速度差,才会出现真实的剪切流动。
诚实说明:这是视觉表现,不是相对论模拟。 引力透镜的星像并不等同于物质沿开普勒轨道绕行。 差动是「参考吸积物质运动」做的艺术化处理。

11. BGM 隔离:查清了,但结论是不能靠脚本做

用户问「能不能把 BGM 单独拎出来循环播放,让任何操作都不影响」。
先查现状,结论是:
  • BGM 已经使用专用音乐声部,与 6 个音效声部完全分开
  • 音效不会抢占 BGM 的声部
  • 死亡、进化、复活、重开、教程开关都不会停止或重播 BGM
  • 只在 Start() 启动一次,已设循环
也就是说:「操作影响 BGM」这件事,在脚本层已经不存在了。
用户真正要的是「画面卡一下、音乐也别断」—— 那需要 BGM 走独立音频后端(游戏不每帧喂数据,音频系统自己循环)。 在 UrhoX 公开的 Lua 接口里没有查到这种接口: SoundSource 全部经由同一套混音链路,soundType = "Music" 只是分类标签, 不是独立后端。
所以本期没有为「隔离」做任何无效修改,也不再碰 SetMode。 真机卡顿的正解仍是降低渲染开销。
horizontal linehorizontal line

二、问题与风险

已解决的问题

① 引力质量的量纲错误——用「视觉半径」当物理质量, 导致中子星、黑洞的引力比行星还弱。这是本期最严重的一处。
② 玩家引力被输入抹平——单分量速度模型下,引力永远攒不起来。
③ 推高阶天体——三处叠加:无敌推土机 + 用 r³ 判轻重 + 两条引力路径只改了一条。
④ 永久无敌——一个 9999 秒的增益被当成了永久加成。

现存风险

🔴 LOD 实际上没有生效(本期发现,未修)
上一期为了抗卡顿,写了「只让最值得看的 2 个黑洞画完整吸积盘」的 LOD。 本期核对代码时发现一个语义漏洞:
lua
fullLodSet[cands[i]] = true -- 选中的标 true ... DrawEntityBody(..., fullLodSet[e]) -- 未选中的是 nil
而绘制侧只在 fullLod == false 时降级——nil 不等于 false, 所以未选中的黑洞仍然全部画完整吸积盘。 LOD 写了,但没起作用。这是下一步要修的第一件事。
这也说明之前那些「LOD 已降低开销」的说法证据不足: 合成压测时是显式传 false 才看出差别的,真实场景里并没有降级。
Web 音频崩溃的根因未确认:只有「回退后不再崩」这一条证据。
BGM 真机卡顿仍未实测:本地软渲染测不出,手机 GPU 画径向渐变比桌面贵得多。
真机性能整体未实测:所有耗时数据都来自桌面软渲染。
Game.lua 已涨到 1688 行,超过 1500 的拆分阈值,构建会告警。
玩家引力被重复施加:GameEcology 里有分片和逐帧两条路径, 两处都在给玩家施加外部引力,尚未合并。
速度分量与边界回推不一致:出界时 vx / cvx / gvx 各减一份, 但合速度与分量的恒等关系没有严格维持,属于遗留隐患。
震屏的生命周期未覆盖全:StartRun / Revive 没有重置震屏字段, 死亡分支不更新震屏,可能残留。
关卡引导缺失:引力现在是核心机制,但完全没有视觉表现, 玩家看不到引力场,只能靠感觉。
未实施的建议(仍未动):
  • 引力可视化 / 引力井 / 逃逸锁定
  • 难度加压、洛希撕裂开启
  • 排行榜、成就、主动技能
  • 切后台暂停、音量开关
双星配置仍未接通:Config.Gameplay.Binary 定义了参数,零引用。
horizontal linehorizontal line

三、下期计划

  1. 修 LOD 的 nil 语义漏洞 —— 这是唯一能让「降开销」真正落地的一步
  2. 真机性能实测 —— 唯一能证伪「卡顿已修」的事
  3. 合并玩家引力的两条施加路径
  4. 引力可视化 —— 核心玩法现在完全看不见
  5. 拆分 Game.lua(1688 行,超阈值)
horizontal linehorizontal line

四、一点感想

这一期最值得记的,是**「美术量被当成物理量」这件事**。
视觉半径是为了让 12 个阶段都能装进一块手机屏幕而设计的, 它把 26 个数量级的真实质量对数压扁成了 12 → 310。 这是正确的美术决策。
但它被拿去算引力了。于是:
  • 中子星半径小 → 引力弱(物理上反了)
  • 碎石半径最小 → 干脆「不受引力」
压扁过的量不能再当原始量用。 这和上一期那个「按半径反推阶段」是同一类错误: 半径在这个项目里是美术量,不是物理量。 上一期踩的是「反推阶段」,这一期踩的是「算引力」, 根因一模一样,只是表现不同。
第二件值得记的,是**「写了不等于生效」。 LOD 那一段代码逻辑看着是对的、注释写得很详细、 甚至还有实测数据(1 盘 6.5ms、3 盘 21.6ms)—— 但它是在显式传参的压测里测出来的。 真实调用路径传进去的是 nil,于是一行都没执行到**。
这件事提醒我:验证要打在真实调用路径上, 否则测的是「我以为的代码」,不是「跑起来的代码」。
horizontal linehorizontal line
文档最后更新:2026-10-19
已通关,放心玩截图
已通关,放心玩
官方
1 赞
《变成黑洞》开发日志
为玩家推翻重来设计新玩法,导致游戏全是bug, ai都不听话的那种。以后我慢慢修吧。当前版本可能是最后的版本了。已经将tap tap创造已经开发到极致了。 一、本期主线:一次撞击被当成了无数次 这一期所有问题都指向同一件事: Impact 被反复调用。 Contact 每帧处理一次接触,但接触记录会被距离判定清掉重建。撞击后两块球贴合在一起(位置重叠、速度相同),PruneContacts 每隔几
官方
2 赞
《变成黑洞》经费已至,敬请期待
日期:2026-10-17 ~ 2026-10-18 本期构建序号:19 → 56(共 38 次构建) 代码规模:8469 行 / 14 个文件 一、本期进展 这一期的主线只有一件事:把「视野」这件事从头重做一遍。 围绕它牵出了一连串问题——阶段错乱、渲染预算、特效不跟随、性能卡顿。 下面按「主线 → 连带修复 → 工程债」的顺序说。 1. 视野重构:从「按玩家体型」到「固定广阔」 起点:用户反馈
官方
1 赞
《变成黑洞》开发日志第 4 期 · 3D 自转、进化链扩展与撞击反馈截图
《变成黑洞》开发日志第 4 期 · 3D 自转、进化链扩展与撞击反馈
日期:2026-09-27 ~ 2026-09-29 构建次数:7 次(09-27)+ 11 次(09-29) 本期进展 1. 真 3D 自转(09-27) 有玩家反馈「天体看起来像圆盘在转,不像球体」。 问题在于原来只是平面贴图旋转:贴图在圆内转圈,看起来就是一张纸在转。 重写后的做法是把表面特征(陨石坑、大陆、云团)建在单位球上: 出生时在单位球面撒 N 个特征点 每帧按自转角绕自转轴旋转 再
官方
2 赞
4 回复
《变成黑洞》开发日志第 5 期 · 补全真实天体演化链与黑洞重做截图
《变成黑洞》开发日志第 5 期 · 补全真实天体演化链与黑洞重做
日期:2026-10-02 当日构建次数:5 次 本期进展 这一期主要做了一件事:把「碎石 → 黑洞」这条链上的物理缺失补上。 之前有玩家在评论区问「黑洞是怎么来的」,我回头查了一遍天体物理资料,发现游戏的进化链在科学上站不住脚。于是做了一次系统性修正。 1. 补上中子星,进化链扩展到 14 阶 问题:真实演化里,红巨星之后应该是白矮星 / 中子星 / 黑洞三选一,取决于坍缩后的核心质量。之前红巨
官方
1 赞
《变成黑洞》开发日志第 2 期 · 玩法闭环与首次发布截图
《变成黑洞》开发日志第 2 期 · 玩法闭环与首次发布
日期:2026-09-19 当日构建次数:29 次 本期进展 这一期的目标很明确:让游戏能发布。 1. 补全玩法闭环 之前只有「吃」,没有「死」。这一期加上: 死亡判定:被更大的天体吞噬即死亡 死亡界面:显示本局得分、吞噬数、复活次数 结算:最高分记录 2. 首次发布上线 完成了发布所需的全套素材: 游戏图标(黑洞吸积盘特写,1024×1024) 宣传图(主标题 + 黑洞吞噬场景) 3 张商店截图
官方
2 赞
2 回复
《变成黑洞》开发日志第 3 期 · 物理真实化起步
日期:2026-09-21 ~ 2026-09-26 构建次数:3 次(09-21)+ 3 次(09-26) 本期进展 激励视频广告(09-21) 接入了「看广告复活」:玩家死亡后可看广告原地复活。 广告代码的关键设计是以回调的 result.success 作为唯一发奖依据,同步拒绝、异步回调、超时看门狗共享同一个「一次性完成」状态,避免重复发奖。 纯引力模式(09-26) 这是本期最大的改动,
官方
2 赞
《变成黑洞》开发日志第 1 期截图
《变成黑洞》开发日志第 1 期
项目:变成黑洞 引擎:UrhoX 类型:宇宙题材吞噬进化(街机) 第 1 期 · 项目起步与核心玩法 日期:2026-09-18 当日构建次数:19 次 本期进展 完成了项目从零到「能玩」的全过程,核心是一个宇宙版的「大鱼吃小鱼」:玩家从一块碎石开始,靠吞噬比自己小的天体不断成长。 定下 9 阶进化链 一开始的进化链设计得比较粗,只有 9 阶: 星尘 → 碎石 → 陨石 → 小行星 → 矮行星#聚光灯GameJam开发者日志
官方
2 赞
《变成黑洞》开发日志
日期:2026-10-20 代码规模:12424 行 / 16 个文件 一、本期主线:从「700 体大混沌」到「渐进解锁的稀疏宇宙」 上一期结束时,场上铺着 700 个天体——引力对、碰撞对、守恒也对, 但玩起来画面挤成一团,性能也吃紧。这一期把整个世界结构重排了一遍: 玩家看到什么、什么时候看到、天体从哪里来,全部重写。 1. 渐进解锁:场上只出现「玩家阶段 +1」以内的天体 开局铺满十阶各两个
官方
2 赞
《变成黑洞》开发日志
日期:2026-10-21 代码规模:13086 行 / 19 个文件 一、本期主线:把「同一个概念的多套实现」逐个收敛 这一期没有新增大玩法,全部工作量都花在消除重复上。 每修一个 bug,根源几乎都是同一句: 同一个概念在多处各写了一遍,谁最后执行谁生效。 概念 曾经有几套 现在 碎石半径 4 套(Collision.Sync / CosmicPhysics 碎片 / CosmicPhysic
官方
2 回复