Juice:加特效之前先想清楚
「Juice it or lose it」—— 这个说法流行了十几年,害处大概和好处一样多。它是对的:一点点动效能让一个死板的原型活过来。但它被理解成了「特效越多越好」,于是无数个人项目走上同一条路:在核心玩法还没立住的时候,花两周做特效,做完发现还是不好玩,但现在它是一个花哨的不好玩。
先看那条曲线
下面这个 demo 会自动持续攻击。把滑块从 0 一路推到 200%,同时注意两件事:
- 右上角那个统计条里的「可读性」数字
- 那个蓝色的小方块(画面上有提示)—— 试着一直用眼睛跟住它
0% 的时候:干巴巴,但你能清楚看到一切。
50–80% 的时候:有力、清晰、爽 —— 这是甜点。
150% 以上的时候:你已经跟丢那个蓝方块了。
Juice 是一条倒 U 曲线,不是一条上升直线。
超过某个点之后,你继续加东西,玩家获得的信息反而在减少 —— 因为新加的东西在遮挡旧的东西。
而在游戏里,玩家读不到的信息 = 他做不出的决策 = 他玩不好 = 他觉得这游戏很随机。
Juice 的预算是「注意力」
理解这一章只需要一个概念:玩家的注意力是一个固定的、很小的池子,而每个视觉元素都在从里面取钱。
屏幕不是无限大的画布,玩家的眼睛也不是。在任何一个瞬间,人能同时追踪的运动物体大概是 4 个左右。超过这个数,剩下的就变成了背景噪音。
把你游戏里所有的视觉元素分成三档,然后严格按这个顺序分配注意力预算:
| 档 | 是什么 | 要求 |
|---|---|---|
| A · 必须看见 | 会杀死玩家的东西、玩家控制的角色、当前目标 | 永远不能被遮挡。特效要给它们让路 |
| B · 应该看见 | 敌人状态、资源变化、可交互物 | 可以被短暂遮挡,但不能持续 |
| C · 看见了更好 | 环境动效、装饰粒子、背景 | 随时可以牺牲 |
规则很简单:C 档的东西永远不能盖住 A 档的东西。
而新手最常犯的错误恰恰是:给一个 C 档事件(打中了一个小怪)配了 A 档强度的特效(半个屏幕的爆炸)。
实操:给特效定一个「不许进入」的区域
一个很有效的具体做法:
- 玩家角色周围的一小圈区域,特效要么不生成,要么降低不透明度
- 屏幕边缘(玩家余光扫描危险的地方)保持干净
- 血条 / 关键 UI 附近不放粒子
这听起来很琐碎,但它是「华丽」和「混乱」的分界线。
Juice 的优先级:先做哪些
假设你只有两小时做 juice,该做什么?下面这个顺序是按每小时收益排的:
| 优先级 | 做什么 | 成本 | 为什么排这么前 |
|---|---|---|---|
| 1 | 缓动(easing) 所有 UI、所有移动,别用线性 |
极低 | 把「机械」变成「有生命」,一个函数的事 |
| 2 | 音效 哪怕是免费素材 |
低 | 贡献一半的手感,不占屏幕空间(第 11 章) |
| 3 | 命中停顿 | 低 | 三行代码换整个打击感 |
| 4 | 挤压拉伸 | 低 | 让角色有弹性和重量 |
| 5 | 过渡 场景切换、菜单进出别硬切 |
中 | 直接决定「像不像正经游戏」 |
| 6 | 粒子 | 中 | 收益开始递减,且最容易做过头 |
| 7 | 屏幕特效(模糊、色差、扭曲) | 高 | 收益最低,风险最高 |
大多数人的实际顺序是:7 → 6 → 然后就没时间了。正好反过来。
第 1 名值得展开:缓动
这是整本书里性价比最高的一个技巧,而且它和游戏类型完全无关。
把任何「从 A 移动到 B」的东西,从线性插值改成有加速度的曲线,画面立刻从「程序」变成「设计」。
# ✗ 线性:机械、廉价 position = position.lerp(target, 0.1) # ✓ 帧率无关的指数趋近:快速起步、平滑收尾 position = position.lerp(target, 1.0 - exp(-SPEED * delta)) # ✓✓ 或者直接用 Tween,带回弹的缓动函数 var t := create_tween() t.tween_property(self, "position", target, 0.3)\ .set_trans(Tween.TRANS_BACK)\ .set_ease(Tween.EASE_OUT)
第一行 position.lerp(target, 0.1) 是个经典 bug,它依赖帧率:
- 60 帧时:每秒趋近 60 次,每次 10%
- 30 帧时:每秒趋近 30 次 —— 移动速度直接减半
玩家在低配机器上会觉得摄像机「拖泥带水」,而你在自己机器上完全测不出来。
第二行的 1.0 - exp(-SPEED * delta) 是正确写法:不管帧率多少,一秒之后趋近的比例是一样的。把这个式子记下来,你会用一辈子。
挤压拉伸:两行代码的生命感
起跳时纵向拉长、落地时横向压扁,然后弹回原状。
func on_jump() -> void: scale = Vector2(0.76, 1.28) # 拉长 func on_land(impact: float) -> void: scale = Vector2(1.0 + 0.34 * impact, 1.0 - 0.30 * impact) # 压扁 func _process(delta: float) -> void: # 平滑弹回。同样用帧率无关的写法 scale = scale.lerp(Vector2.ONE, 1.0 - exp(-14.0 * delta))
两个细节让它从「还行」变成「很好」:
- 缩放的锚点要在脚底,不是中心。否则压扁的时候角色会陷进地里。(在 Godot 里把 Sprite 的
offset设成向上半个身高,或者用一个额外的 Node2D 作为缩放中心) - 形变量要和冲击力挂钩。从高处摔下来压得更扁 —— 这样它就不只是装饰,还携带了信息(第 11 章的第 ② 层职责)。
缓动曲线:哪种用在哪
既然缓动排第一,值得把它讲透一点。不同的曲线传达不同的「物理性格」,选错了会让人说不出哪里怪。
| 曲线 | 感觉 | 用在 |
|---|---|---|
| Ease Out 快起步、慢收尾 |
响应快、有阻尼 | 绝大多数情况的默认值。UI 出现、摄像机跟随、角色转向 |
| Ease In 慢起步、快收尾 |
蓄力、加速、坠落 | 东西离场、下坠、蓄力动作。不要用在「响应玩家操作」上 —— 会显得迟钝 |
| Ease In-Out | 平稳、正式 | 场景过渡、镜头推移。用在小控件上会显得拖沓 |
| Back(回弹) | 有弹性、俏皮 | 按钮按下、道具弹出、卡牌落位。用多了会显得廉价 |
| Elastic(震荡) | 夸张、卡通 | 非常克制地用在庆祝时刻。日常界面用它会让人烦 |
| Linear | 机械、无生命 | 只用在真正匀速的东西上:传送带、进度条、匀速旋转 |
凡是对玩家操作的响应,用 Ease Out;凡是自动发生的过渡,用 Ease In-Out。
原因:Ease Out 的开头最快,所以玩家会感觉到立刻有反应(第 11 章的「确认」职责),而结尾的减速提供了重量感。两者兼得。
而 Ease In 的开头很慢 —— 玩家按下之后有一小段几乎没动静的时间,那正是「不跟手」的感觉来源。永远不要用 Ease In 响应输入。
时长也要选
曲线之外还有时长。几个经验值:
- 对操作的即时反馈:60–120 毫秒。超过 150 毫秒开始有延迟感
- UI 元素进出:150–250 毫秒
- 场景过渡:300–500 毫秒。超过 800 毫秒玩家会不耐烦(尤其是他要看很多次的那些)
- 任何玩家会看一百遍的动画:越短越好。第一次觉得酷的过场,第五十次就是障碍物
最后一条特别重要。凡是重复出现的动画,都要能被跳过或者做得极短 —— 这直接关系到第 7 章那条「失败成本要压到 1 秒内」。
Juice 掩盖的那个真问题
这一节是本章存在的真正理由。
Juice 有一个危险的性质:它能让一个平庸的核心玩法在短时间内显得很好。
你加了粒子、震屏、顿帧,然后自己玩了一下 —— 哇,爽多了。于是你觉得游戏变好了。
但玩家的体验曲线是这样的:
前 30 秒 「哇,这个打击感不错」 ← juice 在起作用 第 5 分钟 「嗯……」 ← juice 的新鲜感耗尽 第 15 分钟 「好像有点无聊」 ← 只剩下核心玩法本身 第 20 分钟 关掉 ← 核心玩法撑不住
Juice 影响的是前五分钟,核心玩法决定的是后五小时。
这不是说 juice 不重要 —— 前五分钟极其重要,很多玩家根本活不过前五分钟。但你要清楚它不能做什么:
- Juice 不能让一个没有深度的动词变得有深度
- Juice 不能修复一个断掉的会话循环
- Juice 不能让假选择变成真选择
- Juice 不能替代手感的 A/B/C 三组(第 9、10 章)
一个诊断方法
怀疑自己在用 juice 掩盖问题?做这个测试:
把所有特效、震动、顿帧、粒子全部关掉,只留最基础的画面和音效,玩十分钟。 还有意思吗?
- 还有意思 → 你的地基是好的,juice 是纯净的加分。放心加。
- 变得很无聊 → 你的乐趣可能大部分来自 juice 的新鲜感。停下来,回卷 II 检查动词和循环。
这个测试之所以有效,是因为你自己已经对 juice 免疫了(看过几千遍),但对核心玩法的问题还是有感觉的。
因为关掉特效之后的游戏,看起来会很寒酸,而你会本能地觉得「这不公平,成品又不是这样」。
但恰恰是这个反应说明了问题:如果你需要特效才敢看自己的游戏,那你可能一直在回避一个你已经隐约知道的答案。
早点面对它,比在发布后从玩家的评论里读到它便宜得多。
什么时候该做 juice
一个明确的时间点建议:
| 阶段 | 该做的 juice | 不该做的 |
|---|---|---|
| 原型期 (验证好不好玩) |
只做音效,因为它是最便宜的确认反馈 | 其他全部不做。你要看的是裸的玩法 |
| 成型期 (玩法定了,做内容) |
缓动、命中停顿、挤压拉伸、过渡 | 还不要做粒子和屏幕特效 |
| 打磨期 (第 23 章) |
粒子、屏幕特效、全套时序调优 | — |
为什么原型期几乎不做 juice?因为 juice 会干扰你自己的判断。你需要在最裸的状态下确认「这个动词本身是不是有意思」,而 juice 会给你一个虚假的肯定答案。
本章小结
- Juice 是倒 U 曲线,不是上升直线。超过甜点之后,加的东西在遮挡信息。
- 预算是注意力:人同时能追踪约 4 个运动物体。把元素分成 A/B/C 三档,C 永远不能盖住 A。
- 优先级(按每小时收益):缓动 → 音效 → 命中停顿 → 挤压拉伸 → 过渡 → 粒子 → 屏幕特效。多数人的实际顺序正好相反。
- 记住这个式子:
lerp(a, b, 1 - exp(-k * delta))。直接写lerp(a, b, 0.1)是帧率相关的 bug。 - Juice 影响前五分钟,核心玩法决定后五小时。它不能修复卷 II 里的任何问题。
- 诊断:全关掉玩十分钟。变得很无聊 → 回去查动词和循环。
- 原型期只做音效,其他一律推迟到打磨期。
- 卡牌:juice 的甜点比动作游戏低,因为玩家需要读牌面文字。过度的粒子会直接让人看不清自己有几费。这类游戏的 juice 预算应该主要花在牌的移动缓动和结算的时序编排上,而不是特效。
- 塔防 / 策略:最需要克制的类型。同屏几十个单位,每个都带特效等于什么都看不见。做法:特效强度随缩放级别衰减 —— 镜头拉远时自动简化。
- 模拟经营:juice 主要花在「变化的可见性」上 —— 作物长大的那一帧要有动画,资源增加要有飘字。这类游戏的 juice 不是为了爽,是为了让缓慢的进展被感知到。
- 叙事解谜:juice 的甜点非常低。这类游戏靠氛围而不是刺激,一个不合时宜的震屏会毁掉整段情绪。把预算全部投到过渡和音效上。
- 射击 / 动作:甜点最高的类型,但也最容易过头。硬规则:玩家角色和子弹永远不能被自己的特效遮住。很多手游射击的差评就来自这一条。