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:
- Periksa fisik yang simulator untuk melihat apakah sebuah proyektil menghantam target.
- 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 lurustable.insert(directions, originCFrame.LookVector)elseif numLasers > 1 then-- Untuk beberapa laser, distribusikan mereka secara merata secara horisontal-- lebih dari rentang laserSpreadDegrees di sekitar pusatlocal leftAngleBound = laserSpreadDegrees / 2local rightAngleBound = -leftAngleBoundlocal degreeInterval = laserSpreadDegrees / (numLasers - 1)for angle = rightAngleBound, leftAngleBound, degreeInterval dolocal direction = (originCFrame * CFrame.Angles(0, math.rad(angle), 0)).LookVectortable.insert(directions, direction)endend
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 thentable.insert(directions, originCFrame.LookVector)elseif numLasers > 1 thenlocal leftAngleBound = laserSpreadDegrees / 2local rightAngleBound = -leftAngleBoundlocal degreeInterval = laserSpreadDegrees / (numLasers - 1)for angle = rightAngleBound, leftAngleBound, degreeInterval dolocal directionif spreadDirection == "vertical" thendirection = (originCFrame * CFrame.Angles(math.rad(angle), 0, 0)).LookVectorelsedirection = (originCFrame * CFrame.Angles(0, math.rad(angle), 0)).LookVectorendtable.insert(directions, direction)endendreturn 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 baruprint(direction) -- baris baruend -- baris barulocal 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
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
- Distance – Jarak antara sumber daya dan titik persimpangan.
- Material – The Enum.Material at the intersection point.
Nilai Instance adalah yang paling kritis dari kepemilikan ini untuk gameplay laser tag sampel karena berkomunikasi ketika sinar bertabrakan dengan pem
castLaserRay() 然後使用 Position 和 Normal 来创建一个新的 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_DISTANCEdestination = CFrame.lookAt(distantPosition, distantPosition - rayDirection)taggedPlayer = nilend
Validasi ledakan
Untuk mencegah kecurangan, bab sebelumnya Mengaktifkan Blaster menjelaskan cara blastClient memberi tahu server tentang ledakan menggunakan
Pertama, getValidatedRayResults memanggil validateRayResult untuk memeriksa bahwa setiap entri dalam tabel rayResults dari klien adalah 1> Datatype.CFrame1> dan 4> Player4> (atau nol).
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 isRayAngleFromOriginValidlocal claimedDirection = (rayResult.destination.Position - originCFrame.Position).Unitlocal directionErrorDegrees = getAngleBetweenDirections(claimedDirection, expectedDirection)return directionErrorDegrees <= ToleranceValues.BLAST_ANGLE_SANITY_CHECK_TOLERANCE_DEGREESRoblox 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:
mendapatkanAngleBetweenDirectionslocal 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)endPemeriksaan 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
apakahPlayerNearPositionlocal distanceFromCharacterToPosition = position - character:GetPivot().Positionif distanceFromCharacterToPosition.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS thenreturn falseendPemeriksaan 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 Obscuredlocal 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.