Turlar eklemek, oyuncuların ilerlemelerini ölçebilmeleri ve eşit bir oyun alanı sağlamak için düzenli olarak fırsat sahibi olabilmeleri amacıyla oyunu net bir başlangıç ve bitiş noktasıyla aşamalara ayırmanıza olanak tanır. Bu, her turda takımda kimin bulunduğuna bağlı olarak oyuncuların oyun tarzını değiştirme şansı sunması nedeniyle özellikle takım tabanlı oyunlarda önemlidir.
Örnek lazer tag deneyimini referans alarak, bu eğitim bölümünde her turu yapılandırmak için Roblox'un yerleşik özelliklerini nasıl kullanacağınızı ve özelleştireceğinizi öğreneceksiniz. Bu, aşağıdaki konularda betik rehberliği içermektedir:
- Bireysel ve takım puanlarını sıfırlayarak, ardından oyuncuları takım doğum bölgelerine yerleştirerek bir turu başlatmak.
- Her oyuncunun ekranının üst kısmında turun amacını belirleyen değişkenleri özelleştirmek.
- Oyuncuların takım puanlarına katkılarını takip etmek.
- Oyuncunun takımı turu kazanıp kazanmadığına bağlı olarak benzersiz UI ekranlarını tetiklemek.
- Oyuncuları bağlantıdan çıkararak ve nötr lobide yeniden doğurarak bir turu sona erdirmek.
Bu bölümü tamamladıktan sonra, oyuncular için hem doğru hem de tatmin edici olan blaster davranışını nasıl uygulayacağınızı öğreneceksiniz.

Döngüyü başlat
ServerScriptService ⟩ Gameplay ⟩ Rounds, turların uygulanması için çoğu mantığı yönetir ve bir tur döngüsünün başlangıcını belirtmek için startRoundLoopAsync() fonksiyonunu çağırarak başlar. Oyuncular lobide yer alırken ve takımlara ayrılmak için beklerken, startRoundLoopAsync() fonksiyonu, ServerScriptService ⟩ Gameplay ⟩ Scoring içinde resetScores() fonksiyonunu çağırarak hem liderlik tablosunu hem de takım puanlarını sıfırlar.
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
Herkesin sıfır puandan başlaması sayesinde, startRoundLoopAsync() ardından Neutral doğum yerinin Neutral özelliğini false olarak ayarlar, böylece yalnızca doğum yerinin TeamColor özelliğiyle aynı Team.Color özelliğine sahip oyuncular orada doğabilir. Doğum yerinin TeamColor özelliği beyaz olarak ayarlandığı için, bu ayar aktif bir tur sırasında tüm oyuncuların orada doğmasını veya yeniden doğmasını engeller.
Lobbyde bulunan oyuncular için, startRoundLoopAsync() mevcut deneyim içindeki tüm oyuncuları sıralayıp dengelemek için ServerScriptService ⟩ Gameplay ⟩ Rounds ⟩ spawnPlayersInMap içindeki spawnPlayersInMap fonksiyonuna aktarır.
Lobby grubunun takımlara sıralanmasından sonra deneyime katılan yeni oyuncular için, startRoundLoopAsync() Players.PlayerAdded:Connect olayını dinler, ardından en az oyuncuya sahip takıma eklemek için spawnPlayersInMap fonksiyonunu yeniden çağırır. Bu süreç hakkında daha fazla bilgi için, önceki Doğurma ve Yeniden Doğurma bölümündeki Doğma Konumlarını Yapılandır kısmını inceleyin.
Rounds
-- Haritada tüm oyuncuları doğur
neutralSpawn.Neutral = false
spawnPlayersInMap(Players:GetPlayers())
-- Haritada yeni oyuncuları doğurduklarında
local playerAddedConnection = Players.PlayerAdded:Connect(function(player: Player)
spawnPlayersInMap({ player })
end)
Hedef belirle
Artık her oyuncu takım arkadaşlarıyla arenada olduğuna göre, deneyim, turda başarılı olmak için ne yapmaları gerektiğine dair talimatlar sunmalıdır. Örnek lazer tag deneyimi, her oyuncunun ekranının üst kısmında, takımın kazanmak için ne yapması gerektiğine yönelik net bir rehberlikle bir hedef istemi sağlayarak bu gerekliliği ele alır.

UI Müfredatında hedef UI bileşenini nasıl yapılandırıp görüntüleyeceğinizi daha fazla öğrenebilirsiniz, ancak bu bölüm, turun başlamasıyla hedef amacını nasıl uygulayacağınız üzerine odaklanmaktadır. Bunun başlangıcı, her takımın turun tamamlanması için tamamlaması gereken puan sayısını ayarlamaktır.
Gerçek zamanlı hedef istemi, oyuncuların kazanmak için üç puan almaları gerektiğini bildirse de, StarterGui ⟩ HUDGui içinde istemi incelediğinizde, bunun yerine yapılandırılabilir bir "%d" puan değeri içerdiğini görebilirsiniz.

"%d" bir yer tutucu dizesidir ve istediğiniz zaman kendi oyun gereksinimlerinize hitap etmek için ReplicatedStorage ⟩ TEAM_SCORE_LIMIT içindeki TEAM_SCORE_LIMIT değişkenini güncelleyerek artırabilir veya azaltabilirsiniz. Örneğin, bu sayıyı aşırı yüksek bir 200 olarak ayarlarsanız, istem ve takım puan görüntüleyicisi buna göre güncellenir.
TEAM_SCORE_LIMITlocal TEAM_SCORE_LIMIT = 200 -- güncellenen satır, lütfen geri değiştirinreturn TEAM_SCORE_LIMIT

Bu basit değişken güncellemesi çalışma zamanında işler çünkü tur başlamadan önce ReplicatedStorage ⟩ HUDGuiSetup ⟩ SetObjective TEAM_SCORE_LIMIT modül betiğini talep eder, böylece UI Hedefinin TextLabel nesnesindeki yer tutucu dizesini değiştirebilir.
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
Puanları takip et
Artık oyuncuların bir amacı olduğuna göre, deneyim, her takımın puanlarını hedeflerini tamamlayana kadar takip etmelidir. Teams servisinin varsayılan davranışı, her oyuncuyu otomatik olarak takımları altında gruplayıp her oyuncunun katkılarını takım puanına eklese de, oyuncunun bir puan kazandığı ve tur döngüsü bitmeden ayrıldığı durumlarda, puanları ayrı bir yerelle saklamanın ve izlemenin önemli olduğunu gösterir. Çünkü oyuncu bağlantısını kestiğinde katkısı liderlik tablosundan düşülür.
Bunun olmasını önlemek ve takım hedefine katkıların korunmasını sağlamak için, ReplicatedStorage ⟩ HUDGuiSetup ⟩ StartSyncingTeamPoints tüm puanları Teams servisi içindeki teamPoints niteliği altında ayrı olarak saklar. teamPoints arttıkça, bu modül betiği startSyncingTeamPoints fonksiyonunu çağırarak Hedef UI bileşenindeki takım sayacını Class.GuiObjects içinde bulur.
TeamACounter ve TeamBCounter bulunduğunda, takımların doğum bölgeleriyle ilişkili olan teamColor niteliğini alır: TeamACounter yeşil takımın puanlarını gösterirken, TeamBCounter pembe takımın puanlarını takip eder.
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)
Modül betiği daha sonra, TeamACounter'ın mint teamColor niteliğinin ve TeamBCounter'ın carnation pink teamColor niteliğinin altında Teams servisinin Team.Color özellikleriyle eşleşip eşleşmediğini doğrulamak için getTeamFromTeamColor fonksiyonunu çağırır. Eğer bu doğruysa, her iki takımı döndürecektir.
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
Bu gerçekleştiğinde, startSyncingTeamPoints her iki takım sayacının TextLabel nesnelerini karşılık gelen teamPoints değerlerine ayarlar ve bir oyuncu, diğer takımdan bir oyuncuyu etiketleyerek puan kazandığında bunları güncellemeye devam eder.
StartSyncingTeamPoints
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
team:GetAttributeChangedSignal(GuiAttribute.teamPoints):Connect(function()
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
Bu bölümde şu ana kadar oyuncunun ekranında puanları takip etmeye odaklanılmıştır, ancak takımın hedef amacını yerine getirip getirmediğini bilmek için sunucuda puanları takip etme mantığını gözden geçirmek de önemlidir. ServerScriptService ⟩ Gameplay ⟩ Scoring bölümüne geri dönerseniz, modül betiğinin, her oyuncu puan kazandığında ateşlenecek bir bağlayıcı olayı oluşturmakla başladığını görebilirsiniz.
Scoringlocal teamScoreChangedBindable = Instance.new("BindableEvent")local Scoring = {teamScoreChanged = teamScoreChangedBindable.Event,}
Ardından, incrementScore fonksiyonunu çağırır ve aşağıdaki işlemleri gerçekleştirir:
- Oyuncunun liderlik tablosundaki bireysel puanını alır ve bir artırır.
- Daha önce bahsedilen bağlayıcı olayı, hem oyuncunun takımını hem de puanını ateşler.
Bu süreç, istemci ile sunucunun her iki oyuncunun bireysel puanları ve takım puanları hakkında uyumlu kalmasını etkin bir şekilde sağlar.
Scoring
function Scoring.incrementScore(player: Player, amount: number)
local team = player.Team
assert(team, `Player {player.Name} must be on a team to score a point, but has no team`)
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
Sonuçları görüntüle
Oyuncular birbirlerini etiketleyip takım puanları kazandıkça, ServerScriptService ⟩ Gameplay ⟩ Rounds hangi takımın tura ait hedefi karşıladığına bakar. Eğer takımın puanı ReplicatedStorage ⟩ TEAM_SCORE_LIMIT içindeki TEAM_SCORE_LIMIT değişkeninden daha düşükse, sunucu, bir takım tekrar puan kazanana kadar beklemeye devam eder.
Ancak, bir takımın puanı TEAM_SCORE_LIMIT değişkenine ulaştığında, betik, oyuncunun adını ve takımını içeren bir roundWinnerRemote olay örneğini ateşler.
Rounds-- Her puandan sonra turun bitip bitmediğini kontrol etlocal team: Teamlocal score: number = 0while score < TEAM_SCORE_LIMIT doteam, score = Scoring.teamScoreChanged:Wait()end-- Kazanan takımı gösterfor _, player in Players:GetPlayers() do-- Tur sonunda oyuncunun hangi takımda olduğunu gönder-- çünkü oyuncunun takımı kaldırılmak üzere, dolayısıyla istemci-- kendi takımını kontrol edemezroundWinnerRemote:FireClient(player, team, player.Team)end
Her istemcideki ReplicatedStorage ⟩ RoundResultsGuiSetup betiği, bu roundWinnerRemote olay örneğini dinler ve böylece:
- Tur sonuçlarını ve oyuncunun kazanan takımdan olup olmadığını duyuran bir StarterGui ⟩ RoundResultsGui UI ekranı görüntüler.
- Bir zafer veya yenilgi ses dosyası çalar.
Örneğin, bir oyuncu kazanan puanı atan takımda ise, tur sonuçları hakkında zafer metni görüntüleyen bir UI ekranı ve neşeli bir ses çalan bir ses dosyası alırlar. Aksine, bir oyuncu kazanan puanı atan takımda değilse, yenilgi metni görüntüleyen bir UI ekranı ve korkutucu bir ses çalan bir ses dosyası alır.
RoundResultsGuiSetup
local function onRoundWinner(winner: Team, localTeam: Team?)
local victoryDefeatText = "Tur sona erdi!"
if localTeam then
-- Takımımız kazandıysa, Zafer! görüntüleyeceğiz. Aksi takdirde Yenilgi...
local isVictory = winner == localTeam
if isVictory then
victorySound:Play()
victoryDefeatText = VICTORY_TEXT
else
defeatSound:Play()
victoryDefeatText = DEFEAT_TEXT
end
end
Takımları sıfırla
Aynı zamanda ServerScriptService ⟩ Gameplay ⟩ Rounds, bir takımın tur hedefine ulaştığını doğruladıktan ve her oyuncu için uygun UI görüntüsünü tetikledikten sonra, tüm oyuncuları arenadan lobideki yerlerine alarak turdan çıkarır. Bu, turun resmi olarak sona erme ve her iki takımı sıfırlama sürecini başlatır.
Doğma Konumlarını Yapılandır bölümünde bahsedilen aynı mantığı kullanarak Rounds, Neutral doğum yerinin Neutral özelliğini true olarak ayarlar, böylece oyuncular takım statülerine bakılmaksızın orada doğabilirler. Bu, oyuncuların turdan ayrıldıktan sonra doğabileceği tek yerin lobby olmasını sağlar.
Rounds-- Herkesi lobide gönderplayerAddedConnection:Disconnect()neutralSpawn.Neutral = truespawnPlayersInLobby(Players:GetPlayers())
On saniyelik bir beklemeden sonra, Rounds sunucu betiği, herkesin puanlarını sıfırlayıp yeni takımlara sıralanarak döngüyü yeniden başlatır. Örnek bu döngüyü, sunucuda hiçbir oyuncu kalmayana kadar tekrar eder.
Artık oyuncular kendi takımlarıyla haritaya doğabilir ve tam bir tur oynayabilirler. Bir sonraki bölüm, her blasterın davranışının arkasındaki betikleri öğretir.