アクションゲームで、剣が確実に当たっているのにすり抜けたり、離れた場所から理不尽にダメージを受ける「ゴーストヒット」はプレイヤーの熱中を一瞬で奪います。
旧来の`BasePart.Touched`は物理演算ステップ(60Hz)に依存し、すり抜けやチートの温床となります。現在の商業タイトルでは`GetPartsInPart`やレイキャスト判定が標準です。
1. Touchedイベントが戦闘判定で破綻する理由
物理判定の遅延とセキュリティ上のリスク:
- トンネリング現象: 高速で振られた武器がフレーム間をすり抜け、当たり判定が消失。
- チートへの脆弱性: クライアント側でTouchedイベントを遠隔偽造されるリスク。
- 連続誤検出: 1振りの間に過剰なイベントが乱発されサーバー負荷が増大。
2. 空間クエリ(Spatial Query)とOverlapParams
幾何学的な交差判定を瞬時に実行するAPI群:
- GetPartsInPart: 複雑なメッシュや剣の軌跡ボリュームと重なるパーツを即座に取得。
- GetPartBoundsInBox: 爆発や衝撃波など高速な立方体・球体判定に最適。
- OverlapParams設定: 攻撃者自身を判定から除外し、無関係なパーツを無視。
3. レイキャスト判定 vs 空間クエリの使い分け
武器の種類に応じた最適な判定手法:
- レイキャストヒットボックス: 刀や槍など、刃の軌跡を点で繋ぐ精密な判定。
- 空間クエリ: ハンマーや範囲攻撃など、体積そのものが重要な打撃。
- ハイブリッド設計: クライアントで即時エフェクト、サーバーで距離と視界を検証。
4. 実践Luaスクリプト:空間クエリ近接ハンドラ
サーバー距離検証を内蔵した安全な戦闘スクリプト:
ServerScriptService.CombatManager
-- 空間クエリによる近接攻撃判定
local Workspace = game:GetService("Workspace")
特徴:攻撃者モデルの除外、多重ヒット防止、18スタッド以内の厳格な距離検証。
5. レイテンシ補正とアンチチート対策
高Ping環境でも公平な勝負を実現するポイント:
- 過去座標バッファ: 過去200msの敵座標を記録し、Ping差によるズレをサーバーで逆算。
- サーバー主導クールダウン: 攻撃インターバルをサーバー側のタイマーで厳密管理。
- 壁抜き防止レイキャスト: 障害物越しにダメージが通らないよう直視判定を併用。
よくある質問(Roblox Spatial Query)
GetPartsInPartがGetTouchingPartsより優れている理由は?
CanCollideの設定に依存せず、OverlapParamsで柔軟なフィルタリングが可能なためです。
壁越しに攻撃が当たるのを防ぐには?
攻撃者と対象の間にレイキャストを飛ばし、障害物が検出されたら攻撃を無効化します。
空間クエリはクライアントから改ざんできますか?
サーバーで実行されている限り、クライアントから改ざんすることは不可能です。