Tur bölümleri ekleme

*Bu içerik, yapay zekâ (beta) kullanılarak çevrildi ve hatalar içerebilir. Sayfayı İngilizce görüntülemek için buraya tıkla.

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

ServerScriptServiceGameplayRounds, 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, ServerScriptServiceGameplayScoring 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 ServerScriptServiceGameplayRoundsspawnPlayersInMap 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, StarterGuiHUDGui 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 ReplicatedStorageTEAM_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_LIMIT

local TEAM_SCORE_LIMIT = 200 -- güncellenen satır, lütfen geri değiştirin
return TEAM_SCORE_LIMIT

Bu basit değişken güncellemesi çalışma zamanında işler çünkü tur başlamadan önce ReplicatedStorageHUDGuiSetupSetObjective 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, ReplicatedStorageHUDGuiSetupStartSyncingTeamPoints 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. ServerScriptServiceGameplayScoring 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.

Scoring

local 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 takımını ve Teams servisindeki Team nesnesinde mevcut teamPoints değerini alır ve bir artırır.
  • 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, ServerScriptServiceGameplayRounds hangi takımın tura ait hedefi karşıladığına bakar. Eğer takımın puanı ReplicatedStorageTEAM_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 et
local team: Team
local score: number = 0
while score < TEAM_SCORE_LIMIT do
team, score = Scoring.teamScoreChanged:Wait()
end
-- Kazanan takımı göster
for _, 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 edemez
roundWinnerRemote:FireClient(player, team, player.Team)
end

Her istemcideki ReplicatedStorageRoundResultsGuiSetup 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 StarterGuiRoundResultsGui 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.

Zafer geri bildirimi
Yenilgi geri bildirimi
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 ServerScriptServiceGameplayRounds, 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önder
playerAddedConnection:Disconnect()
neutralSpawn.Neutral = true
spawnPlayersInLobby(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.

©2026 Roblox Corporation. Roblox, the Roblox logo and Powering Imagination are among our registered and unregistered trademarks in the U.S. and other countries.