2D 载具手感不是把角色速度调快
Phaser 里做 2D 载具,最简单的方法是把角色换成车图,按方向键改变速度。但车和角色的手感完全不同。角色可以瞬间转向,车需要加速、刹车、转弯半径、惯性和抓地力。若只是用角色控制器,车会像滑动的图标;若完全按真实物理,车又可能难以控制。载具系统的目标不是物理仿真,而是让玩家相信它是一辆有重量、有惯性、可被掌控的车。
2D 载具常见在俯视角竞速、开放世界驾驶、战斗载具、配送小游戏和漂移挑战中。不同玩法对手感要求不同。竞速需要稳定路线和漂移奖励;开放世界需要低速可控;战斗载具需要瞄准和移动协调;休闲小游戏需要容错。Phaser 可以用 Arcade Physics、Matter Physics 或自定义运动模型。对于多数俯视角载具,自定义运动模型更容易调手感。
用局部坐标理解速度
载具速度可以拆成前向速度和侧向速度。玩家按油门增加前向速度,转向改变车头方向,抓地力逐渐削减侧向速度。漂移的本质是允许一定侧向速度存在,并用视觉和奖励表达它。若只维护世界速度向量,很难调出车头、惯性和侧滑之间的关系。用局部坐标能让参数更清楚:forwardSpeed、lateralSpeed、heading、angularVelocity。
每帧更新时,先根据输入调整油门和刹车,再根据速度决定转向能力,再用抓地力衰减侧向速度,最后把局部速度转换成世界位移。低速时转向可以更灵活,高速时转向半径变大。漂移键或急转弯时降低抓地力,让侧向速度保留更久。
flowchart TD
A["Input:油门、刹车、转向、漂移"] --> B["VehicleController 计算局部速度"]
B --> C["GripModel:地形摩擦、漂移状态、速度修正"]
C --> D["SteeringModel:转向角速度和车头方向"]
D --> E["CollisionResolver:墙体、障碍、反弹和损伤"]
E --> F["Phaser Sprite:位置、旋转、轮胎痕、粒子"]
F --> G["Telemetry:速度、侧滑角、漂移时间"]
加速和刹车要有曲线
线性加速会显得机械。很多载具在低速时加速快,高速接近上限时加速变慢。可以用曲线或简单插值实现。刹车也分普通松油、主动刹车和倒车。松油只是自然阻力,主动刹车更强,倒车需要车速接近 0 后才开始。若一按反方向立刻倒车,载具会像角色一样不真实。
最高速度也不应只有一个值。不同地形、升级、受损状态、天气都可能影响速度。泥地降低最高速度和抓地力,冰面降低抓地力但不一定降低速度,柏油路抓地强,草地阻力大。地形摩擦可以来自 Tilemap 属性,车辆每帧读取当前位置的 surface type。
漂移是可控的失控
漂移好玩的地方在于玩家主动进入侧滑,再控制它结束。按下漂移键时,抓地力降低,转向响应改变,侧向速度保留。松开漂移键或车头与速度方向重新对齐时,抓地力恢复。漂移期间可以积累能量、分数或氮气,但必须防止玩家原地刷分。漂移奖励应与速度、角度、持续时间和路线风险相关。
漂移角度可以用车头方向和速度方向的夹角计算。角度太小不算漂移,角度太大可能失控或打滑。UI 可以显示轻量漂移火花、轮胎痕和分数增长。不要只靠数字告诉玩家漂移成功,视觉反馈很重要。
一个简化载具控制器
下面的代码展示局部速度和抓地力的核心思路。真实项目会加入碰撞、地形和动画。
interface VehicleInput {
throttle: number;
brake: number;
steer: number;
drift: boolean;
}
interface VehicleState {
x: number;
y: number;
heading: number;
forwardSpeed: number;
lateralSpeed: number;
}
export function updateVehicle(state: VehicleState, input: VehicleInput, dt: number) {
const maxSpeed = 520;
const accel = 760;
const brakePower = 980;
const grip = input.drift ? 2.2 : 7.5;
const steerStrength = 2.8 * Math.min(1, Math.abs(state.forwardSpeed) / 180);
state.forwardSpeed += input.throttle * accel * dt;
state.forwardSpeed -= input.brake * brakePower * Math.sign(state.forwardSpeed) * dt;
state.forwardSpeed = Phaser.Math.Clamp(state.forwardSpeed, -160, maxSpeed);
state.heading += input.steer * steerStrength * dt;
state.lateralSpeed += input.steer * Math.abs(state.forwardSpeed) * 0.45 * dt;
state.lateralSpeed += (0 - state.lateralSpeed) * Math.min(1, grip * dt);
const cos = Math.cos(state.heading);
const sin = Math.sin(state.heading);
state.x += (cos * state.forwardSpeed - sin * state.lateralSpeed) * dt;
state.y += (sin * state.forwardSpeed + cos * state.lateralSpeed) * dt;
}
这个模型不是严格物理,但参数直观。grip 越高,侧滑越快消失;steerStrength 决定转向;lateralSpeed 决定漂移感。调车感时,先让这些数值在调试面板里可见,比盲目改速度有用得多。
碰撞反馈要保留动量感
载具撞墙不能像角色一样直接停住。可以根据碰撞法线反射部分速度,削减前向速度,增加震动和火花。轻微擦碰只减速,正面撞击明显反弹或停顿。若游戏有损伤系统,撞击强度进入 DamageResolver。碰撞反馈要和赛道宽度、转弯半径配合。赛道太窄、碰撞太硬,玩家会不断卡墙;碰撞太软,又没有驾驶压力。
Arcade Physics 可以处理简单碰撞,但载具运动若完全自定义,需要手动解决与墙体的交叠。Matter Physics 更适合复杂形状,但调手感成本更高。多数俯视角休闲载具可以使用圆形或胶囊近似碰撞,避免车角卡住墙。
镜头和速度感
载具速度感不只来自数值。镜头可以随速度略微拉远,前方视野增加;背景和路面线条提供流动感;高速度时增加轻微屏幕边缘模糊或风声。不要把速度感全部压到控制器上,否则车会快到难以控制。镜头提前量要根据车头方向和速度调整,玩家需要看到前方弯道,而不是车尾。
漂移时镜头不要剧烈旋转。俯视角游戏如果镜头跟着车头快速转,会让玩家晕。通常保持世界方向稳定,只让车辆旋转,必要时加轻微偏移。竞速游戏的可读性比电影感更重要。
调试曲线和测试赛道
载具手感需要专门测试场。直道测试加速和最高速,连续弯测试转向,发夹弯测试漂移,窄路测试碰撞,混合地形测试摩擦。不要只在正式关卡里调参数。调试面板显示 forwardSpeed、lateralSpeed、driftAngle、surface、grip、steerStrength。设计师可以实时改参数并保存预设。
还可以记录一圈遥测:每秒速度、漂移角、碰撞次数、刹车次数、出界次数。若玩家普遍在同一个弯撞墙,可能不是玩家菜,而是前方视野、摩擦或弯道提示有问题。载具手感最终要用数据和试玩一起判断。
上线前检查清单
确认载具使用局部速度或等价模型;确认加速、刹车、自然阻力分开;确认漂移有角度阈值和奖励限制;确认地形摩擦来自配置;确认碰撞不会让车角频繁卡墙;确认镜头根据速度提供前方视野;确认手柄和键盘输入都能细腻控制;确认调试面板显示关键速度和抓地参数;确认低帧率下使用稳定 delta 或固定步长;确认测试赛道覆盖直道、弯道、漂移和碰撞。
2D 载具的好手感来自一组可理解的妥协:足够像车,但不被真实物理拖累。Phaser 给了我们快速表现的能力,真正需要打磨的是速度、抓地、漂移和碰撞之间的关系。把这些参数暴露出来,并用测试赛道反复验证,车才会开起来有性格。
AI 载具和玩家载具不要共用全部控制
敌方车辆或幽灵车不应该直接模拟玩家输入。AI 更适合给出目标速度、目标路线和目标漂移点,再由简化控制器跟随。这样 AI 不会因为按键级模拟不稳定而撞墙。玩家载具需要手感和容错,AI 载具需要可预测和可调。两者可以共享 VehiclePhysics,但上层控制不同。
幽灵回放也可以保存控制输入或位置轨迹。若载具模型会频繁调参,旧输入回放可能不兼容,状态轨迹更适合展示。竞速排行榜则需要记录模型版本,避免不同手感版本成绩混在一起。载具系统一旦和排名相关,版本管理就不可省。
载具升级和差异化
不同车辆不应只改最高速度。可以调整加速度、刹车、抓地、漂移保持、重量、碰撞损伤、氮气容量。每个参数都影响手感。新手车抓地高、速度低;漂移车侧滑容易、恢复慢;重型车碰撞强但转向慢。UI 展示不要只给五条抽象星级,最好有试驾或参数说明。
升级也要避免破坏关卡。最高速度提升后,原本安全的弯道可能变得不可读。可以让升级同时提升镜头提前量或刹车能力。关卡测试要覆盖低级车和高级车,尤其是主线必过赛道。载具成长不能让旧内容变成纯撞墙。
音效和触感反馈
载具手感很依赖声音。引擎转速、轮胎摩擦、刹车尖叫、碰撞闷响都能帮助玩家理解状态。引擎音可以根据 forwardSpeed 调 pitch,漂移时叠加轮胎声,碰撞按强度选择音效。声音不能替代视觉,但会显著增强重量感。
支持手柄时,碰撞和漂移可以触发震动。震动要短而有层次,轻擦只轻微,正面撞击明显,长时间漂移不要持续强震。和屏幕震动一样,触感反馈也要有减少选项。
地图设计和车辆参数要一起调
车辆手感不能脱离赛道。一个转向半径很大的车,需要更宽的弯道和更早的预告;一个漂移车需要连续弯和外侧缓冲;重型车需要能发挥碰撞优势的障碍布局。若关卡先做好,再随便塞车辆参数,体验很容易错位。建议地图设计时标注推荐速度、弯道半径、刹车点和漂移点。
Phaser 调试模式可以在赛道上显示理想路线和速度区间。玩家测试时记录实际路线,和设计路线对比。若大多数玩家都冲出同一个弯,可能是弯道提示不足、镜头提前量不够,或者车辆减速能力太弱。不要只把问题归因于玩家操作。
边界、出界和重置
载具游戏经常需要处理出界。掉进水里、翻出赛道、卡在角落,都要有恢复规则。恢复点可以是最近通过的检查点,或者最近安全道路点。恢复时保留速度还是清零,也要按玩法决定。竞速游戏通常清零并有时间惩罚,开放世界可以温和地放回路边。
卡住检测也很重要。车辆速度很低、油门持续、位置几秒不变,可以提示按键重置或自动挪出。不要让玩家因为物理边界卡死而重开关卡。载具碰撞越复杂,恢复机制越必要。
这些恢复事件也应进入遥测,记录地点、速度和碰撞对象。若某个护栏反复触发卡住恢复,说明赛道碰撞或视觉提示需要调整。
这些数据也能反推哪些车辆参数过于激进。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。