
1. 项目概述为什么物理参数调优是游戏手感的核心做游戏开发这么多年我越来越觉得一个游戏好不好玩物理手感占了至少一半的功劳。你想想一个球在地上滚动是轻飘飘的像在冰上滑还是沉甸甸的带着真实的摩擦感一个角色撞到墙上是被“吸”住还是“砰”一下弹开老远——这些细微的差别直接决定了玩家是觉得“这游戏真带劲”还是“这物理好假”。而塑造这些手感的往往不是复杂的代码逻辑恰恰是物理引擎里两个看似简单的参数摩擦力Friction和回弹系数Restitution也叫弹性系数。在 Cocos Creator 的开发中我们直接使用的是内置的物理引擎无论是 Box2D 还是 Cannon.js 等后端。很多开发者尤其是刚入门的同学常常会陷入一个误区认为只要给物体挂上刚体RigidBody和碰撞体Collider物理效果就会自动变得真实。于是我们经常看到游戏里的物体要么滑得停不下来像个永动机要么碰撞后能量诡异越弹越高。这些问题十有八九都出在对PhysicMaterial物理材质的理解和调参上。物理材质就是物体的“皮肤属性”。它定义了当这个物体的表面与其他表面接触时应该如何交互。friction决定了它们之间有多“涩”或多“滑”而restitution则决定了碰撞后能量损失的多少即“有多弹”。这两个参数的值域通常都在 0 到 1 之间但背后的物理模拟和组合效果却千变万化。调好了你的游戏手感真实、反馈明确调不好整个游戏的交互逻辑都可能崩塌。这篇指南就是我结合大量实战项目踩坑、调试的经验为你梳理的一份 Cocos Creator 物理引擎摩擦力与 Restitution 参数的终极调优手册。我们不只讲这两个参数是什么更要深入它们如何相互作用在不同游戏类型如平台跳跃、弹球、赛车、物理解谜中应该如何设置以及那些官方文档里不会写的、只有实际调试才能摸清的“手感玄学”。无论你是想做一个手感扎实的 2D 平台游戏还是一个物理反馈奇妙的弹珠台这里的内容都能让你少走弯路。2. 核心概念深度解析Friction 与 Restitution 到底是什么在开始动手调参之前我们必须像了解老朋友一样彻底吃透这两个核心概念。一知半解地调参就像蒙着眼睛调音永远找不到那个正确的“音准”。2.1 摩擦力Friction不只是让物体停下来物理定义摩擦力是阻碍两个接触物体相对运动或相对运动趋势的力。在 Cocos Creator 的物理材质中friction是一个从 0 到 1 的标量值。0表示完全光滑无摩擦力。想象一下在绝对光滑的冰面上物体一旦运动几乎不会停止。1表示最大静摩擦力。在常规模拟中这通常意味着物体需要很大的力才能开始滑动一旦滑动也会很快停下。重要提示这里的 0 和 1 并不直接对应现实世界某个具体材料的摩擦系数如橡胶对混凝土可能大于1。它是物理引擎内部用于计算的一个相对、归一化的值。引擎会用接触的两个物体的friction值通过某种公式如取平均值、取最小值或使用特定的摩擦混合公式计算出一个“综合摩擦系数”用于本次碰撞的力计算。在游戏中的直观表现水平运动一个方块在平面上被推出friction越高它滑行的距离越短减速越明显。斜坡运动一个球放在斜坡上friction足够高时球会停在斜坡上friction很低时球会自己滚下来。旋转阻力物体在滚动或旋转时friction也会产生影响。高摩擦力会使旋转更快地停止。一个常见的误解开发者常常认为friction只影响“滑动”。实际上它也极大地影响“启动”。一个friction很高的物体你需要施加更大的力才能让它从静止开始移动。这在制作“推箱子”或“重物搬运”玩法时至关重要。2.2 回弹系数Restitution能量守恒的守门员物理定义Restitution 表示碰撞后法线方向上的速度恢复比例通俗讲就是“弹性”或“弹力”。它也是一个 0 到 1 的值。0完全非弹性碰撞。碰撞后物体在碰撞法线方向上的相对速度变为0。表现为物体撞上后“粘”在一起或者像一团湿泥巴砸在地上没有任何反弹。这是大多数需要“踏实”手感的游戏如角色行走、箱子堆放的常用设置。1完全弹性碰撞。碰撞后物体在法线方向上的速度大小不变方向反转。表现为理想状态的无限次反弹没有能量损失就像一个超级弹力球。在真实游戏中极少直接设为1因为会导致能量不衰减的永动反弹看起来很不自然。0到1之间部分弹性碰撞。这是最常用的范围。值越高反弹越有力值越低碰撞越“闷”。在游戏中的核心作用控制能量衰减一个球从高处落下每次撞击地面都会因为restitution 1而损失一部分垂直方向的速度能量所以反弹高度会一次比一次低直到停止。这是实现真实坠落感的关键。塑造碰撞反馈刀剑击中盔甲restitution低沉闷的“铛”声感 vs. 乒乓球击中球拍restitution高清脆的“啪”声感。不同的restitution配合音效能塑造完全不同的打击感。防止物理不稳定将restitution设置过高特别是接近1当两个高速物体或多个物体堆叠碰撞时极易引发数值计算的不稳定表现为物体“抖动”、“震颤”甚至“爆炸”般飞出去。这是物理调试中最常见的坑之一。2.3 两者的相互作用112 的复杂系统单独理解这两个参数不难难的是理解它们如何共同作用。它们不是独立的开关而是一个耦合系统。场景模拟一个保龄球高friction 中低restitution撞向球瓶。碰撞瞬间restitution决定撞击的“硬”度即球和瓶在接触点法线方向上的速度如何交换和损失。一个较低的restitution会让撞击看起来更有力、更“实”而不是轻飘飘地弹开。碰撞后滑动球和瓶在地板上滚动或滑动时friction开始主导让它们快速消耗动能最终停下。如果地板friction很低即使撞击很“实”球和瓶也会滑行很远显得很“飘”。另一个关键组合“打水漂”效果。想让一个扁平的石头Collider在水面另一个 Collider上弹跳多次。石头材质需要较高的restitution例如0.6-0.8确保碰撞后有足够的垂直速度反弹。水面材质需要极低的friction接近0这样石头在接触水面的瞬间水平方向的速度不会被摩擦力迅速消耗才能保持向前飞行的动力实现“蹭”一下飞出去的效果。如果水面friction很高石头第一次接触水面就会因为巨大的滑动阻力而失去大部分水平速度直接沉下去。理解这种相互作用是你从“参数调整工”迈向“物理手感设计师”的第一步。3. 物理材质PhysicMaterial的创建、配置与应用实战知道了“是什么”和“为什么”接下来就是“怎么做”。在 Cocos Creator 中所有关于摩擦力和弹性的调优都围绕PhysicMaterial这个资源展开。3.1 创建物理材质的两种方式Cocos Creator 提供了非常灵活的物理材质创建方式适应不同开发阶段的需求。方式一在编辑器资源管理器中创建推荐用于预制和复用这是最直观、最易于管理的方式尤其适合需要大量复用的材质。在资源管理器面板中右键点击空白处或目标文件夹。选择创建 - 物理材质 - PhysicMaterial。一个名为physic-material的资产就会被创建出来。你可以重命名它比如mat_wood木头材质、mat_ice冰面材质。选中这个材质在属性检查器中你就可以直接修改它的friction和restitution属性。方式二在代码中动态实例化推荐用于运行时动态调整当你需要根据游戏状态比如地面变湿滑了动态改变物体物理属性时代码创建是唯一选择。import { PhysicMaterial } from cc; // 创建一个新的物理材质实例 let slipperyIceMat new PhysicMaterial(); // 配置属性非常光滑有点弹性 slipperyIceMat.friction 0.05; slipperyIceMat.restitution 0.2; // 稍后可以将这个材质赋值给任何碰撞体实操心得对于大多数静态或预设好的材质如草地、水泥地、金属强烈建议使用方式一在编辑器中创建并配置好。这样不仅管理方便而且所有数值对设计师可见无需程序员介入即可调整手感。方式二则留给那些真正需要程序控制的特殊场景。3.2 将物理材质应用到碰撞体Collider创建好的材质必须应用到碰撞体上才能生效。每个 Collider 组件如 BoxCollider2D、CircleCollider2D都有一个Material属性。在编辑器中应用选中场景中带有 Collider 组件的节点。在属性检查器中找到该 Collider 组件。你会看到一个Material属性默认可能是None或者引用了全局默认物理材质。将资源管理器中的物理材质资产如mat_wood拖拽到这个属性框上或者点击后面的圆圈按钮进行选择。在代码中应用import { BoxCollider2D } from cc; // 假设我们有一个箱子的碰撞体组件 const boxCollider this.node.getComponent(BoxCollider2D); // 应用之前创建的冰面材质 boxCollider.material slipperyIceMat;关于“材质共享”的重要机制 这里有一个 Cocos Creator 物理引擎的关键特性也是很多坑的来源为了性能优化物理材质在默认情况下是共享的Shared。这意味着什么看这段代码const colliderA nodeA.getComponent(Collider2D); const colliderB nodeB.getComponent(Collider2D); // 假设它们最初使用的是同一个编辑器创建的材质 mat_common colliderA.material.friction 0.7; // 你以为只改了A // 但此时colliderB.material.friction 也变成了 0.7因为colliderA.material和colliderB.material引用的是同一个PhysicMaterial资产实例。修改其中一个所有引用该资产的地方都会生效。如何解决你需要“实例化”材质const colliderA nodeA.getComponent(Collider2D); // 正确做法先获取当前材质然后修改其属性 // 这会在内部创建一个该材质的独立实例 colliderA.material.friction 0.7; // 现在只影响 colliderA colliderA.material.restitution 0.2; // 或者如果你明确需要一个新的独立实例 const uniqueMat new PhysicMaterial(); uniqueMat.friction 0.7; uniqueMat.restitution 0.2; colliderA.material uniqueMat; // 现在 colliderA 拥有完全独立的材质踩坑记录早期项目里我们想做一个“被油污覆盖后变滑”的地板。程序员直接写了floorCollider.material.friction 0.1结果整个游戏里所有用这个默认材质的地板全都变滑了角色在其他关卡也站不稳。根本原因就是材质共享。务必记住如果希望某个物体的物理属性独立变化一定要确保它的material是独立的实例。3.3 全局默认物理材质在项目设置 - 物理中你可以找到一个Default Material的配置项。当某个 Collider 没有显式指定Material时就会使用这个全局默认材质。最佳实践为你的项目设置一个符合大多数物体感觉的“基准”默认材质。例如一个平台跳跃游戏可以将默认材质设置为friction: 0.4, restitution: 0.1这样大部分地面和普通物体都有适中的摩擦和较低的弹性。对于特殊的物体冰面、弹床再单独创建和应用特定的材质。这能保证游戏手感有一个统一的基线避免出现“有的地方滑有的地方涩”的割裂感。4. 参数调优实战针对不同游戏类型的配置策略理论说再多不如实际调一调。下面我结合几种最常见的游戏类型给出具体的参数配置思路和范围。记住这些数值只是起点最终手感需要你反复微调。4.1 2D 平台跳跃游戏如类马里奥游戏这类游戏对手感要求极高角色控制必须精准、反馈及时。地面Groundfriction:0.3 ~ 0.6。这是关键太低0.2角色起跑和急停会像在溜冰玩家难以控制太高0.7角色会感觉“粘”在地上转身和移动显得笨重。通常普通地面用0.4草地用0.5增加一点阻力冰面用0.1。restitution:0.0 ~ 0.1。必须非常低平台跳跃中角色落地后不应该有显著的垂直反弹。设为0是最安全的确保角色踩上去就稳稳站住。即使是从高处落下也仅通过动画或镜头震动来表现冲击而不是物理反弹。角色脚底Character Feet通常角色会用一个独立的、较小的碰撞体如脚底的 BoxCollider来与地面交互。friction:0.4 ~ 0.6与地面匹配或略高确保抓地力。restitution:0。绝对不要有弹性否则连续跳跃时会出现诡异的弹跳。墙壁Wallfriction:0.1 ~ 0.3。比地面低允许角色“蹭”着墙下滑如果你有爬墙机制可能需要更复杂的处理。restitution:0。角色撞墙应该立刻停下而不是被弹开。弹性平台Bouncy Platformfriction: 同普通地面或略低0.3-0.4。restitution:0.6 ~ 0.8。这是实现弹簧床、蹦床效果的核心。配合音效和粒子手感极佳。4.2 弹珠台/物理弹射游戏如 Peggle, Angry Birds这类游戏的核心乐趣就在于物体间充满动感的碰撞与反弹。弹珠/发射物Ball/Projectilefriction:0.05 ~ 0.2。非常低弹珠的滚动摩擦应该很小这样它一旦获得初速度就能持续滚动很久运动轨迹流畅。restitution:0.5 ~ 0.9。根据你想要的效果调整。想要清脆有力的碰撞就用0.7以上想要厚重、能量衰减快的碰撞就用0.5左右。警告多个高弹性物体堆叠时极易引发连锁反应和物理不稳定需要仔细测试。碰撞挡板/钉子Bumper/Pegfriction:0.1 ~ 0.3。restitution:0.8 ~ 1.0。可以设置得比弹珠更高这样碰撞时能给弹珠一个巨大的反向速度视觉效果非常刺激。这是弹珠台“爽感”的来源。场地边框Borderfriction:0.1。restitution:0.3 ~ 0.6。不宜过高让弹珠在边框上有几次衰减反弹即可最终应能平静地停留在场地底部。4.3 赛车/驾驶游戏手感核心是轮胎与地面的关系模拟抓地力和漂移。轮胎Tire Colliderfriction: 这是最重要的参数且通常需要各向异性处理但Cocos默认材质是各向同性的。我们可以用多个材质或代码模拟纵向驱动/制动需要较高的摩擦如0.8 ~ 1.0来模拟强大的加速和刹车抓地力。横向转弯摩擦系数应低于纵向如0.4 ~ 0.7。这个差值正是产生“转向过度”漂移感觉的物理基础。当侧向力超过横向最大静摩擦力时轮胎就会打滑。restitution:0 ~ 0.1。几乎完全非弹性赛车碰撞后不应有弹跳而是车身变形、能量被吸收的感觉。赛道地面柏油路friction: 0.9,restitution: 0砂石路friction: 0.6,restitution: 0滑动感更强冰面friction: 0.1,restitution: 0路肩/草地friction: 0.7,restitution: 0.1稍高的弹性模拟颠簸高级技巧要实现更真实的赛车物理仅靠一个friction值是不够的。你需要根据轮胎滑移率slip ratio动态调整摩擦系数这需要编写脚本根据车轮转速和车身速度的差值实时修改轮胎碰撞体的material.friction。这是赛车游戏物理的灵魂。4.4 物理解谜/堆叠游戏如 Cut the Rope, 堆箱子这类游戏要求物理稳定、可预测避免“混沌”行为。可互动物体箱子、木块、糖果friction:0.4 ~ 0.7。足够高的摩擦让物体堆叠时不容易滑落摆放更稳定。这也是实现“垒高”玩法的关键。restitution:0.0 ~ 0.2。必须非常低这是最重要的原则。高弹性会导致物体碰撞后乱飞堆好的结构轻易崩塌玩家会非常沮丧。所有用于堆叠的物体弹性系数最好设为0。静态环境平台、容器friction:0.5 ~ 0.8。比可互动物体略高提供稳定的基底。restitution:0。通用黄金法则在解谜和堆叠游戏中当你发现物体物理行为怪异、难以控制时首先尝试把所有restitution调到 0这能立刻解决80%的稳定性问题。5. 高级技巧与性能优化超越基础参数调好了基础参数游戏手感已经有了保障。但要追求极致或者解决一些棘手问题还需要一些“黑科技”。5.1 摩擦混合模式Friction Mixing当两个拥有不同物理材质的物体A和B发生碰撞时引擎如何计算它们之间的综合摩擦系数这就是摩擦混合模式。Cocos Creator 通常提供几种预设如average,min,multiply但有时需要更精细的控制。常见的策略取最小值MINcombinedFriction min(frictionA, frictionB)。这会导致“冰面效应”——只要接触面中有一个是光滑的整体就是光滑的。适合模拟物体在复杂地形上的运动比如轮胎同时接触柏油路和冰水混合物。取平均值AVERAGEcombinedFriction (frictionA frictionB) / 2。这是最常用、最直观的方式也是很多引擎的默认行为。相乘MULTIPLYcombinedFriction frictionA * frictionB。这会使得综合摩擦系数急剧减小通常用于模拟非常特殊的交互。如何设置这个设置通常在物理世界PhysicsWorld的配置里或者在项目物理设置中作为一个高级选项。了解你项目使用的物理后端Box2D, Cannon.js等的默认混合模式非常重要因为它直接影响你调参的预期结果。5.2 使用多个碰撞体组合复杂行为一个物体的物理属性不一定是均匀的。例如一个保龄球球体主体部分restitution设为0.3但在球体底部附加一个非常薄、friction极高的环形碰撞体来模拟球与球道接触点的真实摩擦防止它滑动过于“飘”。一辆车车身用一个低弹性、低摩擦的碰撞体而四个车轮则用四个独立的、高摩擦的圆形碰撞体。通过代码控制车轮碰撞体的启用/禁用来模拟离地。这种“组合碰撞体”的技巧可以让你用简单的物理参数模拟出非常复杂的物理交互效果。5.3 动态调整参数实现特殊效果通过代码在运行时修改material.friction和material.restitution可以实现丰富的游戏机制地面状态变化角色踩到香蕉皮 - 将角色脚底和地面的综合摩擦临时设为0.05持续2秒 - 角色打滑。道具效果“粘液弹”击中敌人 - 将敌人的material.friction临时设为0.8restitution设为0 - 敌人移动变得极其迟缓。角色能力“磁力模式”开启 - 将角色与金属平台的friction暂时提高 - 角色在金属面上行走如飞模拟磁吸。能量衰减曲线不想用固定的restitution可以写一个脚本在每次碰撞后根据当前速度动态计算并设置一个新的、更低的restitution实现自定义的非线性能量衰减。// 示例一个越弹越低的球 onCollisionEnter(other, self) { let myMat self.getComponent(Collider2D).material; // 每次碰撞弹性减少10%但不低于0.1 myMat.restitution Math.max(0.1, myMat.restitution * 0.9); }5.4 性能考量材质实例化与内存虽然动态创建和修改材质很强大但要警惕性能开销。避免每帧创建不要在update循环里new PhysicMaterial()。对象池化材质对于常用的几种材质如正常、湿滑、粘稠可以在游戏初始化时创建好放入对象池需要时取出用完后重置参数并放回。减少不必要的修改如果材质属性不需要变就不要在运行时去动它。物理引擎内部会对恒定属性做优化。6. 常见问题、调试技巧与避坑指南这是干货中的干货都是我项目里真金白银换来的经验。6.1 问题排查清单当你觉得物理效果不对劲时请按以下顺序检查现象可能原因解决方案物体滑动停不下来像在冰上摩擦力friction设置过低接近0逐步增加friction0.3-0.6是安全范围物体碰撞后疯狂弹跳甚至飞走回弹系数restitution过高接近1大幅降低restitution解谜游戏优先设为0物体堆叠时剧烈抖动、震颤1.restitution过高2. 物体质量mass差异过大3. 物理迭代次数不足1. 降低restitution至0.1以下2. 调整质量比避免极端如1:1003. 在项目设置中增加物理步迭代次数物体偶尔穿透其他碰撞体1. 物体速度过快“子弹穿透”2. 碰撞体形状或尺寸不匹配3. 物理引擎的连续碰撞检测CCD未开启1. 开启刚体的useCCD连续碰撞检测2. 检查碰撞体是否完全包裹视觉模型3. 对于高速物体确保每帧位移小于其自身尺寸修改了A物体的材质B物体也变了材质共享问题确保通过collider.material.property value的方式修改或为需要独立属性的物体创建新的PhysicMaterial实例斜坡上物体自动下滑不自然重力过大或friction不足以提供足够的静摩擦力微调重力大小或适当增加斜坡面和物体的friction6.2 调试神器物理调试绘制Cocos Creator 提供了强大的物理调试视图务必善用。在场景编辑器中点击右上角的显示/隐藏物理调试按钮通常是一个小弹簧图标。开启后你可以在场景中看到碰撞体形状以线框形式显示确保它们与你的精灵Sprite对齐。刚体速度向量用箭头显示物体的运动方向和速度大小非常直观。接触点显示物体间碰撞发生的具体位置。通过调试视图你可以一眼看出碰撞体是否错位、物体是否因高速而穿透、力的方向是否正确。这是定位物理问题最快的方法。6.3 参数微调的心得像调音师一样工作一次只调一个参数同时改friction和restitution你永远不知道是哪个起了作用。锁定一个微调另一个观察变化。建立“手感基准”在场景里放一个你理想中的“标准物体”比如一个方块把它调到你觉得最舒服的手感。之后所有其他物体的调参都围绕这个基准进行对比。使用极端值测试想知道参数的影响边界先把friction设为0和1restitution设为0和1看看最夸张的效果是什么。这能帮你快速建立数值变化的感性认识。记录你的配置为每一种“感觉”的材质如mat_heavy_wood,mat_bouncy_rubber建立文档记录下最终的friction和restitution值以及它用在什么类型的物体上。这对团队协作和项目维护至关重要。物理手感调优三分靠理解七分靠耐心和感觉。它没有绝对正确的答案只有最适合你游戏风格的“黄金参数”。最好的学习方法就是现在打开 Cocos Creator创建一个方块和一个平面开始拖动那两个滑块亲眼看看你的游戏世界是如何随着这两个数字而变得生动或怪异的。