Phaser Matter Physics 平台动作实践:斜坡、传感器和角色控制

讨论 Phaser Matter Physics 在平台动作游戏中的使用边界,覆盖角色控制、斜坡、传感器、碰撞分类和调试策略。

选择 Matter 之前先确认问题

Phaser 同时提供 Arcade Physics 和 Matter Physics。很多团队看到 Matter 支持更复杂的刚体、斜坡和多边形,就想直接上 Matter。问题是 Matter 更灵活,也更容易把角色控制做得难以预测。平台动作游戏最重要的不是物理真实,而是玩家按下按钮后得到稳定、可学习的反馈。

我参与过一个横版动作小游戏,前两版用 Arcade Physics。后来关卡加入斜坡、摆锤、推箱子和旋转机关,Arcade 开始显得吃力,于是团队切到 Matter。切换后第一个问题不是功能缺失,而是角色变“滑”:站在斜坡上慢慢下滑,跳跃落地时偶尔弹一下,被移动平台带走时速度叠加异常。Matter 没有错,只是我们还没把角色控制从真实物理里解耦出来。

Matter 适合处理复杂碰撞形状和动态刚体,但平台角色通常仍然需要“游戏化控制”。角色可以是一个 Matter body,但移动、跳跃、落地、贴地、下落加速度和边缘宽容都应该由角色控制器明确管理。

flowchart TD
    A[玩家输入] --> B[角色控制器]
    B --> C{当前接地状态}
    C -->|接地| D[水平速度和跳跃判断]
    C -->|空中| E[空中控制和重力调整]
    D --> F[Matter Body 速度更新]
    E --> F
    F --> G[碰撞事件]
    G --> H[脚底传感器/墙面传感器]
    H --> B
    G --> I[机关/敌人/道具响应]

角色不要直接相信碰撞回调

Matter 的碰撞事件会告诉你 body 之间开始接触、持续接触和结束接触。直接把 collisionstart 当作接地判断很诱人,但实际会遇到很多边界:角色侧面碰到墙也触发碰撞,头顶撞到平台也触发碰撞,斜坡接触点不断变化,多个地面同时接触时结束一个碰撞不代表已经离地。

更稳的方式是给角色增加脚底传感器。传感器是一个不产生物理反作用的 body,只用来检测脚下是否有可站立对象。角色主体负责物理位置,脚底传感器负责接地状态。传感器可以比角色脚宽略窄,避免侧面擦墙也被判定为接地。

接地状态也不要只看当前帧。平台游戏通常需要 coyote time,也就是角色离开平台后短时间内仍允许跳跃。还需要 jump buffer,也就是玩家提前按跳时,落地后立即跳起。这些都是手感规则,不是 Matter 自动提供的物理事实。

斜坡要限制真实物理

Matter 能处理斜坡,多边形碰撞比 Arcade 方便。但平台角色站在斜坡上时,真实重力会让它沿坡滑动。真实当然合理,游戏不一定需要。大多数平台动作希望玩家不输入时稳定站住,输入时顺着斜坡平滑移动。

常见做法是角色不完全依赖力和摩擦。每帧根据输入直接设置水平目标速度,同时根据接地法线和斜坡角度修正移动方向。不输入时,如果接地且坡度在可站立范围内,就抑制沿坡滑动。超过最大坡度才让角色滑下去。

斜坡还会影响跳跃方向。玩家在斜坡上按跳,通常期望向上跳,而不是沿斜坡法线弹出去。除非玩法明确需要物理弹射,普通跳跃应该使用角色规则定义的竖直速度。Matter 的接触法线可以作为参考,但不要让它完全决定手感。

碰撞分类必须提前设计

Matter 支持 collision category 和 mask。平台动作项目里,玩家、地面、单向平台、敌人、攻击盒、传感器、机关、道具都应该有明确分类。没有分类设计时,后期会出现脚底传感器触发金币、攻击盒撞墙改变角色速度、敌人传感器互相干扰等问题。

可以把分类拆成几组:WORLD 表示墙体和地面,PLAYER_BODY 表示玩家主体,PLAYER_SENSOR 表示脚底或墙面传感器,ENEMY_BODY 表示敌人主体,HITBOX 表示攻击判定,ITEM 表示拾取物,TRIGGER 表示剧情或区域触发器。每组只和需要的对象相互检测。

碰撞分类是架构决策,不是调 Bug 时临时改 mask。最好在项目初期就写成常量,并在调试面板里显示当前 body 的 category 和 mask。否则当碰撞关系复杂以后,很难凭肉眼判断某两个对象为什么会或不会碰撞。

移动平台不是普通地面

移动平台是 Matter 平台游戏里最容易出事故的对象。玩家站在平台上时,平台移动要带着玩家;玩家跳起时,不能继续被平台拖走;平台向上顶到玩家时,要避免穿透或抖动;平台突然转向时,不应该把玩家像弹球一样甩出去。

一个实用策略是把移动平台当成 kinematic 对象处理。它的位置由关卡时间线或路径控制,而不是由真实物理力推动。玩家脚底传感器检测到站在平台上后,角色控制器把平台位移作为一部分加入角色位移。这样手感更可控。

如果用 Matter body 直接推动玩家,也要限制平台速度和加速度。高速度平台容易产生穿透,尤其在低帧率移动浏览器中。移动平台的路径最好由固定逻辑时间驱动,而不是依赖每帧 delta 的累计误差。

传感器可以解决很多语义问题

除了脚底传感器,还可以使用墙面传感器、头顶传感器、攻击范围传感器和交互传感器。墙面传感器用于贴墙滑行或墙跳,头顶传感器用于判断是否撞天花板,交互传感器用于判断玩家是否靠近门、NPC 或机关。

传感器的好处是把语义检测和物理反作用分开。门不需要把玩家挡住也能提示交互,攻击范围不需要把敌人推开也能检测命中,墙面传感器不需要改变角色主体形状也能判断贴墙。

但传感器也要管理生命周期。角色死亡、切场景、换皮肤或变身时,传感器 body 要跟着主体创建和销毁。否则旧传感器可能还在世界里,导致幽灵碰撞。开发版可以把所有传感器用半透明颜色画出来,问题会直观很多。

性能和确定性要现实

Matter 比 Arcade 更重。H5 平台上,如果场景里有大量动态刚体、复杂多边形和高频碰撞,低端设备会吃不消。不要把每个装饰物都做成 Matter body,也不要让所有碎片永久参与模拟。能静态就静态,能合并就合并,能只用触发区就不要用真实刚体。

平台动作通常只需要少数关键动态物体:玩家、敌人、箱子、机关、可破坏物。背景装饰、远处粒子、普通掉落物不一定需要 Matter。碰撞形状也要简化。视觉上复杂的石头,物理上可以是一个矩形或简单多边形。

确定性也要谨慎。Matter 是物理引擎,不适合直接承担严格联网回滚里的权威模拟,除非团队能控制时间步、浮点差异和输入同步。单机和弱联网 H5 项目可以使用 Matter 做本地表现,联机强对抗则要把权威规则和表现物理分开。

调试工具决定能否上线

Matter 问题很难只靠感觉排查。建议开发版显示 body 边界、传感器范围、速度向量、接触点、接地状态、坡度、当前平台 id 和碰撞分类。尤其是接地状态,应该能看到由哪个传感器、哪个地面对象、哪个时间点决定。

还可以记录最近 20 次碰撞事件,包含 pair、category、isSensor、normal 和时间。角色突然无法跳跃时,查看日志就能知道脚底传感器没有接触地面,还是接触了但被 mask 过滤,或者 coyote time 已经过期。

调试工具不要等到出问题才做。Matter 项目如果没有可视化,很多 Bug 会在“像是物理怪了一下”的描述里消耗大量时间。可视化让策划、测试和工程都能看到同一个事实。

可操作的角色控制切口

下面的代码只展示思路:输入先进入角色控制器,控制器结合传感器状态决定速度,再把结果写入 Matter body。不要让输入层、碰撞回调和动画层都直接改 body。

type GroundState = {
  grounded: boolean;
  lastGroundedAt: number;
  groundBodyId?: number;
};

function updatePlayerController(player: Phaser.Physics.Matter.Sprite, input: InputState, ground: GroundState, now: number) {
  const body = player.body as MatterJS.BodyType;
  const vx = input.x * 4.2;
  const canJump = ground.grounded || now - ground.lastGroundedAt < 100;

  if (input.jumpPressed && canJump) {
    player.setVelocity(vx, -8.5);
  } else {
    player.setVelocityX(vx);
  }
}

这段实现没有使用真实力来推动角色,因为平台动作更关心响应和可控。真实项目还需要加入空中控制、跳跃缓冲、变高跳、斜坡修正和移动平台位移,但控制权仍然应该集中在角色控制器。

上线前检查清单

上线前至少检查:角色站斜坡是否会无输入滑动,单向平台是否能从下穿过且从上站住,移动平台是否稳定带人,低帧率下是否穿透,脚底传感器是否不会被墙触发,碰撞分类是否有文档,传感器是否随角色销毁,debug overlay 是否能解释一次异常碰撞。

还要在真实手机上跑长时间测试。Matter 在桌面浏览器里很稳定,不代表移动 WebView 里没有峰值。重点观察复杂机关区、多个敌人同时碰撞、平台高速移动和页面后台恢复后的第一秒。

从 Arcade 迁移到 Matter 的节奏

如果项目已经用 Arcade Physics 做了一批关卡,不要为了一个斜坡需求立刻全量迁移。更稳妥的做法是先把角色控制器抽出来,让输入、跳跃、接地、受击和动画不直接依赖 Arcade body。然后在一张测试关卡里用 Matter 重建同样的移动手感,对比起跳高度、落地时间、最大速度、边缘宽容和移动平台表现。

迁移期间可以让新旧关卡并存。普通矩形关卡继续走 Arcade,新机关关卡走 Matter,二者共享角色规则配置和动画状态机。这样团队能在真实内容里验证 Matter 的收益,而不是在 Demo 里得出乐观结论。等 Matter 方案稳定,再决定是否统一物理系统。统一不是目的,稳定交付才是目的。

还要留意内容工具。Tiled 或其他地图编辑器导出的碰撞形状,是否适合 Matter 多边形;美术是否能理解斜坡碰撞的简化规则;策划是否能标记单向平台和传感器区域。这些工作如果没有同步,物理系统升级会把复杂度转移给内容团队。

常见事故和处理方式

第一个常见事故是角色卡在两个斜坡交界处。视觉上只是两个 tile 拼在一起,物理上却可能形成一个很小的凹槽。处理方式不是继续调摩擦,而是在导出碰撞时合并相邻斜坡,或者用更简洁的多边形替代逐 tile 碰撞。平台动作里的碰撞几何越碎,边界问题越多。

第二个事故是角色在高速下穿过薄平台。低帧率时,上一帧在平台上方,下一帧已经到平台下方,碰撞引擎可能来不及给出理想结果。解决方式包括限制最大下落速度、加厚关键平台、提高固定步进频率,或者在角色控制器里增加向下的脚底射线辅助检测。不要把所有责任都推给引擎。

第三个事故是机关推动角色时动画状态错乱。Matter body 被推走了,但角色状态机仍以为自己在 idle。角色控制器应该订阅物理速度和接地变化,把外力移动也纳入状态判断。否则表现层和物理层会各说各话。

结语

Phaser Matter Physics 能让 2D 平台动作项目拥有更丰富的物理表达,但它不是手感的自动答案。角色控制、接地、斜坡、移动平台和传感器都需要游戏化规则。越是使用真实物理,越要清楚哪些部分服务表现,哪些部分服务规则。

如果项目只是矩形碰撞和简单跳跃,Arcade 可能更合适;如果项目确实需要斜坡、多边形、机关和动态刚体,Matter 很值得用。前提是你把碰撞分类、传感器、角色控制器和调试工具一起设计,而不是等角色开始打滑后再回头救火。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页