Memunculkan adalah proses membuat objek atau karakter di pengalaman, dan respawning adalah proses menambahkan objek atau karakter kembali ke pengalaman setelah mereka memenuhi kondisi penghapusan, seperti kesehatan karakter mencapai nol atau jatuh dari peta.Kedua proses penting karena mereka memastikan pemain dapat bergabung dengan pengalaman Anda, dan dapat terus bermain untuk meningkatkan keterampilan mereka.
Menggunakan pengalaman label laser sampel sebagai referensi, bagian tutorial ini mengajarkan Anda cara menggunakan dan menyesuaikan fitur bawaan Roblox untuk menangani pembuatan dan respawn, termasuk panduan pemrograman tentang:
- Mengkonfigurasi lokasi spawn sehingga pemain hanya dapat muncul di zona spawn tim mereka.
- Menambahkan pemain baru dan karakter mereka ke ronde saat mereka bergabung dengan pengalaman.
- Sesuaikan medan gaya yang mencegah kerusakan saat pemain muncul dan beregenerasi.
- Mengelola status klien sehingga gameplay berfungsi dengan benar pada waktu yang tepat.
- Memunculkan karakter kembali setelah mereka diberi label keluar dari ronde.
- Melakukan tindakan kecil dan bervariasi yang penting untuk menetapkan parameter gameplay dan karakter.
Bagian ini berisi banyak konten skrip, tetapi bukannya menulis semuanya dari awal saat membuat pengalaman, ia mendorong Anda untuk memanfaatkan komponen yang ada, berulang dengan cepat, dan menentukan sistem mana yang membutuhkan implementasi khusus untuk mencocokkan visi Anda.Setelah Anda menyelesaikan bagian ini, Anda akan belajar cara menerapkan permainan berbasis ronde yang melacak poin, memonitor status pemain, dan menampilkan hasil ronde.
Konfigurasi lokasi spawn
Jika Anda ingin menguji pengalaman sekarang, semua pemain akan secara acak muncul di objek SpawnLocation di zona spawn tim hijau, atau objek SpawnLocation di zona spawn tim merah muda.Ini menyajikan masalah gameplay di mana pemain dapat menandai satu sama lain di setiap zona spawn segera setelah medan gaya lawan mereka menghilang.
Untuk mengatasi masalah ini, pengalaman tag laser sampel mengkonfigurasi kedua lokasi spawn dengan properti untuk membatasi pemain tim lawan dari bertelur di zona spawn yang salah, dan properti yang diatur ke nilai yang sesuai dari Menugaskan Warna Tim di bagian sebelumnya dari tutorial:
- TimBSpawn – Lokasi spawn di zona spawn tim merah muda dengan properti TeamColor yang diatur ke Carnation Pink .


Ketika pemain bergabung dengan pengalaman, ServerScriptService > Gameplay > Ronde > spawnPlayersInMap memeriksa untuk melihat berapa banyak pemain yang sudah ada di setiap tim, lalu kembali ke tim dengan jumlah pemain paling sedikit.
memunculkan Pemain di Map
local function getSmallestTeam(): Team
local teams = Teams:GetTeams()
-- Urutkan tim dalam urutan menaik dari yang terkecil ke terbesar
table.sort(teams, function(teamA: Team, teamB: Team)
return #teamA:GetPlayers() < #teamB:GetPlayers()
end)
-- Kembalikan tim terkecil
return teams[1]
end
Setelah mengetahui tim dengan jumlah pemain paling sedikit, ia mengatur pemain ke tim itu, mengatur properti Player.Neutral mereka menjadi palsu sehingga pemain hanya dapat muncul dan bereinkarnasi ke lokasi spawn tim mereka, kemudian mengatur PlayerState mereka menjadi SelectingBlaster , yang akan Anda pelajari lebih lanjut nanti dalam tutorial.
memunculkan Pemain di Map
local function spawnPlayersInMap(players: { Player })
for _, player in players do
player.Team = getSmallestTeam()
player.Neutral = false
player:SetAttribute(PlayerAttribute.playerState, PlayerState.SelectingBlaster)
task.spawn(function()
player:LoadCharacter()
end)
end
end
Jika Anda memeriksa Ruang kerja > Dunia > Peta > Memunculkan , Anda dapat melihat bahwa ada satu lokasi spawn lagi di peta: NeutralSpawn .Lokasi spawn ini unik dari yang lain karena tidak memiliki set properti TeamColor untuk salah satu dari dua tim dalam pengalaman; sebaliknya, lokasi spawn ini memiliki properti Neutral yang berubah tergantung pada apakah ronde aktif.
Sebagai contoh, jika ronde aktif, set properti Neutral ke false sehingga spawnPlayersInMap dapat mengatur pemain ke tim dan menyebarkannya ke arena.Namun, jika ronde tidak aktif, seperti waktu antara satu ronde dan berikutnya, set properti Neutral menjadi benar sehingga pemain dapat muncul di sana terlepas dari status tim mereka.Proses ini adalah apa yang membuat lokasi spawn Neutral menjadi lobi fungsional.

Untuk menunjukkan, jika Anda memeriksa ServerScriptService > Gameplay > Ronde > SpawnPlayersInLobby , yang dijalankan di akhir ronde, Anda dapat melihat bahwa untuk setiap pemain yang diteruskan ke tabel players: { Player }, skrip:
- Atur properti Player.Neutral mereka ke benar untuk secara otomatis mengatur ulang Player.Team mereka ke nil , memungkinkan pemain untuk respawn di lobi saat ronde tidak aktif, karena properti lokasi spawn Neutral juga diatur ke benar .
- Mengubah PlayerState mereka menjadi InLobby untuk menghapus blaster pemain dan visual UI orang pertama.
Untuk informasi lebih lanjut tentang zona spawn netral dan fungsionalitasnya untuk setiap ronde, lihat Menambahkan Ronde di bagian selanjutnya dari tutorial.
spawnPemainDiLobi
local function spawnPlayersInLobby(players: { Player })
for _, player in players do
player.Neutral = true
player:SetAttribute(PlayerAttribute.playerState, PlayerState.InLobby)
task.spawn(function()
player:LoadCharacter()
end)
end
end
Hubungkan pemain baru
Kode Luau di Studio sering didorong oleh acara, artinya skrip mendengarkan acara dari layanan Roblox, lalu memanggil fungsi dalam respons.Sebagai contoh, saat menambahkan pemain baru ke pengalaman multi-pemain, harus ada acara yang menangani semua yang diperlukan agar pemain terhubung dengan sukses.Dalam pengalaman tag laser sampel, peristiwa yang sesuai adalah Players.PlayerAdded:Connect .
Players.PlayerAdded:Connect adalah bagian dari beberapa skrip dalam pengalaman.Jika Anda menggunakan pintasan Ctrl/Cmd+Shift+F dan mencari Players.PlayerAdded:Connect , hasilnya memberikan titik awal yang baik untuk memahami pengaturan awal pengalaman.

Untuk menunjukkan, buka ServerScriptService > SetupHumanoid .Perbedaan antara Player dan Character adalah kunci untuk memahami skrip ini:
- Pemain adalah klien terhubung, dan karakter adalah model .
- Pemain perlu memilih blaster dan ditambahkan ke papan peringkat. Karakter perlu muncul dan menerima blaster.
SetupHumanoid segera memeriksa apakah pemain memiliki karakter (baru saja bergabung) atau tidak (sedang di-respawn).Setelah menemukan satu, ia memanggil onCharacterAdded() , mendapatkan model Humanoid dari karakter, dan mengirimkannya ke ServerScriptService > SetupHumanoid > setupHumanoidAsync untuk kustomisasi.Setelah mengatur nilai ini, skrip kemudian menunggu kesehatan karakter mencapai nol.Anda akan mempelajari lebih lanjut tentang respawn nanti di bagian tutorial ini.
setupHumanoidAsync
local function setupHumanoidAsync(player: Player, humanoid: Humanoid)
humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.Subject
humanoid.NameDisplayDistance = 1000
humanoid.HealthDisplayDistance = 1000
humanoid.NameOcclusion = Enum.NameOcclusion.OccludeAll
humanoid.HealthDisplayType = Enum.HumanoidHealthDisplayType.AlwaysOn
humanoid.BreakJointsOnDeath = false
humanoid.Died:Wait()
onHumanoidDied(player, humanoid)
end
Catatan penting dengan skrip ini adalah bahwa properti benar-benar opsional, artinya jika Anda menghapus enam baris pertama dari fungsi, pengalaman masih berfungsi dengan baik.Daripada menjadi persyaratan fungsional, setiap properti memungkinkan Anda untuk membuat keputusan desain yang memenuhi tujuan permainan Anda.Sebagai contoh:
- Jika Anda ingin nama karakter ditampilkan pada jarak yang lebih dekat, kurangi nilai Humanoid.NameDisplayDistance.
- Jika Anda hanya ingin kesehatan karakter ditampilkan jika di bawah 100%, atur Humanoid.HealthDisplayType ke Tampilkan Saat Rusak .
- Jika Anda ingin karakter terpisah ketika kesehatan mereka mencapai 0, atur Humanoid.BreakJointsOnDeath ke Benar .
Jika Anda mengubah nilai properti ini, penting untuk melakukan pengujian untuk melihat dampak dari pengaturan baru Anda.Anda dapat membuat ulang apa yang pemain alami di lingkungan multiplayer dengan memilih setidaknya dua karakter di bagian Klien dan Server dari tab Tes .

Contoh lain dari acara Players.PlayerAdded:Connect adalah di ServerScriptService > PemainStatusPenangani .Sama seperti dalam contoh sebelumnya, PlayerStateHandler segera memeriksa karakter.Jika pemain tidak berada di lobi, skrip menetapkan atribut pemain ke status SelectingBlaster , status awal untuk ronde di mana pemain dapat memilih dari dua jenis blaster yang berbeda setelah muncul di arena.Negara ini juga termasuk medan gaya yang mencegah pemain menerima kerusakan saat mereka membuat pilihan.
Pengelola Negara Pemain
local function onPlayerAdded(player: Player)
player.CharacterAdded:Connect(function()
if not player.Neutral then
player:SetAttribute(PlayerAttribute.playerState, PlayerState.SelectingBlaster)
onPlayerStateChanged(player, PlayerState.SelectingBlaster)
end
end)
Satu variabel tertentu di PlayerStateHandler perang memerlukan diskusi: attributeChangedConnectionByPlayer .Tabel ini menyimpan semua pemain dan Connections mereka ke GetAttributeChangedSignal .Alasan untuk menyimpan koneksi ini di dalam tabel adalah agar PlayerStateHandler dapat terputus ketika pemain meninggalkan pengalaman.Proses ini berfungsi sebagai semacam manajemen memori untuk mencegah jumlah koneksi tumbuh semakin besar seiring waktu.
Pengelola Negara Pemain
local attributeChangedConnectionByPlayer = {}
local function onPlayerAdded(player: Player)
-- Tangani semua pembaruan masa depan ke status pemain
attributeChangedConnectionByPlayer[player] = player
:GetAttributeChangedSignal(PlayerAttribute.playerState)
:Connect(function()
local newPlayerState = player:GetAttribute(PlayerAttribute.playerState)
onPlayerStateChanged(player, newPlayerState)
end)
end
-- Terputus dari koneksi yang diubah atribut saat pemain meninggalkan
local function onPlayerRemoving(player: Player)
if attributeChangedConnectionByPlayer[player] then
attributeChangedConnectionByPlayer[player]:Disconnect()
attributeChangedConnectionByPlayer[player] = nil
end
end
Anda dapat melihat bahwa kedua fungsi terhubung dalam onPlayerAdded() panggilan onPlayerStateChanged() .Selama pengaturan awal setelah pemain disortir ke dalam tim, onPlayerAdded() menetapkan PlayerState ke SelectingBlaster , jadi pernyataan pertama if mengevaluasi ke false dan menonaktifkan BlasterState .Di bagian implementasi blaster kemudian dari tutorial, Anda akan mempelajari lebih banyak rincian tentang proses ini.
Pengelola Negara Pemain
local function onPlayerStateChanged(player: Player, newPlayerState: string)
-- Status blaster adalah 'Siap' hanya jika status pemain adalah 'Bermain'
local newBlasterState = if newPlayerState == PlayerState.Playing then BlasterState.Ready else BlasterState.Disabled
-- Jadwalkan logika medan gaya penghancur saat pemain mulai bermain
if newPlayerState == PlayerState.Playing then
scheduleDestroyForceField(player)
end
player:SetAttribute(PlayerAttribute.blasterStateServer, newBlasterState)
end
Jika Anda menambahkan titik istirahat atau bahkan hanya pernyataan print(), Anda dapat melihat bahwa onPlayerStateChanged() dipanggil sering selama pengalaman: seperti selama pengaturan awal ronde, untuk menetapkan diri di jalur kode utama, setelah pemain memilih blaster, dan saat pemain kembali ke lobi, atau lokasi spawn Neutral .Selain itu, setelah pemain memilih blaster, ServerScriptService > BlasterSelectedHandler > mengatur PlayerState ke Playing, dan PlayerStateHandler akhirnya dapat menghapus medan gaya dengan memanggil scheduleDestroyForceField().
Sesuaikan medan gaya
Alih-alih menggunakan implementasi khusus, pengalaman tag laser sampel menggunakan kelas bawaan Studio ForceField untuk mencegah pemain mengalami kerusakan saat mereka memilih blaster mereka.Ini memastikan bahwa satu-satunya persyaratan bagi pemain untuk muncul dengan medan gaya adalah menyertakan lokasi spawn dengan properti SpawnLocation.Duration yang lebih besar dari 0.Sampel menggunakan nilai acak 9,999 untuk mengaktifkan medan gaya, kemudian menangani durasi nyata secara programatik di ReplicatedStorage > ForceFieldClientVisuals .
Mirip dengan setupHumanoidAsync , sebagian besar baris di ForceFieldClientVisuals adalah opsional.Sebagai contoh, jika Anda mengkomentari konten fungsi seperti skrip berikut, pengalaman menggunakan bidang gaya default bukan hexagonal script di StarterGui > ForceFieldGui .
Mengkomentari Properti di ForceFieldClientVisuals
local function onCharacterAddedAsync(character: Model)
-- field kekuatan lokal = karakter:WaitForChild("ForceField", 3
-- jika bukan forceField maka
-- return
-- akhiri
-- forceField.Visible = salah
-- localPlayer.PlayerGui:WaitForChild("ForceFieldGui") Diaktifkan = benar
-- forceField.Destroying: Menunggu()
-- localPlayer.PlayerGui.ForceFieldGui.Enabled = false
end
Karena bidang gaya khusus adalah GUI bukan baru ParticleEmitter , skrip ForceFieldClientVisuals hanya memengaruhi visual orang pertama untuk setiap pemain, tidak visual ketiga orang ketika pemain melihat pemain lain.Visual orang ketiga mempertahankan penampilan Roblox default.Untuk informasi lebih lanjut tentang memodifikasi bidang gaya, lihat ForceField.Visible .


Medan gaya berguna karena memberi pemain cukup waktu untuk antara menelurkan dan respawn tanpa perlu khawatir tentang pemain musuh, tetapi akhirnya mereka perlu menghilang untuk gameplaytag laser utamaSkrip yang menangani penghapusan medan gaya berada di ReplicatedStorage > scheduleDestroyForceField , dan memeriksa tiga kondisi unik:
- Setelah pemain memilih blaster, medan gaya perlu bertahan cukup lama untuk memungkinkan pemain beradaptasi dengan lingkungan mereka.
- Selama waktu penyesuaian ini, medan gaya tidak bisa menjadi keuntungan, jadi mereka perlu menghilang saat pemain meledakkan blaster mereka.
- Medan gaya perlu menghilang ketika pemain mengatur ulang karakter mereka sebelum meledak atau sebelum waktu medan gaya habis.
Masing-masing periksa ini dalam panggilan skrip untuk kondisi ini.
jadwalkan Destruksi ForceField
-- Akhiri medan gaya jika pemain meledak
local blasterStateAttribute = getBlasterStateAttribute()
attributeChangedConnection = player:GetAttributeChangedSignal(blasterStateAttribute):Connect(function()
local currentBlasterState = player:GetAttribute(blasterStateAttribute)
if currentBlasterState == BlasterState.Blasting then
endForceField()
end
end)
-- Akhiri medan gaya jika pemain mengatur ulang
characterRespawnedConnection = player.CharacterRemoving:Connect(endForceField)
-- Akhiri medan gaya setelah 8 detik
task.delay(MAX_FORCE_FIELD_TIME, endForceField)
endForceField() termasuk pernyataan aneh tampaknya if di sekitar forceFieldEnded boolean.Karena pemeriksaan dijalankan secara berurutan, skrip dapat memanggil fungsi endForceField() dua atau bahkan tiga kali.The forceFieldEnded boolean memastikan bahwa fungsi hanya mencoba menghancurkan medan gaya sekali.
jadwalkan Destruksi ForceField
local function endForceField()
if forceFieldEnded then
return
end
forceFieldEnded = true
attributeChangedConnection:Disconnect()
characterRespawnedConnection:Disconnect()
destroyForceField(player)
end
Tangani status klien
Sementara sebagian besar bagian ini berfokus pada ServerScriptService > PemainStatusPenangani , ada skrip lain dengan nama yang sama di ReplicatedStorage .Alasan untuk pemisahan adalah arsitektur klien-server:
Klien perlu memahami informasi status pemain sehingga dapat merespon dengan tepat secara real time, seperti menampilkan elemen antarmuka pengguna yang tepat, atau memungkinkan pemain bergerak dan meledak.
Server membutuhkan semua informasi yang sama ini sehingga dapat mencegah exploit.Sebagai contoh, server juga membutuhkan status pemain untuk melakukan tindakan seperti memunculkan dan melengkapi karakter, menonaktifkan medan gaya, dan menampilkan papan peringkat.Inilah sebabnya mengapa skrip ini ada di ReplicatedStorage dan bukan lokasi sisi klien murni.
Untuk melihat logika inti ini, tinjau skrip berikut di ReplicatedStorage > Pengelola Status Pemain yang memverifikasi status saat ini pengguna, lalu memanggil fungsi yang sesuai yang menangani tindakan terkait untuk status itu.
Pengelola Negara Pemain
local function onPlayerStateChanged(newPlayerState: string)
if newPlayerState == PlayerState.SelectingBlaster then
onSelectingBlaster()
elseif newPlayerState == PlayerState.Playing then
onPlaying()
elseif newPlayerState == PlayerState.TaggedOut then
onTaggedOut()
elseif newPlayerState == PlayerState.InLobby then
onInLobby()
else
warn(`Invalid player state ({newPlayerState})`)
end
end
Semua respons acara dikelompokkan secara logis bersama-sama dalam skrip ini karena mereka memerlukan perilaku serupa untuk mengaktifkan atau menonaktifkan kendalipemutar, gerakan kamera, dan lapisan UI mana yang terlihat.Sebagai contoh, selama pemilihan blaster, pemain harus menjadi tidak rentan dan tidak dapat bergerak.Server sudah menangani medan gaya, tetapi klien menangani gerakan.Untuk menunjukkan, jika Anda memeriksa logika untuk fungsi onSelectingBlaster() , Anda dapat melihat bahwa klien menonaktifkan gerakan pemain saat mereka memilih blaster.
Pengelola Negara Pemain
local function onSelectingBlaster()
togglePlayerCamera(true)
togglePlayerMovement(false)
setGuiExclusivelyEnabled(playerGui.PickABlasterGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
Fungsi onPlaying() adalah sama mudah.Ini memungkinkan gerakan, transisi ke tampilan head-up utama (HUD), mengaktifkan blaster, dan memanggil fungsi medan gaya yang sama seperti server.
Pengelola Negara Pemain
local function onPlaying()
togglePlayerMovement(true)
setGuiExclusivelyEnabled(playerGui.HUDGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Ready)
scheduleDestroyForceField()
end
Memunculkan karakter kembali
Pengalaman label laser sampel menangani respawn karakter kembali ke ronde melalui status onTaggedOut() di ReplicatedStorage > PemutarStatusHandler .Seperti keadaan onSelectingBlaster() dan onPlaying() seperti, onTaggedOut() memicu perilaku unik sesuai dengan perubahan atribut playerState.Secara khusus, ia menonaktifkan gerakan pemain, menampilkan UI respawn, dan menonaktifkan blaster.
Pengelola Negara Pemain
local function onTaggedOut()
-- Nonaktifkan kontrol saat ditagih keluar
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- Nonaktifkan blaster saat ditagih keluar
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
Jika Anda ingin menguji perilaku ini, Anda dapat menekan Esc , menavigasi ke tab Pengaturan , lalu klik tombol Reset Karakter .Perhatikan bahwa ketika Anda mengaktifkan layar respawn, Anda tidak dapat bergerak, memutar kamera, atau meledakkan blaster Anda.


Penting untuk dicatat bahwa skrip ini sebenarnya tidak menghidupkan kembali karakter, itu hanya menghentikan mereka dari bertindak dan memberikan umpan balas visual kepada pemain bahwa server menghidupkan kembali karakter mereka.Untuk menunjukkan, jika Anda memeriksa ServerScriptService > SetupHumanoid > setupHumanoidAsync > onHumanoidDied , skrip menetapkan PlayerState ke TaggedOut (pada dasarnya memberi pemberitahuan ke ReplicatedStorage > PlayerStateHandler ), dan menambahkan beberapa indikator visual.Logika aktual dari respawn adalah perilaku Roblox yang dibangun.
Ketika pemain muncul kembali ke ronde, mereka muncul kembali di lokasi spawn tim mereka sesuai dengan properti SpawnLocation.TeamColor.Untuk menyesuaikan waktu respawn, Anda dapat menambahkan baris berikut ke bagian atas SetupHumanoid .Untuk mempelajari lebih lanjut tentang teknik ini, lihat Players.RespawnTime .
MenyiapkanHumanoid
local Players = game:GetService("Players")Players.RespawnTime = 10 -- new line, in seconds
Pengaturan lain-lain
Sebagai bagian dari pengaturan awal, pengalaman tag laser sampel juga melakukan beberapa langkah kecil, tetapi kritis:
Pengalaman tersebut termasuk skrip kosong bernama StarterPlayer > StarterCharacterScripts > Kesehatan yang menonaktifkan regenerasi kesehatan default Roblox.Untuk penjelasan tentang perilaku properti ini, lihat Humanoid.Health .
Pengalaman menggunakan kamera orang pertama dengan mengatur properti StarterPlayer.CameraMode.LockFirstPerson.Perhatikan bahwa jika Anda ingin membiarkan pengguna beralih di antara kamera orang pertama dan ketiga, Anda harus mengubah properti secara programatik daripada hanya menetapkannya sekali di Studio, dan mengubah kontrol dan antarmuka untuk menebus perubahan perspektif.
Pengalaman menggunakan papan peringkat Roblox bawaan dengan unit "poin", yang diperoleh pemain setiap kali mereka menandai pemain lain.Anda dapat melihat konfigurasi di ServerScriptService > SetupLeaderboard , tetapi In-Experience Leaderboards menawarkan pandangan lengkap.Perhatikan bahwa onPlayerTagged menambahkan poin ke papan peringkat, yang akan Anda pelajari di Tambah ronde dan Deteksi pukulan.
Sekarang pemain dapat muncul, pilih blaster, dan arahkan dari sudut pandang orang pertama, bagian berikutnya mengajarkan Anda tentang skrip di balik penciptaan gameplayberbasis ronde.