Phát hiện đòn đánh

*Nội dung này được dịch bằng AI (Beta) và có thể có lỗi. Để xem trang này bằng tiếng Anh, hãy nhấp vào đây.

Phát hiện cú đập với người chơi là quá trình xác định khi nào cú đập va chạm với người chơi, sau đó giảm sức khỏe của họ. Ở cấp độ cao, bạn có thể nghĩ về công việc này như một trong những:

  1. Một cuộc kiểm tra vật lý để xem liệu một đạn đạn đã đâm vào mục tiêu.
  2. Một cuộc kiểm tra tức thời xem liệu súng ngắn có đang chỉ vào mục tiêu không.

Loại phát hiện đòn đánh bạn sử dụng phụ thuộc vào yêu cầu gameplay của trải nghiệm của bạn. Ví dụ, một cuộc kiểm tra đòn đánh thể lý tích hợp là phù hợp cho một trải nghiệm né banh nơi bóng cần phải rời khỏi

Sử dụng trang kinh nghiệm laser mẫu như một tham khảo, bài này của hướng dẫn cho bạn về những kịch bản sau phát hiện đòn đánh trong không gian 3D, bao gồm hướng dẫn về các kịch bản sau:

  • Nhận hướng nổ từ giá trị hiện tại của camera và đánh máyngười chơi.
  • Làm cho các tia phóng xa trong một con đường thẳng từ blaster khi nó phóng xa.
  • Xác minh nổ để ngăn chặn sử dụng dữ liệu người lớn.
  • Giảm sức khỏe của người chơi theo sát thương rơi từ mỗi loại bom và số lần bị ảnh hưởng bởi các tia.

Sau khi hoàn thành phần này, bạn có thể khám phá các chủ đề phát triển bổ sung để tăng trưởng trải nghiệm trò chơicủa bạn, ví dụ như âm thanh, chiếu sáng và hiệu ứng đặc biệt.

Nhận Hướng Nổ

Sau khi một người chơi phóng ra khẩu súng của họ, ReplicatedStorage > Blaster > attemptBlastClient > 1> blastClient1> > 4> generateBlastData4> gọi hai chức năng để bắt đầu quá trình phát hiệ

tạo raBlastData

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

Các lựa chọn cho rayDirections là rất đơn giản: vị trí và giá trị quay của máy ảnh hiện tại, và đánh máyblaster của người chơi. Nếu trải nghiệm laser tag mẫu

Tuy nhiên, vì mẫu cung cấp một loại blaster bổ sung tạo ra một loạt các tia laser với chiều rộng, phạm vi dọc rộng, getDirectionsForBlast phải tính hướng cho mỗi tia laser trong khu vực phân phối theo góc trong cấu hình blaster của họ:

nhậnDirectionsForBlast

if numLasers == 1 then
-- Đối với các laser đơn, chúng nhắm thẳng
table.insert(directions, originCFrame.LookVector)
elseif numLasers > 1 then
-- Đối với nhiều laser, phân bố chúng theo cùng một kích thước ngang
-- trên một độ lượng laserSpreadDegrees xung quanh trung tâm
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

Để minh họa khái niệm này tiếp theo, nếu bạn bao gồm một loại blaster thứ ba với một chiếc rộng, 垂直 spread, bạn có thể tạo một đặc tính blaster mới, chẳng hạn như 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

Cuối cùng, chức năng rayDirections() trả lại một bảng Vectors đại diện cho hướng của mỗi tia laser. Nếu hữu ích, bạn có thể thêm một số thông tin để có được cảm giác về những gì dữ liệu này trông giống như.

tạo raBlastData

local rayDirections = getDirectionsForBlast(currentCamera.CFrame, blasterConfig)
for _, direction in rayDirections do -- đường mới
print(direction) -- đường mới
end -- đường mới
local rayResults = castLaserRay(localPlayer, currentCamera.CFrame.Position, rayDirections)

Sử dụng tia

castLaserRay() , hành động thứ hai trong ReplicatedStorage > Blaster > <

Hình ảnh này có í nghĩa đặc biệt cho các trải nghiệm người chơi thứ nhất vì nó cho phép bạn xem khi và nơi nào các vụ nổ phản xạ với người chơi hoặc môi trường. Ví dụ, hình ảnh sau đây cho thấy hai tia

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

Các castLaserRay()參數指定 Raycast() 呼叫必須考慮 Ray 的每個部分 trongWorkspace 1>ngoại trừ1> nhân vật đã nổ tung. Kết thúc script then casts một ray for each direction in the 4>định hướng4> table

Giá trị Instance value là thứ quan trọng nhất trong những thuộc tính này cho trò chơi game thủ laser tag vì nó truyền t

castLaserRay() Sau đó sử dụng PositionNormal để tạo một

castLaserRay

if result then
-- Cái nổ đã đánh vào một cái gì đó, hãy kiểm tra nó là một người chơi.
destination = CFrame.lookAt(result.Position, result.Position + result.Normal)
taggedPlayer = getPlayerFromDescendant(result.Instance)
else
-- Cuộc nổ không đánh vào bất cứ thứ gì, vì vậy nó đến đích là
-- điểm ở khoảng cách tối đa của nó.
local distantPosition = origin + rayDirection * MAX_DISTANCE
destination = CFrame.lookAt(distantPosition, distantPosition - rayDirection)
taggedPlayer = nil
end

Xác minh Blast

Để ngăn chặn gian lận, chương trình trước tiên implement Blasters giải thích cách blastClient thông bá

  1. Đầu tiên, getValidatedRayResults gọi validateRayResult để kiểm tra rằng mỗi hàng trong bảng rayResults từ khách hàng là một 1> Datatype.CFrame1> và một 4> Player4> (hoặc nil).

  2. Tiếp theo, nó gọi isRayAngleFromOriginValid để so sánh các góc độ dự kiến của laser với những góc độ dự kiến của máy chủ. Mã này đặc biệt hiển thị lợi thế của việc sử dụng ReplicatedStorage bởi vì má

    Giống như sự xác nhận của blaster từ chương trước, isRayAngleFromOriginValid dựa trên một giá trị dung dịch để xác định những gì thuộc về một sự khác biệt "quá mức" trong các góc:

    isRayAngleFromOrigin

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

    Roblox tách các thành phần liên quan nhất của toán học, vì vậy kết quả là một hàm trợ giúp ngắn, có thể tái sử dụng cao với khả năng áp dụng trên một loạt các trải nghiệm:

    nhậnAngleBetweenDirections

    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. Cuộc kiểm tra tiếp theo là thuận tiện nhất. Trong khi getValidatedBlastData sử dụng DISTANCE_SANITY_CHECK_TOLERANCE_STUDS để xác minh rằng người chơi đã nổ tung gần với điểm chính của hà

    isPlayerNearPosition

    local distanceFromCharacterToPosition = position - character:GetPivot().Position
    if distanceFromCharacterToPosition.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS then
    return false
    end
  4. Cuộc kiểm tra cuối cùng isRayPathObstructed sử dụng một biến thể của hoạt động phản xạ để kiểm tra xem mục tiêu của ray có đang ở phía sau một bức tường hoặc một vật cản khác từ vị trí của môi trườnghàng. Ví dụ, nếu

    isRayPathBị Cản Trở

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

Không có chiến lược chống lừa đảo toàn diện, nhưng quan trọng là xem xét cách các người chơi malicious tiếp cận trải nghiệm của bạn để bạn có thể đặt các lớp kiểm tra để máy chủ có thể chạy để phát hiện hành vi nghi vấn.

Giảm Sức Khỏe Người Chơi

Sau khi xác minh một người chơi đã gắn nhãn một người chơi khác, các bước cuối cùng trong việc hoàn thành chuỗi gameplay chính trong trải nghiệm người chơi laser là giảm sức khỏe người chơi, tăng bảng xếp hạng và tái sinh người chơi vào vòng.

Bắt đầu với việc giảm sức khỏe của người chơi được gắn nhãn, Spawning and Res

Các trải nghiệm lưu giữ giá trị sát thương trong

Health không chấp nhận giá trị âm, vì vậy onPlayerTagged có một số logic để giữ sức khỏe người chơi ở mức hoặc trên mức 0. Sau khi xác nhậ

Cách tiếp cận này có vẻ như một chút rắc rối. Ví dụ, tại sao không chỉ đặt sức khỏe người chơi thành 0 nếu nó là âm? Lý do là vì đặt giá trị sức khỏe làm tròn vòng tránh trường lực. Sử dụng phương thức Class.Humanoid:TakeDamage()

trênPlayerTagged

local function onPlayerTagged(playerBlasted: Player, playerTagged: Player, damageAmount: number)
local character = playerTagged.Character
local isFriendly = playerBlasted.Team == playerTagged.Team
-- Tắt khản ngục bắn thân thiện
if isFriendly then
return
end
local humanoid = character and character:FindFirstChild("Humanoid")
if humanoid and humanoid.Health > 0 then
-- Tránh sức khỏe tiêu cực
local damage = math.min(damageAmount, humanoid.Health)
-- TakeDamage đảm bảo sức khỏe không bị giảm nếu ForceField đang hoạt động
humanoid:TakeDamage(damage)
if humanoid.Health <= 0 then
-- Ghi điểm cho người chơiBị nổi bật một điểm cho việc gắn nhãn người chơi
Scoring.incrementScore(playerBlasted, 1)
end
end
end

Bước tiếp theo là tăng bảng xếp hạng. Nó có thể đã không cần thiết đối với LaserBlastHandler để bao gồm người chơi đã phát nổ khi đi kèm với dữ liệu nổ tung, nhưng mà không có thông tin đó, trải nghiệ

Năm chương trong chương trình này bao gồm các vòng lặp trò chơi chính của kinh nghiệm, nhưng vẫn còn rất nhiều khu vực để khám phá, chẳng hạn như:

  • Hình ảnh Blaster : Xem ReplicatedStorage > FirstPersonBlasterVisuals và 0> ServerScriptService0> > 3> ThirdPersonBlasterVisuals 3> .
  • âm thanh : Xem ReplicatedStorage > SoundHandler .
  • Chế độ tùy chỉnh : Làm thế nào bạn có thể chỉnh sửa trải nghiệm này để giới thiệu các loại mục tiêu mới, chẳng hạn như đánh giá nhiều điểm nhất trước khi hết thời gian?

Đối với gameplay logic cho trải nghiệm laser tag, cũng như các tài nguyên môi trường có thể tái sử dụng và chất lượng cao, hãy xem mẫu Laser Tag.