Menambahkan ronde memungkinkan Anda mengatur gameplay menjadi fase dengan titik mulai dan selesai yang jelas sehingga pemain dapat mengukur kemajuan mereka dan memiliki kesempatan periodik untuk bermain dalam kondisi yang setara. Ini sangat penting untuk gameplay berbasis tim karena memberikan pemain kesempatan untuk mengubah gaya bermain mereka tergantung pada siapa yang ada di tim mereka selama ronde tersebut.
Menggunakan pengalaman laser tag contoh sebagai referensi, bagian dari tutorial ini mengajarkan Anda cara menggunakan dan menyesuaikan fitur bawaan Roblox untuk mengatur setiap ronde, termasuk bimbingan scripting tentang:
- Memulai ronde dengan mengatur ulang poin individu dan tim, kemudian memunculkan pemain ke zona spawn tim mereka.
- Menyesuaikan variabel yang mengatur tujuan untuk ronde di bagian atas layar setiap pemain.
- Melacak kontribusi poin pemain untuk skor tim mereka.
- Memicu tampilan UI unik tergantung pada apakah tim pemain memenangkan atau kalah ronde.
- Mengakhiri ronde dengan memutuskan koneksi pemain dan memunculkan mereka di lobi netral.
Setelah Anda menyelesaikan bagian ini, Anda akan belajar bagaimana mengimplementasikan perilaku blaster yang akurat dan memuaskan bagi pemain.

Mulai loop
ServerScriptService ⟩ Gameplay ⟩ Rounds menangani sebagian besar logika untuk mengimplementasikan ronde, dan dimulai dengan memanggil fungsi startRoundLoopAsync() untuk menandai awal dari loop ronde. Sementara pemain bergabung ke lobi dan menunggu untuk disortir ke tim, startRoundLoopAsync() memanggil fungsi resetScores() di ServerScriptService ⟩ Gameplay ⟩ Scoring untuk mengatur ulang baik papan peringkat maupun poin tim.
Scoring
function Scoring.resetScores()
for _, player in Players:GetPlayers() do
player.leaderstats.Points.Value = 0
end
for _, team in Teams:GetTeams() do
team:SetAttribute(GuiAttribute.teamPoints, 0)
end
end
Sekarang semua orang memulai dengan nol poin, startRoundLoopAsync() kemudian mengatur properti lokasi spawn Neutral Neutral menjadi false sehingga hanya pemain dengan properti Team.Color yang sama dengan properti TeamColor dari lokasi spawn yang dapat muncul di sana. Karena properti TeamColor dari lokasi spawn diatur ke white alih-alih tim mint atau carnation pink dari contoh, konfigurasi ini mencegah semua pemain muncul atau respawn di sana sementara ronde aktif.
Untuk pemain yang saat ini berada di lobi, startRoundLoopAsync() meneruskan semua pemain yang saat ini berada dalam pengalaman ke fungsi spawnPlayersInMap di ServerScriptService ⟩ Gameplay ⟩ Rounds ⟩ spawnPlayersInMap untuk menyortir dan menyeimbangkan semua orang ke dalam tim dengan jumlah pemain yang kira-kira sama.
Untuk pemain baru yang bergabung dengan pengalaman setelah kelompok lobi disortir ke dalam tim, startRoundLoopAsync() mendengarkan acara Players.PlayerAdded:Connect, kemudian memanggil lagi fungsi spawnPlayersInMap untuk menambahkan mereka ke tim dengan jumlah pemain paling sedikit. Untuk informasi lebih lanjut tentang proses ini, lihat Konfigurasi Lokasi Spawn dari bagian Memunculkan dan Respawn sebelumnya dari tutorial.
Rounds
-- Spawn all players in the map
neutralSpawn.Neutral = false
spawnPlayersInMap(Players:GetPlayers())
-- Spawn new players in the map when they join
local playerAddedConnection = Players.PlayerAdded:Connect(function(player: Player)
spawnPlayersInMap({ player })
end)
Tetapkan tujuan
Sekarang bahwa setiap pemain berada di arena dengan rekan satu tim mereka, pengalaman perlu memberikan instruksi tentang apa yang harus dilakukan untuk berhasil dalam ronde. Pengalaman laser tag contoh memenuhi persyaratan ini dengan memberikan prompt tujuan di bagian atas layar setiap pemain dengan panduan yang jelas tentang apa yang perlu dilakukan tim untuk menang.

Sementara Anda dapat mempelajari lebih lanjut tentang cara mengonfigurasi dan menampilkan komponen UI Tujuan dalam Kurikulum UI, bagian ini fokus pada cara mengimplementasikan tujuan saat ronde dimulai, dimulai dengan bagaimana menetapkan jumlah poin yang perlu diselesaikan oleh setiap tim untuk menyelesaikan ronde.
Meskipun prompt tujuan saat runtime memberi tahu pemain bahwa mereka perlu mencetak tiga poin untuk menang, jika Anda memeriksa prompt di StarterGui ⟩ HUDGui, Anda dapat melihat bahwa ia malah berisi "%d" yang dapat dikonfigurasi untuk nilai poin.

"%d" adalah string placeholder yang dapat Anda tingkatkan atau kurangi kapan saja untuk memenuhi kebutuhan gameplay Anda sendiri dengan memperbarui variabel TEAM_SCORE_LIMIT di ReplicatedStorage ⟩ TEAM_SCORE_LIMIT. Sebagai contoh, jika Anda mengatur angka ini ke 200 yang terlalu tinggi, prompt dan penghitung poin tim akan diperbarui sesuai.
TEAM_SCORE_LIMITlocal TEAM_SCORE_LIMIT = 200 -- updated line, be sure to change backreturn TEAM_SCORE_LIMIT

Pembaruan variabel sederhana ini bekerja saat runtime karena saat ronde dimulai, ReplicatedStorage ⟩ HUDGuiSetup ⟩ SetObjective memerlukan modul skrip TEAM_SCORE_LIMIT sehingga dapat menukar string placeholder di objek TextLabel UI Tujuan.
TEAM_SCORE_LIMIT
local TEAM_SCORE_LIMIT = require(ReplicatedStorage.TEAM_SCORE_LIMIT)
local function setObjective(gui: ScreenGui)
local bodyTextLabel = gui.Objective.ObjectiveDisplay.Body.BodyTextLabel
bodyTextLabel.Text = bodyTextLabel.Text:format(TEAM_SCORE_LIMIT)
end
Melacak poin
Sekarang bahwa pemain memiliki tujuan untuk ronde, pengalaman perlu melacak poin masing-masing tim hingga mereka memenuhi tujuan mereka. Sementara perilaku default dari layanan Teams secara otomatis mengelompokkan setiap pemain di bawah tim mereka dan menjumlahkan kontribusi setiap pemain ke skor tim mereka, penting untuk menyimpan dan memantau poin di lokasi terpisah untuk gameplay berbasis ronde karena jika seorang pemain mencetak poin lalu keluar sebelum ronde berakhir, kontribusinya akan dipotong dari papan peringkat segera setelah mereka terputus dari pengalaman.
Untuk memastikan ini tidak terjadi dan setiap kontribusi menuju tujuan tim tetap terjaga, ReplicatedStorage ⟩ HUDGuiSetup ⟩ StartSyncingTeamPoints menyimpan semua poin secara terpisah di bawah atribut teamPoints dalam layanan Teams. Saat teamPoints meningkat, modul skrip ini memanggil fungsi startSyncingTeamPoints untuk menemukan penghitung tim Class.GuiObjects di dalam komponen UI Tujuan.
Ketika menemukan TeamACounter dan TeamBCounter, ia mendapatkan atribut teamColor mereka, yang berkorelasi dengan zona spawn tim: TeamACounter menampilkan poin tim hijau, dan TeamBCounter melacak poin tim pink.
StartSyncingTeamPoints
local function startSyncingTeamPoints(gui: ScreenGui)
for _, teamPointCounter in gui.Objective.TeamPointCounter:GetChildren() do
if not teamPointCounter:IsA("GuiObject") then
continue
end
local iconTeamColor = teamPointCounter:GetAttribute(GuiAttribute.teamColor)
Modul skrip kemudian memanggil fungsi getTeamFromTeamColor untuk memvalidasi bahwa atribut teamColor mint dari TeamACounter dan atribut teamColor carnation pink dari TeamBCounter keduanya cocok dengan properti Team.Color yang sesuai di bawah layanan Teams. Jika demikian, ia mengembalikan kedua tim tersebut.
StartSyncingTeamPoints
local function getTeamFromTeamColor(teamColor: Color3): Team?
for _, team in Teams:GetTeams() do
if team.TeamColor == teamColor then
return team
end
end
return nil
end
Ketika ini terjadi, startSyncingTeamPoints mengatur objek TextLabel dari kedua penghitung tim ke nilai teamPoints mereka yang sesuai, dan terus memperbarui mereka setiap kali seorang pemain mencetak poin dengan menandai pemain lain di tim lawan.
StartSyncingTeamPoints
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
team:GetAttributeChangedSignal(GuiAttribute.teamPoints):Connect(function()
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
Semuanya di bagian ini sejauh ini telah berfokus pada cara melacak poin di layar pemain, tetapi penting untuk meninjau logika yang menangani pelacakan poin di server sehingga tahu kapan tim memenuhi tujuan dan memenangkan ronde. Jika Anda mengunjungi ServerScriptService ⟩ Gameplay ⟩ Scoring, Anda dapat melihat bahwa modul skrip dimulai dengan membuat acara bindable, yang akan dipicu setiap kali seorang pemain mencetak poin.
Scoringlocal teamScoreChangedBindable = Instance.new("BindableEvent")local Scoring = {teamScoreChanged = teamScoreChangedBindable.Event,}
Ia kemudian memanggil fungsi incrementScore, yang melakukan tindakan berikut:
- Mengambil skor individu pemain di papan peringkat, dan menambah satu.
- Memicu acara bindable sebelumnya yang disebutkan dengan tim pemain dan skor mereka.
Proses ini secara efektif menjaga keselarasan antara klien dan server mengenai skor individu dan skor tim pemain.
Scoring
function Scoring.incrementScore(player: Player, amount: number)
local team = player.Team
assert(team, `Pemain {player.Name} harus berada di tim untuk mencetak poin, tetapi tidak memiliki tim`)
local teamPoints = team:GetAttribute(GuiAttribute.teamPoints)
teamPoints += amount
team:SetAttribute(GuiAttribute.teamPoints, teamPoints)
local leaderstat = player.leaderstats.Points
leaderstat.Value += amount
teamScoreChangedBindable:Fire(team, teamPoints)
end
Tampilkan hasil
Saat pemain saling menandai dan mencetak poin untuk tim mereka, ServerScriptService ⟩ Gameplay ⟩ Rounds memeriksa apakah tim yang mencetak poin memenuhi tujuan ronde. Jika skor tim mereka lebih rendah dari variabel TEAM_SCORE_LIMIT di ReplicatedStorage ⟩ TEAM_SCORE_LIMIT, server terus menunggu sampai salah satu tim mencetak lagi.
Namun, setelah skor tim mencapai variabel TEAM_SCORE_LIMIT, skrip memicu sebuah instance acara roundWinnerRemote dengan nama pemain dan tim mereka.
Rounds-- Check if the round has finished after each scorelocal team: Teamlocal score: number = 0while score < TEAM_SCORE_LIMIT doteam, score = Scoring.teamScoreChanged:Wait()end-- Display winning teamfor _, player in Players:GetPlayers() do-- Sending what team the player is on at the end of the round-- because the player's team is about to be removed, so the client-- won't be able to check its own teamroundWinnerRemote:FireClient(player, team, player.Team)end
Skrip ReplicatedStorage ⟩ RoundResultsGuiSetup pada setiap klien mendengarkan untuk acara instance roundWinnerRemote ini sehingga dapat:
- Menampilkan layar UI StarterGui ⟩ RoundResultsGui unik yang mengumumkan hasil ronde dan apakah pemain berada di tim pemenang.
- Memainkan klip audio kemenangan atau kekalahan.
Sebagai contoh, jika pemain berada di tim yang mencetak poin kemenangan, mereka menerima beberapa bentuk umpan balik tentang hasil ronde dalam bentuk layar UI yang menampilkan teks kemenangan, dan klip audio yang memainkan suara gembira. Sebaliknya, jika pemain tidak berada di tim yang mencetak poin kemenangan, mereka menerima layar UI yang menampilkan teks kekalahan, dan klip audio yang memainkan suara menakutkan.
RoundResultsGuiSetup
local function onRoundWinner(winner: Team, localTeam: Team?)
local victoryDefeatText = "Ronde berakhir!"
if localTeam then
-- Jika tim kami menang, kami akan menampilkan Kemenangan! Jika tidak, tampilkan Kekalahan...
local isVictory = winner == localTeam
if isVictory then
victorySound:Play()
victoryDefeatText = VICTORY_TEXT
else
defeatSound:Play()
victoryDefeatText = DEFEAT_TEXT
end
end
Reset tim
Pada saat yang sama bahwa ServerScriptService ⟩ Gameplay ⟩ Rounds memverifikasi bahwa sebuah tim memenuhi tujuan ronde dan memicu tampilan UI yang sesuai untuk setiap pemain, ia juga mentransportasikan semua pemain dari arena ke lobi dengan memutuskan koneksi mereka dari ronde. Ini memulai proses secara resmi mengakhiri ronde dan mereset kedua tim.
Menggunakan logika yang sama dalam Konfigurasi Lokasi Spawn, Rounds kemudian mengatur properti Neutral dari lokasi spawn Neutral menjadi true sehingga pemain dapat muncul di sana terlepas dari status tim mereka. Ini berarti lobi menjadi satu-satunya lokasi tempat pemain dapat muncul setelah mereka terputus dari ronde.
Rounds-- Send everyone to the lobbyplayerAddedConnection:Disconnect()neutralSpawn.Neutral = truespawnPlayersInLobby(Players:GetPlayers())
Setelah menunggu sepuluh detik untuk jeda, skrip server Rounds kemudian memulai loop lagi dengan mengatur ulang skor semua orang dan menyortir mereka ke dalam tim baru. Sampel ini mengulangi proses ronde siklis ini lagi hingga tidak ada pemain di dalam server.
Sekarang bahwa pemain dapat muncul ke peta dengan tim mereka sendiri dan bermain satu ronde penuh, bagian selanjutnya mengajarkan Anda tentang skrip di balik perilaku setiap blaster.