Mendeteksi Hit

*Konten ini diterjemahkan menggunakan AI (Beta) dan mungkin mengandung kesalahan. Untuk melihat halaman ini dalam bahasa Inggris, klik di sini.

Mendeteksi kepemukulan adalah proses mengidentifikasi ketika ledakan bertabrakan dengan pemain, lalu mengurangi kesehatan mereka sesuai. Pada tingkat tinggi, Anda dapat berpikir tentang pekerjaan ini sebagai berikut:

  1. Periksa fisik yang simulator untuk melihat apakah sebuah proyektil menghantam target.
  2. Pemeriksaan instan apakah blaster dituju pada target.

Jenis deteksi kehancuran yang Anda gunakan tergantung pada persyaratan permainanplay Anda. Misalnya, memeriksa fisik yang simulasi adalah cocok untuk pengalaman dodgeball di mana bola perlu meninggalkan tangan pada kecepatan tertentu, menjatuh sebagai mereka bergerak melalui udara, atau mengubah arah dari kondisi cuaca. Namun, memeriksa check instan unt

Menggunakan ulasan pengalaman laser sebagai referensi, bagian ini dari tutorial menunjukkan tentang skrip di balik deteksi hit di ruang 3D, termasuk panduan tentang:

  • Mendapatkan arah ledakan dari nilai kamera saat ini dan ketikblaster pemain.
  • Mengirim sinar dalam jalan lurus dari blaster saat itu meledak.
  • Mengaktifkan ledakan untuk mencegah ekploitasi data blaster.
  • Mengurangi kesehatan pemain sesuai kerusakan ledakan dari setiap jenis blaster dan berapa banyak sinar yang memukul pemain.

Setelah Anda menyelesaikan bagian ini, Anda dapat menjelajahi topik pengembangan tambahan untuk meningkatkan gameplayAnda, seperti audio, lampu, dan efek khusus.

Dapatkan Arah Ledakan

Setelah seorang pemain menyalakan pistol mereka, ReplicatedStorage > Blaster > attemptBlastClient > 1> blastClient 1> > 4> generateBlastData4> memanggil dua fungsi untuk memulai proses deteksi hit: 7> rayDirections()7> dan 0> rayResults()

menghasilkan data ledakan

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

Input untuk rayDirections adalah mudah: posisi kamera saat ini dan nilai rotasi, dan ketikblaster pemain. Jika pengalaman laser tag sampel hanya memberikan pemain blaster yang menghasilkan satu sinaran laser, ReplicatedStorage > LaserRay >

Namun, karena sampel menyediakan jenis blaster tambahan yang menghasilkan beberapa sinaran laser dengan rentang horizontal yang lebar, getDirectionsForBlast harus menghitung arah untuk setiap sinaran laser dari rentang dalam konfigurasi blaster:

mendapatkanArahUntukBlast

if numLasers == 1 then
-- Untuk laser tunggal, mereka bertujuan lurus
table.insert(directions, originCFrame.LookVector)
elseif numLasers > 1 then
-- Untuk beberapa laser, distribusikan mereka secara merata secara horisontal
-- lebih dari rentang laserSpreadDegrees di sekitar pusat
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

Untuk menunjukkan konsep ini lebih lanjut, jika Anda meng包括 ketiga jenis blaster dengan spread yang lebar, vertikal , Anda dapat menciptakan属性 blaster baru, seperti spreadDirection , kemudian menyesuaikan kalkulasi CFrame untuk


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

Pada akhirnya, fungsi rayDirections() mengembalikan tabel Vectors yang mewakili arah setiap sinar laser. Jika itu membantu, Anda dapat menambahkan beberapa logging untuk mendapatkan gambaran tentang apa data ini terlihat seperti.

menghasilkan data ledakan

local rayDirections = getDirectionsForBlast(currentCamera.CFrame, blasterConfig)
for _, direction in rayDirections do -- baris baru
print(direction) -- baris baru
end -- baris baru
local rayResults = castLaserRay(localPlayer, currentCamera.CFrame.Position, rayDirections)

Mengirim Rentetan

castLaserRay() , fungsi kedua dalam ReplicatedStorage > Blaster > 0> mencoba

Informasi ini sangat berguna untuk pengalaman penembak orang pertama karena memungkinkan Anda untuk melihat kapan dan di mana ledakan bertabrakan dengan pemain atau lingkungan. Misalnya, gambar berikut menunjukkan dua sinar yang saling bertabrakan. Menurut poin asal dan arahnya, Ray A melewatkan dinding dan melanjutkan sampai m

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

Para castLaserRay() parameter meng指示 Raycast() panggilan harus mempertimbangkan setiap bagian dalam ruang kerja except karakter yang meledak. Skrip kemudian menghasilkan ray untuk setiap arah dalam tabel 2>dir2> . Jika ray menghantam sesuatu, itu menghasil

Nilai Instance adalah yang paling kritis dari kepemilikan ini untuk gameplay laser tag sampel karena berkomunikasi ketika sinar bertabrakan dengan pem

castLaserRay() 然後使用 PositionNormal 来创建一个新的 0> Datatype.

castLaserRay

if result then
-- Ledakan menghantam sesuatu, periksa apakah itu seorang pemain.
destination = CFrame.lookAt(result.Position, result.Position + result.Normal)
taggedPlayer = getPlayerFromDescendant(result.Instance)
else
-- Ledakan tidak menghantam apa pun, jadi tujuan utamanya adalah
-- titik pada jarak maksimumnya.
local distantPosition = origin + rayDirection * MAX_DISTANCE
destination = CFrame.lookAt(distantPosition, distantPosition - rayDirection)
taggedPlayer = nil
end

Validasi ledakan

Untuk mencegah kecurangan, bab sebelumnya Mengaktifkan Blaster menjelaskan cara blastClient memberi tahu server tentang ledakan menggunakan

  1. Pertama, getValidatedRayResults memanggil validateRayResult untuk memeriksa bahwa setiap entri dalam tabel rayResults dari klien adalah 1> Datatype.CFrame1> dan 4> Player4> (atau nol).

  2. Selanjutnya, itu memanggil isRayAngleFromOriginValid untuk membandingkan sudut-sudut laser yang diharapkan dari laser spread ke klien. Kode ini khusus menunjukkan keuntungan menggunakan ReplicatedStorage karena server dapat memanggil getDirectionsForBlast sendiri, menyimpan kemb

    Sama seperti validasi blaster dari bab sebelumnya, isRayAngleFromOriginValid bergantung pada nilai toleransi untuk menentukan apa yang merupakan perbedaan "berlebihan" dalam sudut:

    Apakah isRayAngleFromOriginValid

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

    Roblox menghilangkan bit yang paling terlibat dalam matematika, jadi hasilnya adalah fungsi pembantu yang singkat dan dapat diulang berkali-kali dengan kemampuan berlaku di berbagai pengalaman:

    mendapatkanAngleBetweenDirections

    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. Pemeriksaan berikutnya adalah yang paling intuitif. Di mana getValidatedBlastData menggunakan DISTANCE_SANITY_CHECK_TOLERANCE_STUDS untuk memverifikasi bahwa pemain yang meledak berada dekat dengan titik asal sinar, isPlayerNearPosition menggunakan logika identik

    apakahPlayerNearPosition

    local distanceFromCharacterToPosition = position - character:GetPivot().Position
    if distanceFromCharacterToPosition.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS then
    return false
    end
  4. Pemeriksaan terakhir isRayPathObstructed menggunakan variasi operasi sinar untuk memeriksa apakah tujuan sinar berada di belakang dinding atau hambatan lain dari posisi pengguna. Misalnya, jika pemain jahat secara sistematis menghapus semua dinding dari pengalaman untuk menandai pemain lain, server akan memeriksa dan mengonfirmasi bahwa sin

    Apakah RayPath Obscured

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

Tidak ada strategi anti-exploit yang lengkap, tetapi penting untuk mempertimbangkan cara para pemain malicious mendekati pengalaman Anda sehingga Anda dapat menempatkan periksa yang dapat dilakukan server untuk menangkap perilaku curang.

Kurangi Kesehatan Pemain

Setelah mengevaluasi bahwa seorang pemain menyebutkan pemain lain, langkah-langkah terakhir dalam menyelesaikan utas permainan utama dalam pengalaman samurai laser adalah mengurangi kesehatan pemain yang ditag, meningkatkan papan peringkat, dan menempatkan pemain kembali ke putaran.

Memulai dengan mengurangi kesehatan pemain yang ditandai, Spawning and Respawning mencakup perbedaan antara Class.Player</

Pengalaman menyimpan nilai kerusakan dalam karakteristik damagePerHit dari seti

Health tidak menerima nilai negatif, jadi onPlayerTagged memiliki beberapa logika untuk menjaga kesehatan pemain di atas atau di atas nol. Setelah memverifikasi bahwa kesehatan pemain di atas atau di atas nol, itu mem

Cara mendekati masalah ini mungkin tampak sedikit rumit. Misalnya, mengapa tidak hanya menetapkan kesehatan pemain ke nol jika itu akan menjadi negatif? Alasannya karena menetapkan nilai kesehatan mengelakkan lapangan kekuatan. Menggunakan metode Humanoid:TakeDamage() menjamin bahwa pemain tidak mengambil kerusakan saat lapangan kekuatan mereka aktif.

padaPlayerTagged

local function onPlayerTagged(playerBlasted: Player, playerTagged: Player, damageAmount: number)
local character = playerTagged.Character
local isFriendly = playerBlasted.Team == playerTagged.Team
-- Larangan tembakan ramah
if isFriendly then
return
end
local humanoid = character and character:FindFirstChild("Humanoid")
if humanoid and humanoid.Health > 0 then
-- Hindari kesehatan negatif
local damage = math.min(damageAmount, humanoid.Health)
-- TakeDamage menjamin kesehatan tidak turun jika ForceField aktif
humanoid:TakeDamage(damage)
if humanoid.Health <= 0 then
-- Award playerBlasted sebuah poin untuk tagging pemainTagged
Scoring.incrementScore(playerBlasted, 1)
end
end
end

Langkah selanjutnya adalah meningkatkan papan peringkat. Mungkin tampak tidak perlu bagi LaserBlastHandler untuk mencakup pemain yang meledak bersama dengan data ledakan, tetapi tanpa informasi itu, pengalaman tidak dapat mengkredit pemain dengan tagging seseorang keluar. Terakhir, pemain yang tagged kembali ke round, yang dapat Anda

Lima bab dalam kurikulum ini mencakup alur permainan inti pengalaman, tetapi masih ada banyak area untuk dijelajahi, seperti:

  • Visual Blaster : Lihat ReplicatedStorage > FirstPersonBlasterVisuals dan 0> ServerScriptService 0> > 3> ThirdPersonBlasterVisuals 3> .
  • Audio : Lihat ReplicatedStorage > SoundHandler .
  • Mode Kustom. : Bagaimana Anda dapat mengubah pengalaman ini untuk memperkenalkan jenis tujuan baru, seperti menghasilkan lebih banyak poin sebelum waktu habis?

Untuk logika permainan yang diperluas untuk pengalaman laser tag, serta aset lingkungan berkualitas tinggi yang dapat diulang, tinjau Laser Tag template.