ヒットを検出する

*このコンテンツは、ベータ版のAI(人工知能)を使用して翻訳されており、エラーが含まれている可能性があります。このページを英語で表示するには、 こちら をクリックしてください。

ヒットを検出する は、ブラストがプレイヤーと衝突するときにそのプレイヤーの体力を減少するプロセスです。高レベルでは、この作業を次のように考えることができます:

  1. 物理的にシミュレートされたチェックで、発射物がターゲットを打撃したかどうか。
  2. ブラスターがターゲットに狙われているかどうかを即座にチェックする。

ヒット検知の種類は、エクスペリエンスのゲームプレイ要件によります。たとえば、物理的にシミュレートされたチェックは、ボールが特定の速度で手から離れる必要がある、空を飛んでいる間にドロップする必要がある、または天気条件により方向を変更する必要があるなど、ラザータグエクスペ

参照として使用する サンプルレーザータグエクスペリエンス は、3D 空間のヒット検知のスクリプトを含む、スクリプトの裏にあるスクリプトを教えてください。このセクションのチュートリアルでは、次のコンセプトについて説明しています:

  • 現在のカメラ値とプレイヤーのブラスタータイプから爆発入力向を取得します。
  • ブラスターから飛び出すと、直線的なパスでビームをキャストする。
  • 爆発を検証して、ブラスターデータの悪用を防止します。
  • 各種ブラスターの爆発ダメージに基づいて、プレイヤーの体力を減少させる。

このセクションを完了した後、オーディオ、照明、特殊エフェクトなど、ゲームプレイを向上させる追加の開発トピックを探索できます。

爆発方向を取得

プレイヤーがブラスターを爆破した後、 ReplicatedStorage > ブラスター > 試作BlastClient > 1>blastClient1> > 4>生成BlastData4> コールを 2 つ を開始します:7> rayDirections()7> と9> rayResults

爆発データを生成する

local rayDirections = getDirectionsForBlast(currentCamera.CFrame, blasterConfig)
local rayResults = castLaserRay(localPlayer, currentCamera.CFrame.Position, rayDirections)

入力は、rayDirections の 3つの入力項目です: 現在のカメラポジションと回転値、およびプレイヤーのブラスタータイプ。サンプルレーザータグエクスペリエンスが、単一のレーザービームを生

しかし、サンプルはワイド、横長のスプレッドで複数のレーザービームを生成する追加のブラスタータイプを提供するため、getDirectionsForBlast は、スプレッドの角度に基づいて、ブラスターのビームの各ビームの方向を計算する必要があります:

爆発のための方向を取得

if numLasers == 1 then
-- シングルレーザーの場合、直ぐに照準します
table.insert(directions, originCFrame.LookVector)
elseif numLasers > 1 then
-- 複数のレーザーの場合、それらを横に均等に広げる
-- 中央周辺のレーザースプレッド度
local leftAngleBound = laserSpreadDegrees / 2
local rightAngleBound = -leftAngleBound
local degreeInterval = laserSpreadDegrees / (numLasers - 1)
for angle = rightAngleBound, leftAngleBound, degreeInterval do
local direction = (originCFrame * CFrame.Angles(0, math.rad(angle), 0)).LookVector
table.insert(directions, direction)
end
end

このコンセプトをさらに説明するには、幅の広い、 垂直スプレッド のある 3つ目のブラスタータイプを含めると、新しいブラスターアトリビュート、例えば spreadDirection を作成できます。次のスクリプ入力の下の


if numLasers == 1 then
table.insert(directions, originCFrame.LookVector)
elseif numLasers > 1 then
local leftAngleBound = laserSpreadDegrees / 2
local rightAngleBound = -leftAngleBound
local degreeInterval = laserSpreadDegrees / (numLasers - 1)
for angle = rightAngleBound, leftAngleBound, degreeInterval do
local direction
if spreadDirection == "vertical" then
direction = (originCFrame * CFrame.Angles(math.rad(angle), 0, 0)).LookVector
else
direction = (originCFrame * CFrame.Angles(0, math.rad(angle), 0)).LookVector
end
table.insert(directions, direction)
end
end
return directions

最終的に、rayDirections() 機能は、各レーザービームの方向を表す Vectors テーブルを返します。如果有用である場合は、このデータの外観を把握するためにいくつかのログを追加できます。

爆発データを生成する

local rayDirections = getDirectionsForBlast(currentCamera.CFrame, blasterConfig)
for _, direction in rayDirections do -- 新しい行
print(direction) -- 新しい行
end -- 新しい行
local rayResults = castLaserRay(localPlayer, currentCamera.CFrame.Position, rayDirections)

レイをキャスト

castLaserRay()ReplicatedStorage > Blaster > 0>attemptBlastClient0> >

この情報は、特に FPS エクスペリエンスの場合、ブラストがプレイヤーや環境と交差する時間と場所を見ることができるため、特に便利です。たとえば、次の画像では、2つのレイが互いに平行してキャストされていることが示されています。それぞれの起源と方向により、

A diagram where Ray A continues through the wall, and Ray B collides with the wall.

castLaserRay() パラメータは、Raycast() コールがワークスペースのすべての部分を考慮する必要があることを指定します Cast キャラクターが爆発した場合を除きます。スクリプトは、1> dir

これらのプロパティのうち、Instance 値は、サンプルレーザータグエクスペリエンスのゲームプレイで最も重要な値です、因為レイが

castLaserRay() 然後、PositionNormal を使用して、新しい 0>

castLaserRay

if result then
-- 爆発が何かに当たったかどうか、プレイヤーであるかどうかをチェックします。
destination = CFrame.lookAt(result.Position, result.Position + result.Normal)
taggedPlayer = getPlayerFromDescendant(result.Instance)
else
-- 爆発は何もヒットしなかったので、その目的地は
-- 最大距離でのポイント。
local distantPosition = origin + rayDirection * MAX_DISTANCE
destination = CFrame.lookAt(distantPosition, distantPosition - rayDirection)
taggedPlayer = nil
end

爆発を有効にする

チェートを防止するために、前の章 ブラスターの実装 は、blastClient がサーバーに爆発を通知する方法を説明し

  1. まず、getValidatedRayResults は、validateRayResult を呼び出して、クライアントの rayResults テーブルの各エントリが 1> Datatype.CFrame1> および 4> Player4> (またはなし) であるかどうかをチェックします。

  2. 次に、 isRayAngleFromOriginValid を呼び出して、レーザーの拡散の予想される角度とクライアントの角度を比較します。このコードは、特に ReplicatedStorage を使用することの利点を示しています、サーバーが getDirectionsForBlast を自体に呼

    前の章のブラスターの有効性の有効性と同じように、isRayAngleFromOriginValid は、角の "過剰な" 差を構成するものを決定するためにトレールオフィングを使用します:

    isRayAngleFromOriginValid

    local claimedDirection = (rayResult.destination.Position - originCFrame.Position).Unit
    local directionErrorDegrees = getAngleBetweenDirections(claimedDirection, expectedDirection)
    return directionErrorDegrees <= ToleranceValues.BLAST_ANGLE_SANITY_CHECK_TOLERANCE_DEGREES

    Roblox は、数学に関与する最も深いビットを抽象化するため、結果は、あらゆるエクスペリエンスで使用可能な短くて再利用可能なヘルパー関数です:

    角度の間の距離を取得

    local function getAngleBetweenDirections(directionA: Vector3, directionB: Vector3)
    local dotProduct = directionA:Dot(directionB)
    local cosAngle = math.clamp(dotProduct, -1, 1)
    local angle = math.acos(cosAngle)
    return math.deg(angle)
    end
  3. 次のチェックは最も直感的です。 getValidatedBlastData は、DISTANCE_SANITY_CHECK_TOLERANCE_STUDS を使用して、プレイヤーがビームの起源点に近いかどうかを確認します。isPlayerNearPosition は、タグ付きのプレイヤーがビームの目的地に近

    isPlayerNearPosition

    local distanceFromCharacterToPosition = position - character:GetPivot().Position
    if distanceFromCharacterToPosition.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS then
    return false
    end
  4. 最終チェック isRayPathObstructed は、レイキャストオペレーションのバリエーションを使用して、レイの目的地がクライアントの位置の壁やその他の障害から背後にあるかどうかをチェックします。たとえ、悪意のあるプレイヤーがエクスペリエンスからすべての壁を削除してタ

    isRayPathObstructed

    local scaledDirection = (rayResult.destination.Position - blastData.originCFrame.Position)
    scaledDirection *= (scaledDirection.Magnitude - 1) / scaledDirection.Magnitude

反悪用戦略は包括的ではありませんが、悪意のあるプレイヤーがエクスペリエンスに近づいている方法を考慮して、サーバーが疑わしい動作を検出できるようにチェックを設置することが重要です。

プレイヤーの体力を減少

プレイヤーが別のプレイヤーにタグを付けたことを確認した後、サンプルレーザータグエクスペリエンスのメインゲームプレイループを完了するための最終ステップは、タグ付きのプレイヤーの健康を減少、リーダーボードをインクリメントし、プレイヤーをラウンドにリスポーンすることです。

タグ付きのプレイヤーの健康を減少することで、スポーンと再スポーンは、Player と <

エクスペリエンスは、各ブラスターの damagePerHit 属性にダメージ

Health は、ネガティブな値を受け入れませんので、 onPlayerTagged には、プレイヤーの健康を 0 以上に保つためのロジックがあります。プレイヤーの健康が 0 以上であることを

この方法で問題にアプローチすると、少し混乱しているように思えるかもしれません。たとえば、Humanoid:TakeDamage() メソッドを使用して、プレイヤーの体力を0に設定しないでください。理由は、体力値を変更すると、フォースフィールドが有効になります。 Errors: Error:

プレイヤータグ付き

local function onPlayerTagged(playerBlasted: Player, playerTagged: Player, damageAmount: number)
local character = playerTagged.Character
local isFriendly = playerBlasted.Team == playerTagged.Team
-- 友好的な発射を禁止する
if isFriendly then
return
end
local humanoid = character and character:FindFirstChild("Humanoid")
if humanoid and humanoid.Health > 0 then
-- ネガティブな健康を避ける
local damage = math.min(damageAmount, humanoid.Health)
-- TakeDamage は、ForceField がアクティブな場合、健康が損なわれないようにします
humanoid:TakeDamage(damage)
if humanoid.Health <= 0 then
-- PlayerBlasted タグ付けしたプレイヤーにポイントを賞与
Scoring.incrementScore(playerBlasted, 1)
end
end
end

次のステップは、リーダーボードをインクリメントすることです。これは、LaserBlastHandler が爆発データの隣に爆発したプレイヤーを含むことを意図しています。この情報なしで、エクスペリエンスはタグを付けることができません。最後に、タグを付けたプレイヤーは、

この教科書の 5 章は、エクスペリエンスのコアゲームプレイループをカバーしますが、まだ探検するエリアがたくさんあります、例えば:

  • ブラスタービジュアルズ : は、 ReplicatedStorage > FirstPersonBlasterVisuals > および 0> ServerScriptService0> > 3> ThirdPersonBlasterVisuals 3> を参照してください。
  • オーディオ : は、 ReplicatedStorage > SoundHandler を参照してください。
  • カスタムモード : どうすれば、このエクスペリエンスを変更して、時間切れになる前に最も多くのポイントを獲得できるなど、新しいタイプの目標を紹介できますか?

レーザータグエクスペリエンスの拡張されたゲームロジック、および再利用可能で高品質の環境アセットのために、レーザータグ テンプレートをレビューしてください。