Phaser 移动平台与电梯:路径、载客、挤压保护和同步

拆解平台动作游戏里的移动平台、电梯、载客状态、路径节点、挤压保护、角色粘附和场景同步。

为什么值得单独做成系统

平台动作关卡里,玩家跳上矿井电梯,电梯下降到中层,途中经过会挤压角色的横向平台。另一个场景中,移动平台按固定路径循环,玩家必须借它越过尖刺坑。平台看起来只是移动的地板,但它和角色控制、碰撞、机关状态强相关。

移动平台若只用 Tween 改 x 和 y,很容易出现角色滑落、碰撞穿透、挤压死亡误判和读档位置不同步。平台应该是有路径、有速度、有载客关系和安全规则的系统。 本文会按一个可上线的小系统来拆,不追求炫技,而是把数据结构、状态流、玩家反馈、调试工具和发布检查说清楚。Phaser 的优势是让画面和交互快速成型,但越是快速,越需要把规则层和表现层分开。

核心架构

flowchart TD
  N1["PlatformPath"] --> N2["MotionDriver"]
  N2["MotionDriver"] --> N3["PlatformView"]
  N2["MotionDriver"] --> N4["PassengerTracker"]
  N4["PassengerTracker"] --> N5["角色位移补偿"]
  N2["MotionDriver"] --> N6["CrushGuard"]
  N7["DoorInterlock"] --> N2["MotionDriver"]
  N8["CheckpointSync"] --> N2["MotionDriver"]

这张图的重点是单向流动。PlatformPath、MotionDriver、PassengerTracker、CrushGuard、DoorInterlock、CheckpointSync、PlatformView 不应该互相随意读写。输入或场景事件进入模型,模型输出快照或事件,Phaser 表现层再根据结果更新 Sprite、Graphics、Sound 和 UI。只要这条边界稳定,后续加内容、加难度、加存档或加多人同步,都不会把系统推倒重写。

路径节点要数据化

PlatformPath 记录节点、速度、等待时间、循环方式和触发条件。平台可以往返、单向、停靠或被按钮控制。不要把路径写在 Tween 链里,Tween 很难处理暂停、反向、读档和动态改目标。MotionDriver 每帧根据路径和 delta 计算平台位移。

实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。

载客关系要明确

角色站在平台上时,需要跟随平台移动。PassengerTracker 通过脚底传感器或上一帧接触法线判断角色是否是乘客。平台移动后,把位移补偿到乘客身上。不要只依赖摩擦力,否则高速平台会把角色甩掉;也不要无条件吸附,否则跳起时会被平台拉回。

实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。

电梯需要门和状态

电梯不是普通平台。它有楼层、门、按钮、占用状态和安全锁。DoorInterlock 确保门没关时不移动,到达楼层前不允许开门。玩家按按钮后,电梯进入 moving,期间忽略重复请求或排队。这个状态写清楚,剧情和机关才能可靠引用。

实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。

挤压保护要区分危险

平台把角色推向天花板时,应该判定挤压;平台轻微贴墙时,不应立刻杀死玩家。CrushGuard 检查平台移动方向、角色碰撞体、可逃脱空间和持续时间。给 80 到 150 毫秒缓冲,可以避免单帧误判。若确实挤压,反馈要明确。

实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。

暂停和读档要同步

移动平台在读档时要恢复路径进度、方向、当前节点和等待时间。只保存位置不够,因为下一帧不知道该往哪里走。CheckpointSync 保存 MotionDriver 的状态快照,读档后平台和机关一起恢复。

实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。

镜头震动要克制

大型电梯启动、停靠可以有轻微震动和音效,但不要影响玩家判断跳跃。平台运动本身已经提供动感,额外镜头反馈应只出现在重型机械或剧情时刻。分屏合作时,震动也要按相关玩家镜头触发。

实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。

调试显示路径和乘客

开发模式画出平台路径、当前目标节点、速度向量、乘客列表和挤压检测区域。移动平台问题经常是接触判断错,调试信息能立刻看出角色到底有没有被系统认定为乘客。

实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。

TypeScript 实现骨架

interface PathNode { x: number; y: number; waitMs: number }
class MotionDriver {
  index = 0;
  wait = 0;
  position = new Phaser.Math.Vector2();
  constructor(private nodes: PathNode[], private speed: number) {
    this.position.set(nodes[0].x, nodes[0].y);
  }
  update(dt: number) {
    if (this.wait > 0) { this.wait -= dt; return new Phaser.Math.Vector2(); }
    const target = this.nodes[(this.index + 1) % this.nodes.length];
    const before = this.position.clone();
    const to = new Phaser.Math.Vector2(target.x, target.y).subtract(this.position);
    const step = Math.min(to.length(), this.speed * dt / 1000);
    if (step > 0) this.position.add(to.normalize().scale(step));
    if (Phaser.Math.Distance.Between(this.position.x, this.position.y, target.x, target.y) < 1) {
      this.index = (this.index + 1) % this.nodes.length;
      this.wait = target.waitMs;
    }
    return this.position.clone().subtract(before);
  }
}

这段代码只展示核心边界,不是完整项目代码。真实项目里还需要补配置加载、错误码、事件派发、对象池、性能采样和测试。关键是让核心规则能独立运行,Phaser 层只是把规则结果变成玩家能感知的反馈。

落地步骤

  1. 第一,先把 PlatformPath 和 MotionDriver 写成普通 TypeScript 模型。不要让它们依赖 Phaser Scene、Sprite 或 Camera。核心模型越普通,越容易写测试、做编辑器预览和复现玩家问题。
  2. 第二,Phaser 层只做适配:接收输入、播放动画、更新图形、触发音效。它可以很薄,但必须清楚。只要某段规则开始读取 Sprite 的 visible、alpha 或动画状态,就说明边界正在变脏。
  3. 第三,给 PassengerTracker 或同等复杂的中间结果做调试显示。开发模式里能看到状态、阈值、候选对象、失败原因和耗时,后续调参才不会靠猜。
  4. 第四,准备三组测试夹具:正常流程、边界流程、错误配置。正常流程验证体验,边界流程验证稳定性,错误配置验证系统会报出人能看懂的问题。

检查清单

  • 确认 PlatformPath 的状态可以序列化,能写入存档或调试日志。
  • 确认 MotionDriver 的配置有默认值、版本号和校验错误。
  • 确认快速点击、暂停、切后台、读档和切场景不会重复提交关键事件。
  • 确认失败反馈足够具体,玩家能知道是条件不足、输入中断、资源不够还是规则禁止。
  • 确认低端机有降级策略,尤其是粒子、音效、动态对象和调试图层。
  • 确认开发模式可以导出最近关键事件,方便复现玩家反馈。

常见误区

第一类误区,是把表现当成事实。动画播完、按钮亮着、Sprite 存在,都只能说明表现层当前长什么样,不能说明规则已经完成。规则事实应该存在于模型和事件里。

第二类误区,是只为了第一个关卡写逻辑。第一个关卡对象少、输入慢、节奏简单,临时判断很难暴露问题。等内容增加,重复触发、配置错误和性能峰值会一起出现,早期的边界会决定后期成本。

第三类误区,是没有设计失败路径。复杂系统一定会遇到失败,好的失败路径会告诉玩家和开发者发生了什么;坏的失败路径只会留下一句操作失败,甚至什么都不显示。

发布前验证

发布前至少跑一次规则级测试和一次运行时冒烟。规则级测试不需要启动浏览器,直接喂数据,断言状态和事件。运行时冒烟则在 Phaser 场景里验证输入、反馈、暂停、重开和边界情况。若系统涉及经济、存档或排行榜,还要记录 requestId 或事件 id,保证重复提交不会造成重复奖励或重复扣费。

额外实践建议

  • 不要用 Tween 作为平台真相,路径进度要可存档。
  • 载客判断必须能调试显示。
  • 挤压判定要有缓冲,避免单帧误杀。

运行时观测与调参

移动平台的关键日志应该围绕乘客和危险事件:角色何时成为乘客、何时脱离、平台位移补偿多少、挤压检测持续多久、读档后路径进度是否一致。若玩家说自己从平台上滑下去,日志能告诉你是 PassengerTracker 没有识别,还是补偿位移过小。若玩家说被无故压死,检查 CrushGuard 的持续时间和可逃脱空间即可。关卡编辑时也可以显示平台路径耗时和等待点,帮助设计师判断跳跃窗口是否过短。平台系统越透明,平台关卡越敢做复杂。

对电梯类平台,还要记录每次停靠楼层和门状态。很多卡死问题不是平台没到位,而是门锁、按钮请求和平台等待状态不同步。把这些状态放在同一个面板里,比盯着坐标变化更容易定位。

结语

移动平台与电梯:路径、载客、挤压保护和同步 的关键不是某个 API,而是把可解释的规则交给模型,把可感知的反馈交给 Phaser。只要这条线清楚,项目就能持续扩展;如果所有逻辑都塞进 Scene 回调,第一版越快,后面的维护压力越大。

继续阅读

探索更多技术文章

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

全部文章 返回首页