scenario-roblox-gameplay について
Roblox Studio向けのゲームプレイシステム開発スキルで、戦闘、NPC、乗り物を扱います。テスト可能なルール、サーバー側の命中判定、Luneとプレイテストでの性能測定を重視します。
主な機能
- 01サーバー側の空間クエリによる戦闘
- 02NPCのステートマシンと経路探索
- 03NPC処理のスケジューリングとコスト測定
- 04飛翔体とコンボシステム
- 05制約を使った乗り物の構成
活用シーン
- 01サーバー検証型の近接戦闘の構築
- 02NPCの挙動と経路探索のテスト
- 03NPC数に応じたサーバー負荷の測定
- 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 のゲームプレイシステム(ゲームプレイシステムプログラマー)
対象環境:scenario-roblox-expert ツールキットを通じて操作する、macOS 上の Roblox Studio(2026 年 10 月ビルド)。
エキスパートレベルでは、ゲームプレイシステムとは Lune でテストされた純粋なルールであり、単一のサーバースケジューラーによってエンジンに接続され、計測されたサーバーコストを伴うプレイテストで実証されるものです。基本方針は、クライアントは意図を送信し、サーバーは空間クエリですべての命中を判定し、計測していない数値はリリースしないことです。ここに記載された兄弟スキルが利用可能なスキルに見当たらない場合は、ユーザーにインストールを依頼してください(npx skills add scenario-labs/skills --skill <name>)。無人で進める場合は、ツールのスキーマに基づいて作業を進め、該当箇所を明示してください。
必須の背景知識: scenario-roblox-expert(チャネル、レビューの反復、ツールキット、Roblox の最新の落とし穴)。
状況(2026-10-19): Studio 0.743 でライブテスト 23 件に合格(Edit プローブ、NPC ベンチマーク、ハント、デバッグ描画、コンボ、リモートのフラッド、スロットルを押したままの車とその降車、ムーバー、プレイテストサーバー内のすべてのドキュメントスニペット)。オフラインチェック 6 件に合格(Lune 仕様 23 件、キットファイル 15 件とスニペット 12 件に対する両方の型ソルバーでの luau-lsp)。未実施:2 プレイヤーでの戦闘(各テストクライアントで Studio ウィンドウを開く必要があります)、タッチデバイス、パスファインディングモディファイアーとリンクを経由するルート。
方針(エキスパートならではの差分)
- 意図はクライアントから、ヒット判定はサーバーで行います。 クライアントは引数なしで
Attackを発火し、サーバーは自身のクロックからコンボの段階を決め、ルートの前方にあるボックスをクエリします。空間クエリはTouchedの代わりになります(Ludius、gmz904QpfxU 00:01:15):クライアント所有のパーツは、サーバー上のどこでもTouchedを発火できます(Network ownership doc)。検証とレート制限については、scenario-roblox-networking を参照してください。 - クエリが無視する対象を把握します。 Spherecast、Blockcast、Shapecast は、開始地点の内側にあるパーツを無視します(veraktt、GtqFcyFgIXQ 00:19:33)。オーバーラップクエリで開始地点を確認してください。Shapecast の最終位置は
origin + direction.Unit * Distanceで、Positionは接触点です(Crusherfire、EIOwGMZYidw 00:07:12)。FilterDescendantsInstancesは使わず、ExcludeInstancesまたはIncludeInstancesを使い、ショットごとにリストを作成してください(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 に 1 つのスケジューラーを使い、対象数で計測します。 1 つの Heartbeat で毎フレーム 1 バケットを処理し、1 つのワーカーが予算内で経路を計算します。知覚処理はまず距離で絞り込み、静的ジオメトリに対してレイキャストを 1 回行います [追加]。R15 NPC 100 体で計測した結果、サーバーは 60 fps、フレーム p95 は 17.6 ms、巡回中の AI は 1 フレームあたり 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 doc)。純粋に装飾目的の群衆は、NPC ごとに 5 秒ごとに 1 つの属性を送るクライアント側 Humanoid として動作させることができます(Suphi Kaner、JyMxrcqEzu8 00:13:50)。 - 脳はヒステリシスを備えたデータです。
onEnter、onStay、onExitを持つ状態と、リスト形式の遷移を使います(Miller、Roblox Learn、nlVpAZEkxgo 00:00:57)。5 studs で Attack に入り、6.5 を超えたら抜け、視界を失ってから 4 秒後に諦めます [追加]。経路探索の成功条件はpcallとStatus == Successの両方です(BrawlDev、ckA4fVkAjIA 00:15:48)。Blockedが発生した場合は、そのインデックスが次のウェイポイント以降のときに限り再計算してください(Pathfinding doc)。8 秒後にMoveToは諦めるため、再度発行してください。特別扱いのコードではなく、1 つのCostsテーブルでルートのコスト(マテリアル、PathfindingModifier、PathfindingLinkのラベル)を設定します。計算は地面の上で、読み込み済みのワールド内、3,000 studs 未満の範囲でのみ行ってください。移動に失敗した場合は、そのウェイポイントにスナップし、ゴールにはスナップしません(P12)。 - スタンは保留中のヒットをキャンセルします。 ヒットを受けたキャラクターのキューに入っている攻撃は破棄され、一定時間のスタン中はリクエストも拒否されます(ArTheDev、Aoc9HkGHu_8 00:02:57)。1 回のスイングにつきキャラクターごとに 1 回だけヒットさせ、部位ごとにはヒットさせません(Ludius 00:04:06)。
LinearVelocityを 0.2 s 適用して Humanoid をノックバックさせます。立っているダミーにApplyImpulseを 1 回適用すると 1.2 studs 動きましたが、LinearVelocityでは 10.5 動きました [計測]。 - 車は拘束と所有権で構成します。 ホイールごとに、同じアタッチメントに CylindricalConstraint と SpringConstraint を 1 つずつ設定し、上限を 0 未満にします(Suphi Kaner、FVOowr2DXbM 00:10:19)。運転手が着席している間は車を運転手が所有し(Network ownership doc)、サーバーは速度をチェックします。競技用レースでは 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 スタッド、距離 3.5 スタッド。投射物のスイープには半径 0.25 スタッドの球体を使用し、車の数値は以下のとおりです。
手順
完全なコードとテスト結果:procedures.md。モジュール: scripts/agentkit/gameplay/。Python: scripts/rbx_gameplay.py。
- インストール。 目標:開いているプレースにキット、起動スクリプト、Input Action インスタンスを追加します。方法:
rbx_gameplay.install(studio)が Edit でSourceを書き込みます(P1)。GATE:プレイテストの Server で フックとリモートが確認でき、Client でGameplayInputs.Combat.Attackが確認でき、コンソールに起動エラーがないこと。 - クエリを調査。 目標:このビルドに関する事実を確認します。方法:Edit のプローブ(P2)。GATE:内部からの Spherecast が 奥側のパーツを返すこと。Shapecast の距離が、予想される移動距離から 0.05 スタッド以内であること。
- Lune でブレインを作成。 目標:読みやすく、テスト済みの判定テーブルを作成します。方法:
StateMachineとNpcBrain(P4)。GATE:lune run lune_unit.luauが成功すること。 - 群衆とコスト。 目標:サーバーコストを把握します。方法:
NpcServiceとベンチマーク(P5)。GATE:100 個のルートのうち、 クライアント所有のものが 0 個であること。各数でサーバーの fps と p95 を記録し、scenario-roblox-performance と予算に合意すること。 - 追跡。 目標:知覚、パス、近接攻撃を組み合わせます。方法:
walk_toでプレイヤーを視界内に移動させ、 次に壁の後ろへ移動させます(P6)。パス失敗のルールとルートのコスト設定(P12)。GATE:NPC が壁の後ろにいるプレイヤーまで到達して ヒットを与えること。キャプチャを取得します。 - 戦闘。 目標:連打とスタンに耐えるコンボを作成します。方法:Input Action、意図を送るリモート、
Combo、Hitbox.box(P7)。Projectileを使った投射物(P8)。GATE:正面のダミー 2 体の体力が 58 で、後ろのダミーには 攻撃が当たっていないこと。連打しても、受け付けられたスイングの間隔が前回から 0.24 秒未満にならないこと。 0.2 スタッドの壁ですべての投射物が止まること。待機時間にかかわらず、user_keyboard_inputは 0.13〜0.20 秒間隔で 押下を配信します。フラッドテストでは、クライアントスクリプトからリモートを呼び出します(P7)。 - 乗り物。 目標:走行と操舵ができ、横転しないこと。方法:
Car.build、Car.serve、Car.controller(P9)。GATE:運転者がシャーシを所有すること。W を 3 秒間押すと、前方に 30 スタッドを超えて進むこと。W と D を同時に押すと、 右に 20 度を超えて曲がること。UpVector.Yが 0.8 を上回ること。降車時に所有権が自動に戻ること。 スロットルを押したまま降車すると車が停止すること(P14)。実行前と実行後のキャプチャを取得します。 - 監査とレビュー。 方法:
GameplayAuditとリードのAudit(P3)、批評、 コンタクトシート 1 枚。GATE:エラーが 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(レイ) | 1 回の呼び出しあたり |
| サスペンション | 剛性 3500、減衰 200、自由長 2.8 | Suphi Kaner |
| スライド制限 | 上限 -1、下限 -2 | Attachment0 の X 軸(上方向)に沿う |
| 駆動 | MaxSpeed / radius、トルク 5000、アイドル 2000 | 後輪 |
| ステアリング | 0.4 s で 30 度 | 車体前方のアタッチメント |
| 車速チェック | MaxSpeed の 1.5 倍、1 s 内に 2 回 | ドライバーが所有している間、サーバー側で実行 |
| NPC 100 体、測定値 | 60 fps、p95 17.6 ms、ハートビート 0.27 ms、物理演算 1.8 ms、送信 21.5 kbps | 巡回中、サーバー、Studio 0.743 |
| パス 1 件、測定値 | 壁時計時間 65 ms(yield を含む)、失敗 0 件 | ComputeAsync、空のベースプレート |
| キャスト、測定値 | Spherecast 0.46、Raycast 0.30 マイクロ秒 | 50 studs、小規模な include リスト |
| 車、測定値 | 3 s で 177.9 studs、最高速度 51.0 studs/s。2.5 s で 112 度 | W、次に W + D |
品質ゲート
- 測定可能な項目:Lune の仕様、
rbx_checkのエラー数が 0、GameplayAuditのエラー数が 0、NpcService.stats()(状態、クライアント所有のルート、AI の処理時間(ms)、経路)、Server 上の AgentKitStats、ダミーの体力とヒット数、車両のサンプル(距離、方位、UpVector.Y)。 - 視覚的な項目:群衆、壁の向こう側からの追跡、フィニッシャー後のダミー、運転前後の車両を撮影し、
rbx_review.contact_sheet(1,600 px 以下)で確認します。Visualization Options で Navigation mesh または Network owners をオンにし、DebugDrawアドーンメントでウェイポイントとクエリボックスを描画します。撮影画像に表示されるよう、深度テストを有効にします(P13)。 - キーテストではクライアントの入力を記録し、送信したキーと異なる場合は再実行します(P7)。
よくある間違い
| 間違い | 症状 | 修正 |
|---|---|---|
Touchedでダメージを与える | 壁越しに当たる、ダメージを悪用される | サーバーでボックスクエリを行う |
| 部位ごとに結果を1つずつ返す | 1回のスイングで3~5回ヒットする | キャラクターモデルごとに結果をキーにする |
| 壁の中から飛翔体が発射される | 弾が通り抜ける | 最初のスイープ前にオーバーラップクエリを行う |
フレームごとにPositionでテレポートする | 高速移動時にすり抜ける | スイープしてから移動する |
FilterDescendantsInstances | 新しいコードでは非推奨のAPI | ExcludeInstances、IncludeInstances |
| デバッグ用パーツがクエリ対象になっている | キャストが独自のマーカーで止まる | CanQueryをfalseにする(Crusherfire 00:10:42) |
MoveToFinished:Wait() | 8秒後にNPCがフリーズする | MoveToを再実行し、reached == falseに対処する |
| マップの読み込み前、または空中でパスを計算する | Statusが不正になり、NPCが動かなくなる | FloorMaterialを待ち、読み込み完了を条件にする(P12) |
| 移動に失敗した後、目的地にスナップさせる | NPCが壁をすり抜ける | そのウェイポイントにスナップさせる(P12) |
| コードで危険物を回避する | 場当たり的な特別処理が増える | Costsでコストを設定したモディファイアラベルを使う(P12) |
| すべてのHumanoidを完全に有効化する | NPCごとに物理演算の負荷が増える | ステートを絞り込み、プールを使い、静止時はステートマシンを使わない(P5) |
pcallなしでComputeAsyncを実行する | 不正なパスでスクリプトが停止する | pcallとStatusを併用する |
| NPCのルートが固定されていない | 最も近いクライアントがNPCを動かす | SetNetworkOwner(nil)を設定する |
| NPCごとにループを1つずつ使う | スクリプトが増えるほどコストが増える | スケジューラーを1つにし、バケットを使う |
| BodyVelocity | 非推奨のムーバー | LinearVelocity、VectorForce、AlignPosition |
Attachment0なしのConstraint | 何も動かず、エラーも出ない | GameplayAudit constraint-no-attachment |
| サスペンションの上限が0 | スプリングが底付きし、車が跳ねる | 上限を-1にする |
Throttleを読み取る | ゲームパッドやタッチ操作でアナログ入力ができない | ThrottleFloat、SteerFloat |
| 乗客が車の所有者になっている | 運転手にラグが発生する | Occupantの変更時に割り当て直す |
| 固定された片側の降車位置 | 車が横転すると、プレイヤーがマップの下に落ちる | 最も高い降車位置を使う(P14) |
| 降車時にモーター値を残す | 無人の車が走り続ける | 降車時にモーターを解除する(P14) |
| キーボードのみの戦闘 | スマートフォンでは攻撃できない | タッチ用のUIButtonバインディングを使う(P7) |
引き継ぎ
- scenario-roblox-architecture から受け取るもの:RoundMachine のラウンドループ、タグ付けされた武器とハザード用の Binder、DamageService のスロット。
- scenario-roblox-networking に引き渡すもの:検証するヒットボックス、飛翔体、アビリティのルール(巻き戻しを使う
HitCheck)、疑いスコア用の車の速度フラグ、Server Authority の設定。 - scenario-roblox-animation に引き渡すもの:トラックを駆動する NPC の
StateおよびAction属性とコンボの手順。Server Authority ではトラックをキャッシュしません。 - 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 にベータ版は必要ありません。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 ランナー。