一刀砍下去,怪物胸口蹦出一个「1389」。
紧接着第二刀、第三刀,数字一个接一个往上跑,越堆越高,最后连成一道向上流的瀑布。
很少有人会停下来想一件事:为什么是往上?为什么不是往下、不是往左往右,也不是老老实实停在被打中的那个部位?
答案有点反直觉:往上飘不是为了好看,是为了给下一个数字让位置。
这是一条乍看很不起眼的 UI 冷知识,但它把「打击感」里最容易被忽略的一层——伤害数字的排版——解释得很干净。下面按「为什么排队、为什么往上、怎么飘」三步拆开,最后给一段可以直接贴给 AI 的实现需求。

一、数字不是「弹」出来的,是「排队」出来的
注意一个细节:每一刀的数字,都从同一个点冒出来。
这个点通常锚在受击部位——怪物胸口、被击中的关节、爆点中心。位置固定,是为了让玩家一眼看出「这一下打在他身上」,而不是飘在空气里。
但位置固定就意味着:第二刀的数字,天生就站在第一刀的位置上。
如果数字不飘——注意,是不飘,不是飘得慢——那么第二刀会直接盖住第一刀。连击到十几下,屏幕上只剩一团橙红色的大色块:描边互相打穿,数字彼此叠印,你根本读不出「这一刀打了多少」。
「数字都从同一个点冒出来,不让开就叠成一团。」
所以「往上飘」的第一层职责不是演出,是排版:给下一位腾一个身位,像排队一样,后来的站在后面。


把三种做法摆在一起看,差别一眼就出来了:
| 数字的行为 | 屏幕上发生什么 | 玩家能读到什么 |
|---|---|---|
| 原地不动 | 第二刀压住第一刀,第三刀压住第二刀 | 只能看清最上面那个数,连击数无从判断 |
| 原地抖动 | 每个数字都在闪,但位置几乎重叠 | 一片糊,节奏感全丢 |
| 向上错位 | 每刀一个高度,像排队往上走 | 能数出打了几下、每下多少 |
第三种做法还有一个副作用:它天然形成了节奏。数字一层层往上走,视觉上就是连击的鼓点,比任何音效都直观。
二、为什么偏偏往上:先给屏幕画一张「空地地图」
把手机横过来,屏幕的四个方向其实早就被占满了。

- 下:左半边是虚拟摇杆,右半边是技能键,玩家的拇指长期覆盖,是屏幕最「脏」的区域。
- 左:角色本体、头像、血条都在这一侧,数字往左会和主体打架。
- 右:连击数、技能图标、暂停键贴着边,往右会跟 HUD 抢位置。
- 上:天空、远景、墙面,什么都没有——这是整块屏幕上唯一一块真正的空地。

「脚下有地面、有技能键。」
「头顶最空。」
所以「上」不是一个审美选择,是这道题在横屏动作游戏里的唯一解:把信息放到玩家不看也不会漏、不挡操作也不被遮挡的地方。
顺手记一下这条思路的适用范围:空地地图是跟着游戏类型变的。竖屏卡牌的空地可能在中间偏上,俯视射击的空地在上方偏左,弹幕游戏甚至会刻意让数字贴边——因为它们要抢的是「不挡弹幕」而不是「不挡手指」。先画出你的空地,再决定数字往哪飘,顺序不能反。
三、飘也有讲究:弹 0.1 秒、飘 0.75 秒、淡 0.25 秒
方向定完,才轮到手感。往上飘看着简单,其实是三段时长叠出来的:



| 阶段 | 时长 | 这一段在做什么 |
|---|---|---|
| 弹(Pop) | 0.1 秒 | 从 1 倍瞬间放大到约 1.15~1.3 倍再回弹,抢到眼睛,让人立刻注意到「出新数字了」 |
| 飘(Float) | 0.75 秒 | 匀速或轻微减速上移 1~2 个字高,让位给下一个数字,同时留出读数时间 |
| 淡(Fade) | 0.25 秒 | 透明度从 1 线性归零,收尾,不留残影,不占屏 |
「先弹一下。」
「再慢慢停。」
「看清就淡掉。」
这三个数字值得抄下来,是因为它们刚好卡在几个临界点上:
- 0.1 秒:60fps 下正好 6 帧。短于 0.1 秒,玩家会觉得「数字闪了一下就没了」;长于 0.15 秒,连击时新数字会等老数字,节奏开始拖。
- 0.75 秒:飘的时长是「弹」的 7.5 倍。这个比例决定了观感是「弹出去」还是「飘上去」——比例小于 3 倍,看起来像被弹弓打出去的;大于 15 倍,又像气球慢慢升空。
- 0.25 秒:淡出必须短于飘的 1/2。飘还在走就开始淡,玩家会觉得数字「没看清就没了」;飘停住再淡,屏幕上会有一瞬间的静止感。
还有一条隐含规则:三段不是串行播放,是叠在一起的。弹的 0.1 秒结束时,飘已经开始了;飘的最后 0.25 秒,淡就已经在走。整体生命周期大约 1 秒,比三段相加(1.1 秒)略短——因为这个重叠。


四、可直接复制的实现方案
如果你正在用 AI 做游戏,下面这段可以直接贴进对话里。它把上面的结论翻译成了参数和验收标准,不留「好看一点」「自然一点」这种没法定量的词。
【需求】实现游戏中的伤害数字(Damage Number)系统,横屏动作游戏。
1. 出字点:锚定受击部位的骨骼节点,同一帧内所有伤害共用一个出字点,坐标取受击点向上偏移 20px。
2. 排队:每个数字在出现后立即开始上移,与上一个数字保持至少 1 个字高的间距;同屏最多显示 8 个,超出时最早的数字加速淡出。
3. 方向:只向上。禁止向左、向右、向下飘,避免与摇杆区(屏高 55% 以下)、技能键区(右下角 180×180)、血条区(顶部 80px)重叠。
4. 动画三段:弹 0.1 秒(scale 1.0 → 1.25 → 1.0,ease-out);飘 0.75 秒(每秒上移 60px,线性或 ease-out);淡 0.25 秒(alpha 1 → 0,线性)。三段重叠播放,总生命周期 1.0 秒。
5. 暴击:字号 ×1.3,颜色用暖橙(#FF9A2E)+ 描边 #5A2A00,额外加一次 0.084 秒的横向抖动(±3px,衰减)。
6. 数字格式:小于 10000 直接显示;≥10000 显示为 1.2万;≥1亿 显示为 1.2亿,最多 1 位小数。
7. 性能:对象池预生成 16 个,循环复用;数字用位图字体图集,禁止每次实例化 Text 组件。
【验收】
· 连打 20 刀,20 个数字全程互不重叠,任意时刻能读出最上面 3 个数字的数值;
· 单帧 GC 分配为 0(对象池命中率 100%);
· 数字出现到消失总时长 1.0 秒 ±0.05 秒;
· 缩放到 320px 宽的最小屏,数字仍不进入摇杆与技能键区域。
这段需求里,真正决定成败的是第 2 条和第 4 条。前者管「排队」,后者管「手感」,其余都是锦上添花。
五、组合顺序与六个坑
照着做的时候,建议按这个顺序来——顺序错了,后面全是返工:
- 先定出字点:锚在受击骨骼上,保证「打哪出哪」。
- 再做排队:只做位移,不做任何缩放和颜色,先把「不重叠」跑通。
- 然后加弹:0.1 秒的缩放,让新数字被看见。
- 最后加淡:0.25 秒收尾,顺便解决同屏堆积。
几个踩过的坑:
- 坑 1:把出字点锚在屏幕坐标。相机一动,数字就和怪物脱钩。必须锚世界坐标或骨骼节点。
- 坑 2:随机偏移给太大。横向 ±30px 看起来「活泼」,实际上会破坏队列感,读数变慢。横向偏移控制在 ±8px 以内,且只做视觉抖动,不影响排队高度。
- 坑 3:每刀都出新数字。高攻速角色一秒十刀,屏幕会变成弹幕。正确做法是合并:0.1 秒内的同源伤害合并成一个数字,或只显示累计值。
- 坑 4:连击时字号不衰减。第 20 个数字和第 1 个一样大,屏幕会越来越吵。让后续数字字号按 0.98 递减,最小不小于 0.75 倍。
- 坑 5:淡出用透明度但没关渲染。alpha 到 0 的对象仍在渲染队列里,几十个数字就是实打实的开销。淡完立刻回收进池。
- 坑 6:飘的速度和距离不成比例。只调时长不调距离,低帧率设备上会看到数字「跳格」。位移请用像素/秒,不要用「总距离 ÷ 时长」硬算到帧。
六、自测清单
做完了别急着上线,按这张表过一遍,五项里过四项才算及格:
| 检查项 | 及格线 | 不达标的表现 |
|---|---|---|
| 连击不重叠 | 连打 20 刀,任意时刻能读出最上面 3 个数字 | 数字糊成一团色块,只能看见最后一个 |
| 方向不挡操作 | 数字全程不进入摇杆区、技能键区 | 拇指按技能时被数字盖住,操作变形 |
| 生命周期 | 出现到消失 1.0 秒 ±0.05 秒 | 数字赖在屏幕上不消失,或一闪就没 |
| 读数窗口 | 飘的 0.75 秒内,四位数字清晰可辨 | 字太小、飘太快,要盯着看才读得出 |
| 性能 | 同屏 8 个数字时,单帧 GC 分配为 0 | 连击时掉帧,或数字出现有延迟 |
七、写在最后
「伤害数字往上飘」这件事,拆开看只有三个决定:从哪出、往哪走、走多久。
从哪出,决定了数字和目标的绑定关系;往哪走,决定了它和 UI 的相处方式;走多久,决定了玩家能不能在混战里读到它。三个都想清楚了,数字才不是特效,而是信息。
下次打游戏的时候,不妨留意一下:那些让你打得爽的作品,数字几乎都在做同一件事——安静地排队,把位置让给下一个。
八、扫码玩一把
道理讲完了,手感这东西还是得自己按一按。下面这个小游戏,把「数字怎么出、怎么走、怎么消失」都调过一遍,扫码就能玩,不用下载、不用注册。

也可以直接长按下面这张原尺寸二维码(上面是卡片,这张是原码,手机上更好识别):

二维码原图 · 长按识别或微信扫一扫
「玩两把,再回头看这篇文章,你会更清楚「让位置」到底解决了什么问题。」
说明:本文的动画参数(弹 0.1 秒、飘 0.75 秒、淡 0.25 秒、出字点固定、单向上飘)来自公开的游戏 UI 设计分享;第 4 节的提示词与第 5 节的数值细节属于实现建议,落地时请按自己的屏幕尺寸与帧率重新标定。素材来源:游戏 UI 冷知识(魔脑 × GAMEUI)。
发表评论 取消回复