偵測擊中

*此內容是使用 AI(Beta 測試版)翻譯,可能含有錯誤。若要以英文檢視此頁面,請按一下這裡

偵測擊中玩家 是一個過程,在爆炸與玩家碰撞時,減少其生命值。在高層級,您可以將此工作思考為:

  1. 一個物理模擬檢查,以確認一個拋射物是否擊中目標。
  2. 一次檢查是否要將雷射瞄準目標。

您使用的擊殺偵測類型取決於您的體驗的遊戲玩法需求。例如,物理模擬的檢查對於需要將球從手中離開特定速度、扔出空中或變更方向的撞球體驗來說是合適的。但是,即時檢查對於雷射標籤體驗來說是最佳的選擇,因為光束必須有

使用 示例雷射標籤體驗 作為參考,這個教學的第三部分教你關於3D空間中的命中偵測腳本,包括指向:

  • 從目前攝影機值和玩家的 Blaster 類輸入中獲得爆炸方向。
  • 將射線拋射在從噴射器爆炸時直接從噴射器到射線。
  • 驗證爆炸以防止使用者濫用雷射資料。
  • 減少玩家受到的爆炸傷害,並且根據各種噴射器的爆炸傷害來減少玩家的生命值。

完成此部分後,您可以探索更多開發主題來提升遊遊玩體驗,例如音訊效、照明和特效。

取得爆破方向

玩家在爆炸他們的迴射器後, ReplicatedStorage > Blaster > attemptBlastClient > 1> blastClient1> > 4> generateBlastData4> 呼叫兩個函數來啟動擊殺偵測過程:7> rayDirections()7> 和9>

生成爆炸資料

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

rayDirections 的輸入是很簡單的:現有的攝影機位置和旋轉值,以及玩家的雷射類型。如果樣本雷射標籤體驗只會給玩家雷射光束, ReplicatedStorage > LaserRay >

但是,因為樣本提供一個額外的雷射類型,它可以產生多個雷射光束,getDirectionsForBlast 必須根據其在雷射配置中的角度計算每個雷射光束的方向:

取得爆炸方向

if numLasers == 1 then
-- 對於單一雷射,它們瞄準直線
table.insert(directions, originCFrame.LookVector)
elseif numLasers > 1 then
-- 對於多個雷射,請均勻分布在水平上
-- 在中心周圍的間隔雷射SpreadDegrees
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

要進一步展示此概念,如果您包含寬涵垂直 垂直 分布的第三個噴氣式噴氣機輸入型,您可以創建一個新的噴氣屬性,例如 spreadDirection ,然後調整 CFrame 計算


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> attemptBlastClient

這些資訊對第一人稱射擊體驗非常有用,因為它讓您可以看到當爆炸與玩家或環境交叉時,它們是否位於牆上。例如,下圖所示的兩個射線正在交叉,其中一個射線正在接近牆壁,而另一個射線正在接近牆壁。對於此過程的更多資訊,請參閱

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

castLaserRay() 參數指定 Raycast() 呼叫必須考慮工作區的所有部分 除了 那個角色爆炸之外 。 腳本然後為 1>dir

Datatype.RaycastResult.Instance|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> (或 null)。

  2. 下一個,它會呼叫 isRayAngleFromOriginValid 來比較雷射擴散的預期角度與來自客戶端的角度。這個代碼中,特別顯示使用 ReplicatedStorage 來存儲資料,並且在服務器可以呼叫 getDirectionsForBlast 自己,存取資料,然後與客戶端的資料進行比

    與以前的章節的「槍枝」驗證相同,isRayAngleFromOriginValid 需要寬差值來確定角度中的「過度」差異:

    isRayAngleFromOrigin

    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 有一些理論可以保持玩家健康在或以上零。 後檢查玩家健康是否為零,它會比較健康到 damagePerHit 並使用��

這種方法來解決問題可能看起來有點複雜。例如,為什麼不將玩家的生命值設置為零,如果它是負的? 理由是因為設置生命值值會導致力場的力量。使用 Humanoid:TakeDamage() 方法可以確保玩家在力場啟用時不會受到傷害。

在PlayerTagged

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
-- 讓玩家Blasted a point for tagging playerTagged
Scoring.incrementScore(playerBlasted, 1)
end
end
end

下一步是增加排行榜。這可能看起來不是LaserBlastHandler 包含爆炸資料旁邊的玩家,但沒有這些資訊,體驗無法給予玩家標籤。最後,標籤的玩家重生回到回合中,你可以在生成和重生檢查到。

這個教程包括五個章節,詳細討論體驗的核心遊戲流程,但還有很多區域可以探索,例如:

  • 爆破視覺效果 : 請參閱 ReplicatedStorage > FirstPersonBlasterVisuals 和 0> ServerScriptService0> > 3> ThirdPersonBlasterVisuals 3> 。
  • 音訊 : 請參閱 ReplicatedStorage > SoundHandler
  • 自訂模式 : 您如何可以修改此體驗,以介紹新的類型的目標,例如在時間結束前得到最多分數?

對於雷射標籤體驗的擴展遊戲規則,以及可重用的高品質環境資產,請查看 雷射標籖 樣板。