本页尚未翻译,当前显示英文版本。
Locomotion
你声明物体如何移动,不需要任何人手写积分器。 移动模型把带序号的输入变成权威的运动:它与碰撞联动,为预测记录历史,并受增益、减益和地形影响。
何时使用
- 实体(entity)由玩家输入驱动移动(坦克、角色、载具),并且运动必须以服务器为权威(authoritative)。
- 你宁愿声明速度、加速度和转向速率的上限,也不想自己写积分器。
- 玩法会推动物体:
Impulse击退、Teleport,以及像泥地那样带持续时间的修正效果。 - 移动必须手感即时:同一个声明的模型既在服务器上步进,也在预测循环中步进。
- 无需使用:如果位置只按离散的步骤变化。实体上的一个同步字段就够了。
分工
| 主体 | 在本页中的职责 |
|---|---|
schema-author | 声明移动模型、约束和绑定 |
room-owner | 在主机上施加冲量、传送和修正效果 |
player | 提交带序号的输入;读取运动状态 |
适用于哪些房间
本模块只在由平台推进模拟的地方运行,即声明了 Host = "Backend" 的房间(room)。如果模拟归你自己的游戏服务器所有(PlayServ 作为元服务器),移动、碰撞和预测都留在引擎一侧,本页描述的是平台托管这一备选方案,而不是必须遵守的要求。
概览
声明
Tank 的移动模型:Locomotion.Tank,带速度、加速度和转向速率上限[Entity("tank")]
public class Tank
{
[Sync] public Vector3 Position;
[Motion(Model.Tank, MaxSpeed = 8f, Acceleration = 14f, TurnRateDeg = 120f)]
public Motion Motion;
}@Entity('tank')
export class Tank {
@Sync() position!: Vector3;
@Motion({ model: 'tank', maxSpeed: 8, acceleration: 14, turnRateDeg: 120 }) motion: Motion;
}@entity("tank")
class Tank:
position: Vector3 = sync()
motion = locomotion.motion(model="tank", max_speed=8.0, acceleration=14.0, turn_rate_deg=120.0)即将推出 —— Go
Go 中基于特性的声明方式尚未确定(O-1),确定写法后会补上示例。
UCLASS(PSEntity = "tank")
class UTank : public UObject
{
GENERATED_BODY()
UPROPERTY(PSSync) FVector3f Position;
UPROPERTY(PSMotion = (Model = "Tank", MaxSpeed = "8.0", Acceleration = "14.0", TurnRateDeg = 120))
FPSMotion Motion;
};
// declarations compile into the same pushed model — playserv push from the UE project or CI[Entity("tank")]
public class Tank
{
[Sync] public Vector3 Position;
[Motion(Model.Tank, MaxSpeed = 8f, Acceleration = 14f, TurnRateDeg = 120f)]
public Motion Motion;
}客户端输入是带序号的意图,运动由平台来步进:
客户端输入即带序号的意图:
Motion.Drive 按输入频率发送,在服务器端步进room.My<Tank>().Motion.Drive(throttle: 1f, steer: -0.4f); // cl — sent at input rateroom.my<Tank>().motion.drive({ throttle: 1, steer: -0.4 }); // cl — sent at input rateroom.my(Tank).motion.drive(throttle=1.0, steer=-0.4) # cl — a bot brain drives the same way即将推出 —— Go
Go 中基于特性的声明方式尚未确定(O-1),确定写法后会补上示例。
Room->Entities->Of<UTank>()->Select().GetMine().Then(
TPSOnResult<UTank*>::CreateWeakLambda(this, [this](const TPSResult<UTank*>& Result)
{
if (!Result.HasValue()) { return; }
// client — sent at input rate, numbered so the platform can acknowledge
Result.Value()->Motion->SubmitInput(FPSMoveInput{ .Throttle = 1.f, .Steer = -0.4f }, InputSequence);
}));
// co_await support ships later: a built-in SDK coroutine wrapper that respects Unreal's GC and threading.room.My<Tank>().Motion.Drive(throttle: 1f, steer: -0.4f); // cl — sent at input rate服务器端操作:
服务器端操作:击退冲量、持续 3 秒的泥地修正效果、一次干净的传送
tank.Motion.Impulse(knockback);
tank.Motion.Modify("mud", speedMultiplier: 0.6f, duration: 3.Seconds());
tank.Motion.Teleport(spawn);tank.motion.impulse(knockback);
tank.motion.modify('mud', { speedMultiplier: 0.6, duration: seconds(3) });
tank.motion.teleport(spawn);tank.motion.impulse(knockback)
tank.motion.modify("mud", speed_multiplier=0.6, duration=seconds(3))
tank.motion.teleport(spawn)即将推出 —— Go
Go 中基于特性的声明方式尚未确定(O-1),确定写法后会补上示例。
// on a dedicated server / master-client host
Tank->Motion->Impulse(EPSImpulseKind::Impulse, KnockbackVelocity);
Tank->Motion->Modify({ .Modifier = TEXT("mud"), .SpeedMultiplier = 0.6f, .For = FPSDuration::Seconds(3.f) });
Tank->Motion->Teleport(SpawnPosition, SpawnFacing);
// co_await support ships later: a built-in SDK coroutine wrapper that respects Unreal's GC and threading.tank.Motion.Impulse(knockback);
tank.Motion.Modify("mud", speedMultiplier: 0.6f, duration: 3.Seconds());
tank.Motion.Teleport(spawn);模型
实体要移动,需要声明什么。
| 声明项 | 含义 |
|---|---|
移动模型 | 从内置集合中选一个:转向、坦克、角色、载具、飞行。它们是同一个步进的几种实现,选择条件和默认值都由声明给出。步进是一个纯函数 (pose, input, dt) → pose |
参数 | 客户端可读的声明值;没有它们,预测(prediction)会系统性地偏离。参数属于 seed:策划会调整它们,部署不能悄悄丢掉这些修改;而反作弊所依赖的上限可以设为 managed,这样从管理控制台修改会被拒绝 |
上限 | 最大速度、加速度和制动,每次输入的最大转向,倒车倍率,以及部件单独的旋转速度。每次输入的转向与旋转速度特意分开声明:前者限制瞬时跳变,后者限制持续速率,是两道不同的防线 |
输入过期时的行为 | stop、continue until a declared deadline 或 continue indefinitely。没有“照旧继续”这种默认值,否则断网的玩家会一直开下去 |
位姿容差 | 客户端声称的位姿与服务器的位姿最多能差多远,并且可以按状态区分:静止、移动和刚重生后是三种不同的容差 |
步进频率与追帧上限 | 步进多久运行一次,以及服务器落后时一次最多能补多少步 |
|