Turlar Ekle

*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ı için periyodik fırsatlar elde edebilmeleri için oyun akışını net bir başlangıç ve bitiş noktası olan aşamalara yapılandırmanıza olanak tanır. Bu, takım tabanlı oyunlar için özellikle önemlidir çünkü oyuncuların bu turda takımlarında kim olduğuna bağlı olarak oyun tarzlarını değiştirme şansı sunar.

örnek lazer tag oyunu referans alarak, bu öğretici 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çerir:

  • Bir turu başlatmak için bireysel ve takım puanlarını sıfırlamak, ardından oyuncuları takım spawn bölgelerine yerleştirmek.
  • Her oyuncunun ekranının üst kısmında tur için hedefi belirleyen değişkenleri özelleştirmek.
  • Oyuncu puan katkılarını takım puanı için takip etmek.
  • Oyuncunun takımı turu kazanıp kazanmadığına bağlı olarak benzersiz UI ekranlarını tetiklemek.
  • Bir turu, oyuncuları ayırarak ve onları nötr lobide yeniden doğurarak sonlandırmak.

Bu bölümü tamamladıktan sonra, hem doğru hem de oyuncular için 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ı işaretlemek için startRoundLoopAsync() fonksiyonunu çağırarak başlar. Oyuncular lobide katılırken ve bir takıma ayrılmayı beklerken, startRoundLoopAsync() ServerScriptServiceGameplayScoring içindeki 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

Herkes sıfır puandan başladığına göre, startRoundLoopAsync() daha sonra Neutral spawn konumunun Neutral özelliğini false olarak ayarlayarak yalnızca spawn konumunun TeamColor özelliği ile aynı Team.Color özelliğine sahip oyuncuların orada doğmasına izin verir. Spawn konumunun TeamColor özelliği, örneğin mint veya karanfil pembe takımları yerine beyaz olarak ayarlandığı için, bu yapılandırma, bir tur aktifken tüm oyuncuların orada doğmasını veya yeniden doğmasını engeller.

Lobide bulunan oyuncular için, startRoundLoopAsync() mevcut oyundaki tüm oyuncuları ServerScriptServiceGameplayRoundsspawnPlayersInMap içindeki spawnPlayersInMap fonksiyonuna geçirerek herkesin yaklaşık olarak aynı sayıda oyuncuya sahip bir takıma ayrılmasını sağlar.

Lobi grubuna ayrıldıktan sonra oyuna katılan yeni oyuncular için, startRoundLoopAsync() Players.PlayerAdded:Connect olayını dinler ve ardından spawnPlayersInMap fonksiyonunu tekrar çağırarak onları en az oyuncuya sahip takıma ekler. Bu süreç hakkında daha fazla bilgi için, önceki Doğurma ve Yeniden Doğurma bölümündeki Doğurma Yerlerini Yapılandır kısmına bakın.

Rounds
-- Haritada tüm oyuncuları doğur
neutralSpawn.Neutral = false
spawnPlayersInMap(Players:GetPlayers())
-- Oyuncular haritaya katıldıklarında yeni oyuncuları doğur
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, oyunun tur içinde başarılı olmak için ne yapmaları gerektiğine dair talimatlar sağlaması gerekiyor. Örnek lazer tag oyunu, bu gereksinimi her oyuncunun ekranının üst kısmında takımın kazanmak için ne yapması gerektiğine dair net bir rehberlik sağlayan bir hedef istemi sunarak ele alır.

UI Müfredatında Hedef UI bileşenini nasıl yapılandıracağınızı ve görüntüleyeceğinizi daha fazla öğrenebilirsiniz, bu bölüm ise tur başladığında hedefi uygulamanın nasıl yapılacağına odaklanmaktadır. Bu, her takımın turu tamamlamak için ihtiyaç duyduğu puan miktarını ayarlamakla başlar.

Çalışma zamanında hedef isteminin oyunculara kazanmak için üç puan almaları gerektiğini bildirmesine rağmen, StarterGuiHUDGui içindeki isteme baktığınızda, bunun yerine yapılandırılabilir bir "%d" içerdiğini görebilirsiniz.

"%d" bir yer tutucu dizesidir ve istediğiniz zaman kendi oyun gereksinimlerinizi karşılamak 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ı sayacı buna göre güncellenir.

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

Bu basit değişken güncellemesi çalışma zamanında işe yarar çünkü tur başladığında ReplicatedStorageHUDGuiSetupSetObjective, UI Hedefinin TextLabel nesnesindeki yer tutucu dizesini değiştirmek için TEAM_SCORE_LIMIT modül betiğini gerektirir.

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 tur için bir hedefi olduğuna göre, oyun her takımın puanını hedefe ulaşana kadar takip etmelidir. Teams hizmetinin varsayılan davranışı, her oyuncuyu otomatik olarak takımlarının altına gruplandırır ve her oyuncunun katkılarını takım puanına eklerken, tur tabanlı oyunlar için puanları ayrı bir yerde saklamak ve izlemek önemlidir çünkü bir oyuncu puan alıp tur bitmeden ayrılırsa, katkısı oyundan ayrıldığında liderlik tablosundan düşer.

Bunun olmasını önlemek ve takım hedefine yönelik her katkının korunmasını sağlamak için, ReplicatedStorageHUDGuiSetupStartSyncingTeamPoints, tüm puanları Teams hizmetindeki 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'ı bulduğunda, takım spawn bölgeleriyle ilişkili 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 getTeamFromTeamColor fonksiyonunu çağırarak TeamACounter'ın mint teamColor niteliği ile TeamBCounter'ın carnation pink teamColor niteliğinin Teams hizmetindeki karşılık gelen Team.Color özellikleriyle eşleşip eşleşmediğini doğrular. Eğer öyleyse, her iki takımı da döndürür.

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 karşı takımda başka bir oyuncuyu etiketleyerek puan aldıkça 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 şimdiye kadar her şey, oyuncunun ekranında puanları takip etmeye odaklanmışken, sunucuda puanları takip eden mantığı gözden geçirmek önemlidir, böylece bir takım hedefe ulaştığında ve turu kazandığında bunu bilmektedir. ServerScriptServiceGameplayScoring bölümüne geri döndüğünüzde, modül betiğinin her oyuncu bir puan aldığında ateşleyecek bir bağlanabilir olay oluşturduğunu 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 hizmetindeki Team nesnesindeki mevcut teamPoints değerini alır ve bir ekler.
  • Oyuncunun liderlik tablosundaki bireysel puanını alır ve bir ekler.
  • Daha önce bahsedilen bağlanabilir olayı, oyuncunun takımı ve puanı ile ateşler.

Bu süreç, hem istemci hem de sunucu arasında oyuncuların bireysel puanları ve takım puanları hakkında uyumlu kalmayı etkili 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öster

Oyuncular birbirlerini etiketleyip takımları için puan alırken, ServerScriptServiceGameplayRounds, puan alan takımın tur hedefini karşılayıp karşılamadığını kontrol eder. Eğer takım puanı ReplicatedStorageTEAM_SCORE_LIMIT içindeki TEAM_SCORE_LIMIT değişkeninden daha düşükse, sunucu bir takım tekrar puan alana kadar beklemeye devam eder.

Ancak, bir takımın puanı TEAM_SCORE_LIMIT değişkenine ulaştığında, betik bir roundWinnerRemote olay örneğini oyuncunun adı ve takımı ile 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
-- Oyuncunun tur sonunda hangi takımda olduğunu gönder
-- çünkü oyuncunun takımı kaldırılmak üzere, bu yüzden istemci
-- kendi takımını kontrol edemeyecek
roundWinnerRemote:FireClient(player, team, player.Team)
end

ReplicatedStorageRoundResultsGuiSetup betiği, her istemcide bu roundWinnerRemote olay örneğini dinler, böylece:

  • Tur sonuçlarını ve oyuncunun kazanan takımda olup olmadığını duyuran benzersiz bir StarterGuiRoundResultsGui UI ekranı görüntüleyebilir.
  • Bir zafer veya yenilgi ses kaydını çalabilir.

Örneğin, bir oyuncu kazanan puanı alan 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 kaydı ile birden fazla geri bildirim alır. Tersine, bir oyuncu kazanan puanı alan takımda değilse, yenilgi metni görüntüleyen bir UI ekranı ve korkutucu bir ses çalan bir ses kaydı alır.

Zafer geri bildirimi
Yenilgi geri bildirimi
RoundResultsGuiSetup
local function onRoundWinner(winner: Team, localTeam: Team?)
local victoryDefeatText = "Tur sona erdi!"
if localTeam then
-- Eğer takımımız kazandıysa, Zafer! göstereceğ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

ServerScriptServiceGameplayRounds, bir takımın tur hedefini karşıladığını doğrularken ve her oyuncu için uygun UI görüntülemesini tetiklerken, aynı zamanda tüm oyuncuları arenadan lobideki yere taşır ve onları turdan ayırır. Bu, turun resmi olarak sona erme sürecini başlatır ve her iki takımı da sıfırlar.

Doğurma Yerlerini Yapılandır bölümündeki aynı mantığı kullanarak, Rounds daha sonra Neutral spawn konumunun Neutral özelliğini true olarak ayarlayarak oyuncuların takım durumlarına bakılmaksızın orada doğabilmelerini sağlar. Bu, lobinin, oyuncuların turdan ayrıldıktan sonra doğabileceği tek yer haline gelir.

Rounds
-- Herkesi lobide gönder
playerAddedConnection:Disconnect()
neutralSpawn.Neutral = true
spawnPlayersInLobby(Players:GetPlayers())

On saniyelik bir ara bekledikten sonra, Rounds sunucu betiği daha sonra herkesin puanlarını sıfırlayarak ve yeni takımlara ayırarak döngüyü tekrar başlatır. Örnek, sunucuda hiç oyuncu kalmayana kadar bu döngüsel tur sürecini tekrarlar.

Artık oyuncular kendi takımlarıyla haritaya doğabilir ve tam bir tur oynayabilirler, bir sonraki bölümde her blaster'ın davranışının arkasındaki betikleri öğreneceksiniz.

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