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 pengalaman penembak orang pertama. Sementara pemain dapat melakukan ledakan dengan satu klik atau tekan tombol, menciptakan perilaku ledakan yang memuaskan dan akurat sangat penting karena meningkatkan kesenangan pemain dalam keseluruhan gameplay.

Dengan menggunakan pengalaman laser tag contoh sebagai referensi, bagian dari 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 tepat jika ledakan bertubrukan dengan pemain lain.
  • Mengatur ulang blaster di antara setiap ledakan untuk memberikan waktu bagi blaster untuk mendingin sebelum dapat melakukan ledakan lagi.

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

Mendeteksi input pemain

Langkah pertama untuk mengimplementasikan perilaku blaster adalah mendengarkan kapan pemain menekan tombol ledakan. Jenis input yang digunakan pemain untuk menekan tombol ledakan tergantung pada perangkat yang mereka gunakan untuk mengakses pengalaman tersebut. Misalnya, pengalaman laser tag contoh mendukung kontrol mouse dan keyboard, gamepad, dan kontrol sentuh. Anda dapat melihat setiap 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 keluar dari blaster. Perhatikan bahwa HUDGui memiliki tombol untuk ledakan di perangkat mobile, yang akan terhubung 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 tersebut. Namun, mekanik ledakan tidak terasa responsif kecuali terjadi saat tombol ditekan.

Sebagai contoh, Anda dapat mengubah Enum.UserInputState.Begin menjadi Enum.UserInputState.End, lalu melakukan pengujian untuk melihat bagaimana responsivitas ledakan memengaruhi gameplay dari pengalaman tersebut. 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 melakukan ledakan

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

canLocalPlayerBlast

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

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

Jeda kecil ini mencegah Anda untuk dapat melakukan ledakan secepat Anda mengklik. Misalnya, jika Anda mengubah fungsi untuk selalu mengembalikan true, Anda dapat dengan cepat melakukan ledakan tanpa jeda, yang tidak realistis untuk gameplay 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 memuat 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 sebaran horizontal yang lebar, dan yang lainnya menghasilkan satu sinar tunggal. Anda dapat menemukan konfigurasinya di ReplicatedStorageInstancesLaserBlastersFolder.

Fungsi tersebut kemudian menggunakan currentCamera.CFrame sebagai titik asal untuk ledakan, menyerahkannya ke getDirectionsForBlast. Pada titik ini, kode tidak lagi tentang blaster, tetapi tentang sinar laser, yang akan Anda pelajari lebih lanjut di bagian mendeteksi pukulan 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 yang 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 lain tentang ledakan. Misalnya, ReplicatedStorageFirstPersonBlasterVisuals menggunakan peristiwa ini untuk mengetahui kapan 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 oleh setiap klien. Pemeriksaan ini termasuk:

  1. Apakah BlastData sebuah tabel? Apakah ia mengandung Class.CFrame dan tabel lain yang dinamai rayResults?
  2. Apakah pemain memiliki blaster yang dilengkapi?
  3. Apakah pemain memiliki karakter dan lokasi dalam dunia?
  4. Setelah mengirim data ledakan, apakah pemain bergerak terlalu jauh dari tempat mereka melakukan ledakan sinar laser?

Pemeriksaan terakhir ini melibatkan penilaian, dan sesuai dengan latensi server dan kecepatan gerakan pemain, Anda mungkin memutuskan bahwa nilai yang berbeda terlalu tinggi untuk pengalaman Anda sendiri. Untuk mendemonstrasikan bagaimana membuat penilaian ini, Anda dapat merasa tentang besarnya perubahan posisi yang tipikal dengan menambahkan pernyataan cetak di getValidatedBlastData dan melakukan pengujian pengalaman.

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 memeriksa keabsahan asal saat melakukan ledakan`)
return
end

Saat Anda bergerak dan melakukan ledakan, catat 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, kemudian lakukan pengujian lagi, Anda kemungkinan besar 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 melakukan ledakan.
  • Mengatur ulang status blaster.
  • Mengurangi kesehatan untuk setiap pemain yang terkena.
  • Menyebarkan ledakan ke semua pemain lain sehingga mereka dapat melihat visual pihak ketiga.

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

Mengatur ulang blaster

Dalam pengalaman laser tag contoh, blaster menggunakan mekanik panas. Alih-alih memuat ulang setelah sejumlah ledakan tertentu, mereka memerlukan waktu untuk "mendinginkan" di antara setiap ledakan. Jeda pendinginan 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 jeda secondsBetweenBlasts berlalu, pemain dapat melakukan ledakan lagi, dan seluruh proses diulang. Untuk membantu pemain memahami kapan mereka bisa melakukan ledakan lagi, pengalaman ini menyertakan bilah cooldown.

Pada titik ini, pemain dapat muncul dan respawn, membidik dan melakukan ledakan, tetapi pengalaman ini masih harus menentukan hasil dari setiap ledakan. Di bagian berikutnya dari tutorial, Anda akan belajar bagaimana memprogram kemampuan bagi blaster untuk mendeteksi ketika ledakan mengenai pemain lain, lalu 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.