关于 scenario-roblox-gameplay
面向 Roblox Studio 游戏系统程序员的技能,涵盖战斗、NPC 和载具。它强调可测试的规则、由服务器判定命中,并在 Lune 和实机测试中衡量性能。
主要功能
- 01服务器端空间查询战斗
- 02NPC 状态机与寻路
- 03NPC 调度处理和成本测量
- 04投射物与连击系统
- 05基于约束的载具配置
适用场景
- 01构建由服务器验证的近战战斗
- 02测试 NPC 行为与寻路
- 03衡量不同 NPC 数量下的服务器开销
- 04实现并测试载具控制
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-roblox-gameplay安装后在 Claude Code 中输入/scenario-roblox-gameplay确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/critique.mdexpert-notes.mdgui-paths.mdprocedures.mdsources.mdscripts/rbx_gameplay.pyscripts/agentkit/gameplay/Car.luauCarSafety.luauCombo.luauDebugDraw.luauGameplayAudit.luauGameplayInputs.luauHitbox.luaulune_gameplay_audit.luaulune_unit.luauNpcBrain.luauNpcPool.luauNpcService.luauPathGuard.luauProjectile.luauStateMachine.luauscripts/agentkit/gameplay/boot/GameplayClient.client.luauGameplayServer.server.luau详细介绍
Roblox 游戏玩法系统(游戏玩法系统程序员)
目标平台:macOS 上的 Roblox Studio(2026 年 10 月构建版),通过 scenario-roblox-expert 工具包驱动。
在专家级别,游戏玩法系统是一套纯规则:在 Lune 中测试,由一个服务器调度器接入引擎,并通过实测服务器开销的试玩验证。核心原则:客户端发送意图,服务器通过空间查询判定每次命中,所有数值在未经测量前都不得上线。如果这里提到的某项关联技能不在你可用的技能中,请让用户安装它(npx skills add scenario-labs/skills --skill <name>);若无法获得协助,则根据工具架构继续操作,并标明缺失项。
必备背景: scenario-roblox-expert(通道、审查流程、工具包、当前 Roblox 中容易踩的坑)。
状态(2026-10-19): Studio 0.743 中 23 项实时测试通过(Edit 探测、NPC 基准测试、hunt、调试绘图、连击、远程调用洪泛、车辆及其在油门按住时的退出、移动器,以及试玩 Server 中的每个文档代码片段);6 项离线检查通过(23 项 Lune 规格、luau-lsp 在 15 个套件文件和 12 个代码片段上使用两种类型求解器检查)。尚未运行:双人战斗(每个测试客户端都会打开一个 Studio 窗口)、触控设备测试、经过路径寻找修饰器和连接的路线测试。
原则(专家级差异)
- 意图由客户端发起,命中由服务器判定。 客户端发送不带参数的
Attack;服务器根据自己的时钟选择连击步骤,并查询根部前方的盒形区域。空间查询取代Touched(Ludius,gmz904QpfxU 00:01:15):客户端拥有的部件可以在服务器上的任意位置触发Touched(Network ownership 文档)。验证和速率限制:scenario-roblox-networking。 - 了解查询会跳过什么。 Spherecast、Blockcast 和 Shapecast 会忽略起点所在的部件(veraktt,GtqFcyFgIXQ 00:19:33)。用重叠查询检查起点。Shapecast 的最终位置为
origin + direction.Unit * Distance;Position是接触点(Crusherfire,EIOwGMZYidw 00:07:12)。使用ExcludeInstances或IncludeInstances,绝不要使用FilterDescendantsInstances,并为每次射击单独构建列表(BrawlDev,u6I17z6ggUg 00:28:41)。 - 先扫掠,再移动;按 dt 逐步推进。 在确认移动之前,先对整个步长执行投射(veraktt 00:12:22)。梯形位移使路径不受帧率影响(BrawlDev,0Dt-Ab8czPw 00:33:08);在 Lune 中测得:30、60 和 240 Hz 的结果相差不超过 0.001 studs,而欧拉积分的偏差为 0.5。
- 所有 NPC 共用一个调度器,并按目标数量测量。 每次 Heartbeat 处理一个分组,每个工作线程在预算内计算路径;感知先按距离筛选,再对静态几何体进行一次射线投射 [added]。测量结果基于 100 个 R15 NPC:服务器 60 fps,帧耗时 p95 为 17.6 ms,巡逻时 AI 每帧耗时 0.14 ms,追逐时为 0.26 ms;物理步骤增至 1.8 ms。Humanoid 物理的开销高于大脑,因此应按你的数量使用 AgentKit
Stats进行测量,并降低每个 Humanoid 的开销:禁用未使用的状态,将BreakJointsOnDeath设为 false,静态 NPC 不使用状态机,在多个波次中复用模型(P5)。 - 将 NPC 根部固定在服务器上。 玩家附近未锚定的 NPC 会由该玩家的客户端模拟并移动(实测:未固定的 NPC 距离玩家 6 studs 时归该玩家所有);在设定父级后调用
SetNetworkOwner(nil)(Network ownership 文档)。纯装饰性的人群可以使用客户端 Humanoid,每 5 s 为每个 NPC 更新一个属性(Suphi Kaner,JyMxrcqEzu8 00:13:50)。 - 大脑是带滞后的数据。 状态包含
onEnter、onStay、onExit,转换则以列表表示(Miller,Roblox Learn,nlVpAZEkxgo 00:00:57)。距离 5 studs 时进入 Attack,距离超过 6.5 时退出,失去视野 4 s 后放弃追击 [added]。寻路成功条件是pcall成功且Status == Success(BrawlDev,ckA4fVkAjIA 00:15:48);仅当Blocked时的索引位于下一个航点或之后,才重新计算路径(Pathfinding 文档)。重新发出MoveTo,因为它会在 8 s 后放弃。将路线代价集中在一个Costs表中(材质、PathfindingModifier和PathfindingLink标签),不要编写特殊情况代码;仅在地面上、已加载的世界中,且距离小于 3,000 studs 时计算;移动失败时跳到该航点,而不是目标点(P12)。 - 眩晕会取消待处理的攻击。 受击者排队中的挥击会被丢弃,且在有限时长的眩晕期间拒绝其请求(ArTheDev,Aoc9HkGHu_8 00:02:57)。每次挥击每个角色只能命中一次,不能按肢体分别计算(Ludius 00:04:06)。使用持续 0.2 s 的
LinearVelocity将 Humanoid 击退:一次ApplyImpulse让站立的假人移动了 1.2 studs,而LinearVelocity让其移动了 10.5 [measured]。 - 汽车由约束和所有权构成。 每个车轮使用一个 CylindricalConstraint 和一个 SpringConstraint,并连接到相同的附件;上限低于 0(Suphi Kaner,FVOowr2DXbM 00:10:19)。驾驶员坐在车内时拥有汽车(Network ownership 文档),服务器则持续检查速度;竞技赛车应使用 Server Authority。实时检查转向符号:这个工具包的首个版本按 D 时向左转。保持重心较低:底盘低且密度大,车身轻,座椅位置低且居中(FVOowr2DXbM 00:54:05)。离车时,释放马达,让松散部件归同一所有者,并从最高的出口点离开(P9, P14)。
首先确定
- NPC 数量,以及 NPC 是否造成或承受伤害(服务端),还是仅用于装饰(客户端人群)。
- 命中模型:近战框、命中扫描射线,或具有飞行时间和下坠效果的抛射物(Weapons 工具包文档)。
- 竞技或休闲:竞技类移动和载具交由 Server Authority 处理 (scenario-roblox-networking)。
- 平台:手机是最常见的设备,因此每个战斗操作都要绑定一个按键、一个游戏手柄按钮
和一个屏幕触控按钮,并通过
InputBinding.UIButton进行绑定 (P7)。
未确认时的默认值:NPC 在服务端运行,6 个桶,每秒 30 条路径;近战框为 5 × 5 × 5 studs,距离 3.5 studs;抛射物使用半径 0.25 studs 的球体扫掠;载具采用下方的数值。
流程
完整代码和测试结果:procedures.md。模块: scripts/agentkit/gameplay/;Python: scripts/rbx_gameplay.py。
- 安装。 目标:在打开的 place 中安装工具包、启动脚本和 Input Action 实例。方法:
rbx_gameplay.install(studio)会在 Edit 中写入Source(P1)。验收关卡:Playtest 的 Server 能看到 hook 和 remotes;Client 能看到GameplayInputs.Combat.Attack;控制台中没有启动错误。 - 探测查询。 目标:获取此构建版本的事实数据。方法:执行 Edit 探测(P2)。验收关卡:从内部发起的 Spherecast 会返回远处的部件;Shapecast 距离与预期行程相差不超过 0.05 studs。
- 在 Lune 中实现决策逻辑。 目标:获得清晰且经过测试的决策表。方法:使用
StateMachine和NpcBrain(P4)。验收关卡:lune run lune_unit.luau通过。 - 人群和开销。 目标:明确服务端开销。方法:使用
NpcService和基准测试(P5)。验收关卡:100 个根部件中有 0 个由客户端所有;记录每个数量下的服务端 fps 和 p95;与 scenario-roblox-performance 确定预算。 - 追猎。 目标:协同实现感知、寻路和近战。方法:
walk_to让玩家先进入视线,再移动到墙后(P6);制定寻路失败规则和路线定价(P12)。验收关卡:NPC 能到达墙后的玩家并命中;记录结果。 - 战斗。 目标:实现一个能抵御连发和眩晕的连击。方法:使用 Input Action、intent remote、
Combo和Hitbox.box(P7);使用Projectile实现抛射物(P8)。验收关卡:两个正面的假人生命值均为 58,后方的假人未受影响;连发时,已接受的挥击间隔不小于 0.24 s;0.2-stud 厚的墙能挡住所有抛射物。无论等待多久,user_keyboard_input都会以 0.13 至 0.20 s 的间隔发送按键;洪泛测试通过客户端脚本发送 remote(P7)。 - 载具。 目标:能够驾驶和转向,并保持平稳。方法:使用
Car.build、Car.serve、Car.controller(P9)。验收关卡:驾驶员拥有底盘;按住 W 3 s 后,载具向前移动超过 30 studs;同时按住 W 和 D 后,载具右转超过 20 degrees;UpVector.Y保持在 0.8 以上;退出后所有权恢复为自动;在油门按住时离开会让载具停下(P14);记录前后状态。 - 审计和审查。 方法:使用
GameplayAudit、负责人执行的Audit(P3)、审查和一张联系表。验收关卡:0 个错误。
数值
| 数值 | 默认值 | 相对于 |
|---|---|---|
| 思考频率 | 每个 NPC 每秒 10 次 | 60 fps 下 6 个时段 |
| 路径预算 | 每秒 30 次 | 整个服务端 |
| 检测、攻击、离开范围 | 60、5、6.5 studs | 目标根部;追击范围为检测范围的 1.5 倍 |
| 视野丢失 | 4 s | 上次看到目标的时间 |
Humanoid MoveTo 超时 | 8 s | 每次思考时重新发出指令 |
| 路径限制 | 3,000 studs、20,000 个节点;超出任一限制均会以错误 Status 失败 | 起点到终点(P12) |
| 路线成本 | 默认 1,最后手段为 20 到 1,000,math.huge 表示永不通行 | Costs 键:材质、修改器和链接标签(P12) |
| 触控按钮 | 72 px,位于右下角,与跳跃按钮保持距离 | 仅当 PreferredInput 为 Touch 时显示;布局检查:scenario-roblox-ui(P7) |
| 连击伤害 | 10、12、20 | 第 1 至 3 招 |
| 连击间隔 | 0.30、0.30、0.45 s,容差为 0.8 | 上一次已接受的挥击 |
| 终结技击退 | LinearVelocity 为 45 studs/s,持续 0.2 s;MaxForce 为质量乘以重力再乘以 20 | 远离攻击者 |
| 连击窗口、终结技锁定、眩晕 | 0.9、0.6、0.35 s | 上一次挥击或命中 |
| 投射距离 | 1,024 studs(形状投射),15,000(射线) | 每次调用 |
| 悬挂 | 刚度 3500、阻尼 200、自由长度 2.8 | Suphi Kaner |
| 滑动限制 | 上限 -1,下限 -2 | 沿 Attachment0 X 轴(向上) |
| 驱动 | MaxSpeed / radius、扭矩 5000、怠速 2000 | 后轮 |
| 转向 | 0.4 s 内转动 30 degrees | 车身前部的附件 |
| 汽车速度检查 | MaxSpeed 的 1.5 倍;1 s 内检查两次 | 服务端,且车辆由驾驶员拥有时 |
| 100 个 NPC,实测 | 60 fps、p95 17.6 ms、心跳 0.27 ms、物理 1.8 ms、发送速率 21.5 kbps | 巡逻中,服务端,Studio 0.743 |
| 单条路径,实测 | 65 ms 墙钟时间(会让出执行权),0 次失败 | ComputeAsync,开放底板 |
| 投射,实测 | Spherecast 0.46、Raycast 0.30 microseconds | 50 studs,小型包含列表 |
| 汽车,实测 | 3 s 行驶 177.9 studs,最高速度 51.0 studs/s;2.5 s 转向 112 degrees | W,然后 W 加 D |
质量门槛
- 可测量:Lune 规格;
rbx_check错误数为 0;GameplayAudit错误数为 0;NpcService.stats()(状态、客户端拥有的根部件、AI 毫秒数、路径);Server 中的 AgentKitStats;假人生命值和命中次数;汽车样本(距离、朝向、UpVector.Y)。 - 视觉:通过
rbx_review.contact_sheet查看人群、墙后追捕、终结技后的假人、汽车驾驶前后的截图(不超过 1,600 px)。在 Visualization Options 中启用 Navigation mesh 或 Network owners,并用DebugDraw装饰器绘制路点和查询框,进行深度测试,确保截图中能看到它们(P13)。 - 关键测试会记录客户端输入,并在输入与发送的按键不同时重新运行(P7)。
常见错误
| 错误 | 症状 | 修复 |
|---|---|---|
Touched 造成伤害 | 隔墙命中、伤害异常 | 在服务器上进行盒体查询 |
| 每个肢体返回一个结果 | 每次挥击命中 3 到 5 次 | 按角色模型对结果去重 |
| 投射物从墙内开始 | 射击穿透墙壁 | 首次扫描前进行重叠查询 |
每帧通过 Position 传送 | 高速移动时发生穿透 | 先扫描,再移动 |
FilterDescendantsInstances | 在新代码中属于已弃用的 API | 使用 ExcludeInstances、IncludeInstances |
| 可查询调试部件 | 射线检测停在自己的标记上 | 将 CanQuery 设为 false(Crusherfire 00:10:42) |
MoveToFinished:Wait() | NPC 在 8 秒后冻结 | 重新发出 MoveTo;处理 reached == false |
| 在空中或地图加载前计算路径 | Status 异常,NPC 静止不动 | 等待 FloorMaterial,并在加载完成后再执行(P12) |
| 移动失败后直接传送到目标点 | NPC 会穿过墙壁 | 传送到该路径点(P12) |
| 在代码中规避危险 | 特殊情况处理脆弱 | 在 Costs 中为修改器标签设定成本(P12) |
| 启用每个 Humanoid 的所有功能 | 每个 NPC 都会增加物理步骤开销 | 精简状态、使用对象池;静止时不启用状态机(P5) |
调用 ComputeAsync 时未使用 pcall | 路径异常时脚本会终止 | 使用 pcall 并检查 Status |
| NPC 根部未固定 | 最近的客户端会移动 NPC | 调用 SetNetworkOwner(nil) |
| 每个 NPC 一个循环 | 开销随脚本数量增长 | 使用一个调度器和分组 |
| BodyVelocity | 已弃用的驱动器 | 使用 LinearVelocity、VectorForce、AlignPosition |
约束未设置 Attachment0 | 无法移动,且不报错 | 使用 GameplayAudit constraint-no-attachment |
| 悬架上限为 0 | 弹簧触底,汽车弹跳 | 将上限设为 -1 |
读取 Throttle | 不支持游戏手柄模拟输入或触控输入 | 使用 ThrottleFloat、SteerFloat |
| 乘客拥有汽车 | 驾驶员会遇到延迟 | 在 Occupant 变化时重新分配所有权 |
| 只有一个固定出口侧 | 汽车翻转时,玩家会掉到地图下方 | 使用最高的出口点(P14) |
| 离开时未重置马达值 | 空车会继续行驶 | 离开时释放马达(P14) |
| 只能使用键盘进行战斗 | 手机无法攻击 | 绑定触控 UIButton(P7) |
交接
- 从 scenario-roblox-architecture 接收:RoundMachine 回合循环、用于带标签武器和危险物的 Binder、DamageService 插槽。
- 交付给 scenario-roblox-networking:待验证的命中箱、弹道和技能规则(带回溯的
HitCheck)、用于可疑度评分的汽车速度标记、服务器权威设置。 - 交付给 scenario-roblox-animation:NPC 的
State和Action属性及连招步骤,用于驱动动画轨道;在服务器权威模式下,不缓存动画轨道。 - 交付给 scenario-roblox-vfx-audio:命中位置、法线和用于冲击特效的步骤。
- 交付给 scenario-roblox-ui:用于提示和重新映射的
GameplayInputs上下文和操作。 - 交付给 scenario-roblox-performance:NPC 基准数据和预算。
- 与 scenario-roblox-luau 共享:固定步长代码(
BindToSimulation)和 Deferred 事件规则。
当前 Roblox 说明
RaycastParams和OverlapParams:ExcludeInstances和IncludeInstances取代了FilterDescendantsInstances和FilterType(2026-04-07)。参考文档中列有RaycastParams.Margin和SizeGradient,但在 0.743 中设置任一属性都会报错“not enabled yet”(P2): 粗射线请继续使用Spherecast。- 碰撞组位于
workspace上(RegisterCollisionGroup、CollisionGroupSetCollidable);PhysicsService方法已弃用。 - 使用
PathfindingService:CreatePath和Path:ComputeAsync;FindPathAsync和ComputeRawPathAsync已弃用。PathfindingModifier 和 PathfindingLink 无需启用 beta。 - 文档说明
RunService:BindToSimulation需要Workspace.UseFixedSimulation。在 0.743 中, 即使 place 从未设置该属性,它仍能在 Edit 和 Play 中运行(P11);脚本无法从 Studio MCP 上下文读取此属性,因此请在 Rojo 项目中显式设置。 - Creator Store 模型已沙盒化(2026-05-13):FastCast 等供应商库应以源码形式提供。
参考资料
- references/expert-notes.md:按专家整理的原则,附时间戳。
- references/procedures.md:P1 至 P14,包含完整代码和测试结果。
- references/critique.md:自我审查准则。
- references/gui-paths.md:Studio 菜单及脚本化替代方案。
- references/sources.md:所有来源及实时测量设置。
- scripts/rbx_gameplay.py:安装、固定数据、钩子、键盘序列、 审计。
- scripts/agentkit/gameplay/:Luau 模块和 Lune 运行器。