Mengimplementasikan perilaku blaster

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

Mengimplementasikan perilaku blaster adalah proses pemrograman mekanik ledakan dalam permainan tembak-menembak orang pertama. Sementara pemain dapat meledakkan dengan satu klik atau tekan tombol, menciptakan perilaku ledakan yang memuaskan dan akurat sangat penting karena meningkatkan kesenangan pemain terhadap keseluruhan permainan.

Menggunakan permainan laser tag contoh sebagai referensi, bagian tutorial ini mengajarkan Anda tentang skrip di balik implementasi perilaku blaster untuk dua jenis blaster yang berbeda, termasuk panduan tentang:

  • Mendeteksi kapan pemain menekan tombol ledakan.
  • Memeriksa apakah pemain dapat menggunakan blaster mereka jika mereka baru saja menekan tombol ledakan.
  • Menghasilkan data ledakan yang memberi tahu server siapa yang memulai ledakan, dari mana asalnya, dan apa tujuan akhir dari setiap sinar laser.
  • Memberitahu server tentang data ledakan sehingga dapat melakukan tindakan yang sesuai jika ledakan bertabrakan dengan pemain lain.
  • Mengatur ulang blaster di antara setiap ledakan untuk memberi blaster cukup waktu untuk mendingin sebelum dapat meledak lagi.

Setelah Anda menyelesaikan bagian ini, Anda akan belajar tentang skrip yang memungkinkan blaster mendeteksi ketika ledakannya bertabrakan dengan pemain lain, kemudian mengurangi jumlah kesehatan yang sesuai sesuai dengan setiap jenis blaster.

Mendeteksi input pemain

Langkah pertama untuk mengimplementasikan perilaku blaster adalah mendengarkan ketika seorang pemain menekan tombol ledakan. Jenis input yang digunakan pemain untuk menekan tombol ledakan tergantung pada perangkat yang mereka gunakan untuk mengakses permainan. Misalnya, permainan laser tag contoh mendukung kontrol mouse dan keyboard, gamepad, dan kontrol sentuh. Anda dapat melihat masing-masing jenis input ini di ReplicatedStorageUserInputHandler.

Skrip klien ini menggunakan ContextActionService untuk mengikat MouseButton1 dan ButtonR2 ke aksi ledakan. Ini berarti bahwa setiap kali seorang pemain menekan tombol mouse kiri atau tombol R2 pada gamepad, itu memicu sinar laser untuk meledak keluar dari blaster. Perhatikan bahwa HUDGui berisi tombol untuk meledak di perangkat seluler, yang akan dihubungkan nanti dalam skrip.

UserInputHandler
ContextActionService:BindAction("_", onBlasterActivated, false,
Enum.UserInputType.MouseButton1,
Enum.KeyCode.ButtonR2
)

Catatan penting lainnya adalah penggunaan Enum.UserInputState.Begin dalam definisi onBlasterActivated(). Banyak interaksi antarmuka pengguna, seperti memilih blaster dalam contoh ini, tidak terjadi sampai setelah tombol mouse dilepaskan (Enum.UserInputState.End), yang memberi pengguna kesempatan terakhir untuk menghindari interaksi. Namun, mekanik ledakan tidak terasa responsif kecuali terjadi seketika tombol ditekan.

Untuk mendemonstrasikan, Anda dapat mengubah Enum.UserInputState.Begin menjadi Enum.UserInputState.End, lalu melakukan pengujian untuk melihat bagaimana responsivitas ledakan mempengaruhi permainan. Misalnya, jika pemain dapat menahan tombol tanpa memicu ledakan, bagaimana hal itu dapat mengubah pengalaman mereka saat menandai pemain lain?

UserInputHandler
local function onBlasterActivated(_actionName: string,
inputState: Enum.UserInputState, _inputObject: InputObject)
if inputState == Enum.UserInputState.End then -- baris yang diperbarui, pastikan untuk mengubah kembali
attemptBlastClient()
end
end

Periksa apakah pemain dapat meledak

Setelah UserInputHandler mendeteksi penekanan tombol atau ketukan layar, ia memanggil ReplicatedStorageBlasterattemptBlastClient untuk memeriksa apakah pemain dapat meledak atau tidak. Seperti kebanyakan pemeriksaan dalam permainan laser tag contoh, ini terjadi dua kali: pertama di klien, kemudian di server. attemptBlastClient kemudian memanggil ReplicatedStorageBlastercanLocalPlayerBlast untuk melakukan pemeriksaan sederhana terhadap atribut pemain blasterStateClient:

canLocalPlayerBlast
local function canLocalPlayerBlast(): boolean
return localPlayer:GetAttribute(PlayerAttribute.blasterStateClient) == BlasterState.Ready
end

Jika Anda memeriksa ReplicatedStorageBlasterBlasterState, Anda dapat melihat bahwa permainan memiliki tiga status blaster: Ready, Blasting, dan Disabled. Untuk melihat efek dari masing-masing status ini, Anda dapat melakukan pengujian permainan, memilih pemain Anda di bawah layanan Players, lalu mengamati atribut blasterStateClient di jendela Properties. Perhatikan bagaimana ia menampilkan Disabled saat Anda memilih blaster Anda, Ready sebagian besar waktu, dan Blasting selama kurang dari satu detik setelah Anda menekan tombol.

Penundaan kecil ini mencegah Anda meledak secepat Anda dapat mengklik. Misalnya, jika Anda mengubah fungsi untuk selalu mengembalikan true, Anda dapat dengan cepat meledakkan blaster Anda tanpa penundaan, yang tidak realistis untuk permainan laser tag.

canLocalPlayerBlast
local function canLocalPlayerBlast(): boolean
return true -- baris yang diperbarui, pastikan untuk mengubah kembali
end

Menghasilkan data ledakan

Setelah memverifikasi bahwa blaster pemain berada dalam status Ready, attemptBlastClient memanggil ReplicatedStorageattemptBlastClientblastClient. Langkah pertama yang diambil oleh blastClient adalah mengatur atribut pemain blasterStateClient ke Blasting, yang menghindari kasus tembakan cepat yang sama dari sebelumnya.

Langkah selanjutnya adalah menghasilkan data ledakan. Jika Anda meninjau ReplicatedStorageBlasterBlastData, Anda dapat melihat bahwa setiap ledakan terdiri dari tiga informasi:

  • Pemain yang memulai ledakan.
  • Sebuah DataType.CFrame yang mewakili titik asal ledakan.
  • Sebuah tabel RayResult yang berisi tujuan akhir dari setiap sinar laser dan pemain yang terkena, jika mengenai pemain lain.

Untuk menghasilkan data ini, blastClient memanggil ReplicatedStorageattemptBlastClientblastClientgenerateBlastData, yang dapat Anda tinjau di bawah ini.

generateBlastData
local function generateBlastData(): BlastData.Type
local blasterConfig = getBlasterConfig()
local rayDirections = getDirectionsForBlast(
currentCamera.CFrame, blasterConfig)
local rayResults = castLaserRay(
localPlayer, currentCamera.CFrame.Position, rayDirections)
local blastData: BlastData.Type = {
player = localPlayer,
originCFrame = currentCamera.CFrame,
rayResults = rayResults,
}
return blastData
end

Fungsi ini dimulai dengan menggunakan getBlasterConfig untuk mengambil jenis blaster pemain. Contoh ini menyediakan dua jenis blaster: satu yang menghasilkan beberapa sinar dengan penyebaran horizontal yang lebar, dan satu lagi yang menghasilkan satu sinar. Anda dapat menemukan konfigurasi mereka di ReplicatedStorageInstancesLaserBlastersFolder.

Fungsi ini kemudian menggunakan currentCamera.CFrame sebagai titik asal untuk ledakan, meneruskannya ke getDirectionsForBlast. Pada titik ini, kode tidak lagi tentang blaster, tetapi tentang sinar laser, yang akan Anda pelajari lebih lanjut di bagian mendeteksi hits dari tutorial. Akhirnya, setelah membuat tabel rayResults, generateBlastData memiliki semua informasi yang dibutuhkan untuk mengembalikan data ledakan ke blastClient.

Memberitahu server

Setelah blastClient memiliki data lengkap untuk ledakan, ia memicu dua peristiwa:

blastClient
local laserBlastedBindableEvent = ReplicatedStorage.Instances.LaserBlastedBindableEvent
local laserBlastedEvent = ReplicatedStorage.Instances.LaserBlastedEvent
laserBlastedBindableEvent:Fire(blastData)
laserBlastedEvent:FireServer(blastData)

BindableEvent memberi tahu skrip klien lainnya tentang ledakan. Misalnya, ReplicatedStorageFirstPersonBlasterVisuals menggunakan peristiwa ini untuk mengetahui kapan harus menampilkan efek visual, seperti animasi ledakan dan bilah cooldown. Demikian pula, RemoteEvent memberi tahu skrip server tentang ledakan, yang mulai memproses ledakan di ServerScriptServiceLaserBlastHandler.

LaserBlastHandler
local function onLaserBlastedEvent(playerBlasted: Player, blastData: BlastData.Type)
local validatedBlastData = getValidatedBlastData(playerBlasted, blastData)
if not validatedBlastData then
return
end
if not canPlayerBlast(playerBlasted) then
return
end
blastServer(playerBlasted)
processTaggedPlayers(playerBlasted, blastData)
for _, replicateToPlayer in Players:GetPlayers() do
if playerBlasted == replicateToPlayer then
continue
end
replicateBlastEvent:FireClient(replicateToPlayer, playerBlasted, blastData)
end
end

Untuk membantu mencegah kecurangan, server harus memverifikasi semua data yang dikirim setiap klien. Pemeriksaan ini mencakup:

  1. Apakah BlastData adalah tabel? Apakah itu berisi Class.CFrame dan tabel lain bernama rayResults?
  2. Apakah pemain memiliki blaster yang terpasang?
  3. Apakah pemain memiliki karakter dan lokasi dalam dunia?
  4. Setelah mengirim data ledakan, apakah pemain telah bergerak jarak yang berlebihan dari tempat mereka meledakkan sinar laser?

Pemeriksaan terakhir ini melibatkan penilaian, dan sesuai dengan latensi server dan kecepatan gerakan pemain, Anda mungkin memutuskan bahwa nilai yang berbeda adalah berlebihan untuk permainan Anda sendiri. Untuk mendemonstrasikan bagaimana membuat penilaian ini, Anda dapat mendapatkan gambaran tentang besaran perubahan posisi yang tipikal dengan menambahkan pernyataan cetak di getValidatedBlastData dan melakukan pengujian permainan.

getValidatedBlastData
local distanceFromCharacterToOrigin = blastData.originCFrame.Position - rootPartCFrame.Position
print(distanceFromCharacterToOrigin.Magnitude) -- baris yang diperbarui, pastikan untuk menghapus
if distanceFromCharacterToOrigin.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS then
warn(`Pemain {player.Name} gagal dalam pemeriksaan keabsahan asal saat meledak`)
return
end

Saat Anda bergerak dan meledak, perhatikan outputnya. Itu mungkin terlihat seperti ini:

1.9019629955291748
3.1549558639526367
2.5742883682250977
4.8044586181640625
2.6434271335601807

Jika Anda meningkatkan kecepatan gerakan untuk pemain di ReplicatedStoragePlayerStateHandlertogglePlayerMovement, maka lakukan pengujian lagi, Anda kemungkinan akan mengalami banyak pemeriksaan yang gagal karena gerakan yang berlebihan antara ledakan.

togglePlayerMovement
local ENABLED_WALK_SPEED = 60 -- baris yang diperbarui, pastikan untuk mengubah kembali

Server kemudian melakukan hal berikut:

  • Memvalidasi rayResults.
  • Memeriksa apakah pemain dapat meledak.
  • Mengatur ulang status blaster.
  • Mengurangi kesehatan untuk pemain yang ditandai.
  • Mereplikasi ledakan ke semua pemain lain sehingga mereka dapat melihat efek visual orang ketiga.

Untuk informasi lebih lanjut tentang operasi server ini, lihat bagian mendeteksi hits dari tutorial.

Mengatur ulang blaster

Dalam permainan laser tag contoh, blaster menggunakan mekanik panas. Alih-alih mengisi ulang setelah sejumlah ledakan tertentu, mereka memerlukan waktu untuk "mendinginkan" antara setiap ledakan. Penundaan cooldown yang sama terjadi di klien (blastClient) dan server (blastServer), dengan server bertindak sebagai sumber kebenaran.

blastServer
local blasterConfig = getBlasterConfig(player)
local secondsBetweenBlasts = blasterConfig:GetAttribute("secondsBetweenBlasts")
task.delay(secondsBetweenBlasts, function()
local currentState = player:GetAttribute(PlayerAttribute.blasterStateServer)
if currentState == BlasterState.Blasting then
player:SetAttribute(PlayerAttribute.blasterStateServer, BlasterState.Ready)
end
end)

Atribut secondsBetweenBlasts adalah bagian dari konfigurasi blaster di ReplicatedStorageInstancesLaserBlastersFolder. Setelah penundaan secondsBetweenBlasts berlalu, pemain dapat meledak lagi, dan seluruh proses diulang. Untuk membantu pemain memahami kapan mereka dapat meledak lagi, permainan menyertakan bilah cooldown.

Pada titik ini, pemain dapat muncul dan respawn, mengarahkan dan meledak, tetapi permainan masih harus menentukan hasil dari setiap ledakan. Di bagian berikutnya dari tutorial, Anda akan belajar bagaimana memprogram kemampuan blaster untuk mendeteksi ketika ledakan mengenai pemain lain, kemudian mengurangi jumlah kesehatan pemain yang sesuai sesuai dengan pengaturan blaster.

©2026 Roblox Corporation. Roblox, logo Roblox, dan Powering Imagination termasuk dalam merek dagang kami yang terdaftar dan tidak terdaftar di AS dan negara lainnya.