การเพิ่มรอบ ช่วยให้คุณสามารถจัดโครงสร้างการเล่นเกมให้มีเฟสที่มีจุดเริ่มต้นและจุดสิ้นสุดที่ชัดเจน เพื่อให้ผู้เล่นสามารถวัดความก้าวหน้าและมีโอกาสในการเล่นเกมที่เท่ากันในระยะเวลาสั้น ๆ ซึ่งเป็นสิ่งที่สำคัญมากสำหรับการเล่นเกมแบบทีม เนื่องจากมันเปิดโอกาสให้ผู้เล่นปรับเปลี่ยนสไตล์การเล่นขึ้นอยู่กับว่าใครอยู่ในทีมของพวกเขาในรอบนั้น
โดยใช้ ตัวอย่างประสบการณ์เลเซอร์แท็ก เป็นแนวทาง ส่วนนี้ของบทเรียนจะสอนคุณเกี่ยวกับการใช้และปรับแต่งฟีเจอร์ในตัวของ Roblox เพื่อตั้งโครงสร้างสำหรับแต่ละรอบ รวมถึงแนวทางในการเขียนสคริปต์เกี่ยวกับ:
- การเริ่มรอบโดยการรีเซ็ตคะแนนของแต่ละบุคคลและทีม จากนั้นสปอนผู้เล่นไปยังโซนสปอนของทีมของพวกเขา
- ปรับแต่งตัวแปรที่กำหนดวัตถุประสงค์สำหรับรอบที่ด้านบนของหน้าจอผู้เล่นแต่ละคน
- ติดตามการมีส่วนร่วมของคะแนนผู้เล่นสำหรับคะแนนทีมของพวกเขา
- เรียก UI ที่ไม่ซ้ำกันขึ้นอยู่กับว่าทีมของผู้เล่นชนะหรือแพ้ในรอบ
- สิ้นสุดรอบโดยการตัดการเชื่อมต่อผู้เล่นและสปอนพวกเขาในล็อบบี้ที่เป็นกลาง
หลังจากที่คุณทำส่วนนี้เสร็จสิ้น คุณจะได้เรียนรู้วิธีการใช้พฤติกรรมของปืนที่มีความแม่นยำและน่าพอใจสำหรับผู้เล่น

เริ่มลูป
ServerScriptService ⟩ Gameplay ⟩ Rounds จัดการตรรกะส่วนใหญ่ในการนำรอบมาใช้ และเริ่มต้นโดยการเรียกใช้ฟังก์ชัน startRoundLoopAsync() เพื่อทำเครื่องหมายจุดเริ่มต้นของรอบลูป ขณะที่ผู้เล่นเข้าร่วมล็อบบี้และรอที่จะจัดเรียงเป็นทีม startRoundLoopAsync() จะเรียกฟังก์ชัน resetScores() ใน ServerScriptService ⟩ Gameplay ⟩ Scoring เพื่อรีเซ็ตทั้งกระดานคะแนนและคะแนนทีม
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
ตอนนี้เมื่อทุกคนเริ่มจากคะแนนศูนย์ startRoundLoopAsync() จะตั้งค่าคุณสมบัติของตำแหน่งสปอนร์ Neutral Neutral เป็น false เพื่อให้เฉพาะผู้เล่นที่มีคุณสมบัติ Team.Color เดียวกันกับคุณสมบัติ TeamColor ของตำแหน่งสปอนร์สามารถสปอนที่นั่นได้ เนื่องจากคุณสมบัติ TeamColor ของตำแหน่งสปอนร์ถูกตั้งค่าเป็น white แทนทีมตัวอย่างที่เป็นมินต์หรือสีชมพู ดังนั้นการกำหนดค่านี้จึงป้องกันไม่ให้ผู้เล่นทั้งหมดสปอนหรือสปอนใหม่ที่นั่นในขณะที่รอบยังคงดำเนินอยู่
สำหรับผู้เล่นที่อยู่ในล็อบบี้ในขณะนี้ startRoundLoopAsync() จะส่งผู้เล่นทั้งหมดที่อยู่ในประสบการณ์ไปยังฟังก์ชัน spawnPlayersInMap ใน ServerScriptService ⟩ Gameplay ⟩ Rounds ⟩ spawnPlayersInMap เพื่อจัดเรียงและปรับสมดุลผู้เล่นทั้งหมดให้มีจำนวนใกล้เคียงกัน
สำหรับผู้เล่นใหม่ที่เข้าร่วมประสบการณ์หลังจากกลุ่มล็อบบี้ถูกจัดเรียงในทีม startRoundLoopAsync() จะฟังเหตุการณ์ Players.PlayerAdded:Connect จากนั้นเรียกฟังก์ชัน spawnPlayersInMap อีกครั้งเพื่อลงทะเบียนพวกเขาในทีมที่มีจำนวนผู้เล่นน้อยที่สุด สำหรับข้อมูลเพิ่มเติมเกี่ยวกับกระบวนการนี้ ดูที่ กำหนดค่าตำแหน่งสปอนร์ จากส่วนก่อนหน้านี้ในบทเรียน การสปอนน์และการเกิดใหม่
Rounds
-- สปอนผู้เล่นทั้งหมดในแผนที่
neutralSpawn.Neutral = false
spawnPlayersInMap(Players:GetPlayers())
-- สปอนผู้เล่นใหม่ในแผนที่เมื่อพวกเขาเข้าร่วม
local playerAddedConnection = Players.PlayerAdded:Connect(function(player: Player)
spawnPlayersInMap({ player })
end)
ตั้งวัตถุประสงค์
ตอนนี้ผู้เล่นแต่ละคนอยู่ในสนามรบกับเพื่อนร่วมทีมของพวกเขา ประสบการณ์จำเป็นต้องให้คำแนะนำเกี่ยวกับสิ่งที่จะทำเพื่อประสบความสำเร็จในรอบ ตัวอย่างประสบการณ์เลเซอร์แท็กจัดการความต้องการนี้ด้วยการให้คำแนะนำวัตถุประสงค์ที่ด้านบนของหน้าจอผู้เล่นแต่ละคนพร้อมกับคำแนะนำที่ชัดเจนเกี่ยวกับสิ่งที่ทีมต้องทำเพื่อชนะ

แม้ว่าคุณจะสามารถเรียนรู้เพิ่มเติมเกี่ยวกับวิธีการกำหนดค่าและแสดง UI วัตถุประสงค์ ในหลักสูตร UI แต่ส่วนนี้จะเน้นที่วิธีการนำเสนอเป้าหมายเมื่อเริ่มรอบ โดยเริ่มต้นด้วยการตั้งค่าจำนวนคะแนนที่แต่ละทีมต้องทำให้สำเร็จในรอบ
แม้ว่าคำแนะนำวัตถุประสงค์ในเวลาทำงานจะบอกผู้เล่นว่าพวกเขาต้องทำคะแนนสามคะแนนเพื่อชนะ หากคุณตรวจสอบคำแนะนำใน StarterGui ⟩ HUDGui คุณจะเห็นว่ามันมีการกำหนดค่า "%d" สำหรับค่าคะแนน

"%d" เป็นสตริงที่เป็นตัวแทนซึ่งคุณสามารถเพิ่มหรือลดได้ทุกเมื่อเพื่อตอบสนองความต้องการการเล่นของคุณเองโดยการอัปเดตตัวแปร TEAM_SCORE_LIMIT ใน ReplicatedStorage ⟩ TEAM_SCORE_LIMIT ตัวอย่างเช่น หากคุณตั้งค่านี้เป็นตัวเลขที่สูงผิดปกติ 200 คำแนะนำและตัวนับคะแนนทีมจะอัปเดตตามนั้น
TEAM_SCORE_LIMITlocal TEAM_SCORE_LIMIT = 200 -- บรรทัดที่อัปเดต อย่าลืมเปลี่ยนกลับreturn TEAM_SCORE_LIMIT

การอัปเดตตัวแปรอย่างง่ายนี้ใช้งานได้ในเวลาทำงาน เนื่องจากเมื่อเริ่มรอบ, ReplicatedStorage ⟩ HUDGuiSetup ⟩ SetObjective ต้องการโมดูลสคริปต์ TEAM_SCORE_LIMIT เพื่อให้สามารถเปลี่ยนสตริงตัวแทนในวัตถุ TextLabel ของ UI วัตถุประสงค์
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
ติดตามคะแนน
ตอนนี้ที่ผู้เล่นมีเป้าหมายสำหรับรอบ ประสบการณ์จำเป็นต้องติดตามคะแนนของแต่ละทีมจนกว่าพวกเขาจะบรรลุวัตถุประสงค์ ขณะที่พฤติกรรมเริ่มต้นของบริการ Teams จะจัดกลุ่มผู้เล่นแต่ละคนให้ใต้ทีมของพวกเขาและบวกคะแนนจากการมีส่วนร่วมของผู้เล่นแต่ละคนเข้ากับคะแนนทีม นั้นๆ การเก็บรักษาและติดตามคะแนนในตำแหน่งแยกต่างหากสำหรับการเล่นที่มีรอบเป็นสิ่งสำคัญ เนื่องจากหากผู้เล่นทำคะแนนแล้วออกจากเกมก่อนที่รอบจะจบ คะแนนของเขาจะลดลงจากกระดานคะแนนทันทีที่เขาหรือเธอตัดการเชื่อมต่อจากประสบการณ์
เพื่อให้แน่ใจว่าสิ่งนี้จะไม่เกิดขึ้นและทุกคะแนนที่ส่งเสริมเป้าหมายของทีมจะยังคงอยู่ ReplicatedStorage ⟩ HUDGuiSetup ⟩ StartSyncingTeamPoints จะเก็บคะแนนทั้งหมดแยกต่างหากภายใต้คุณลักษณะ teamPoints ในบริการ Teams เมื่อ teamPoints เพิ่มขึ้น โมดูลสคริปต์นี้จะเรียกฟังก์ชัน startSyncingTeamPoints เพื่อค้นหาตัวนับทีม Class.GuiObjects ภายใน UI วัตถุประสงค์
เมื่อมันพบ TeamACounter และ TeamBCounter มันจะดึงคุณลักษณะ teamColor ของพวกเขาซึ่งเกี่ยวข้องกับโซนสปอนของทีม: TeamACounter แสดงคะแนนของทีมสีเขียว และ TeamBCounter ติดตามคะแนนของทีมสีชมพู
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)
โมดูลสคริปต์จะเรียกฟังก์ชัน getTeamFromTeamColor เพื่อยืนยันว่าคุณลักษณะ teamColor ของ TeamACounter mint และ TeamBCounter carnation pink ตรงกับคุณสมบัติ Team.Color ที่อยู่ใต้บริการ Teams ถ้าใช่ มันจะคืนค่าทั้งสองทีม
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
เมื่อเกิดเหตุการณ์นี้, startSyncingTeamPoints จะตั้งค่าตัวนับทีมทั้งสองของ TextLabel ให้ตรงกับค่า teamPoints ที่เกี่ยวข้องของพวกเขา และจะอัปเดตพวกเขาเมื่อใดก็ตามที่ผู้เล่นทำคะแนนโดยการแท็กผู้เล่นอีกคนหนึ่งจากทีมตรงข้าม
StartSyncingTeamPoints
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
team:GetAttributeChangedSignal(GuiAttribute.teamPoints):Connect(function()
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
ทุกอย่างในส่วนนี้จนถึงตอนนี้เน้นว่าการติดตามคะแนนบนหน้าจอของผู้เล่นเป็นอย่างไร แต่เป็นสิ่งสำคัญที่จะต้องทบทวนตรรกะที่จัดการติดตามคะแนนบนเซิร์ฟเวอร์เพื่อให้รู้ว่าเมื่อใดที่ทีมบรรลุวัตถุประสงค์และชนะรอบ หากคุณกลับไปที่ ServerScriptService ⟩ Gameplay ⟩ Scoring คุณจะเห็นว่าโมดูลสคริปต์เริ่มต้นด้วยการสร้างเหตุการณ์ที่สามารถเชื่อมต่อได้ ซึ่งจะเกิดขึ้นทุกครั้งที่ผู้เล่นทำคะแนน
Scoringlocal teamScoreChangedBindable = Instance.new("BindableEvent")local Scoring = {teamScoreChanged = teamScoreChangedBindable.Event,}
จากนั้นมันจะเรียกฟังก์ชัน incrementScore ซึ่งทำงานดังต่อไปนี้:
- ดึงคะแนนเฉพาะของผู้เล่นในกระดานคะแนนและเพิ่มหนึ่ง
- เรียกใช้งานเหตุการณ์ที่เชื่อมต่อได้ previously ที่กล่าวถึงโดยมีทีมผู้เล่นและคะแนนของพวกเขา
กระบวนการนี้มีประสิทธิภาพในการรักษาคะแนนเฉพาะบุคคลของผู้เล่นทั้งทางไคลเอนต์และเซิร์ฟเวอร์ให้ตรงกันเกี่ยวกับคะแนนของผู้เล่นแต่ละคนและคะแนนของทีมของพวกเขา
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
แสดงผลลัพธ์
เมื่อผู้เล่นแท็กกันและทำคะแนนให้กับทีมของพวกเขา, ServerScriptService ⟩ Gameplay ⟩ Rounds จะตรวจสอบว่า ทีมที่ทำคะแนนได้มีคะแนนถึงวัตถุประสงค์ของรอบหรือไม่ ถ้าคะแนนทีมของพวกเขาต่ำกว่าตัวแปร TEAM_SCORE_LIMIT ใน ReplicatedStorage ⟩ TEAM_SCORE_LIMIT เซิร์ฟเวอร์จะรอจนกว่าหนึ่งในทีมจะทำคะแนนอีกครั้ง
อย่างไรก็ตาม เมื่อคะแนนของทีมใดทีมหนึ่งถึงตัวแปร TEAM_SCORE_LIMIT สคริปต์จะสร้างเหตุการณ์ roundWinnerRemote พร้อมกับชื่อผู้เล่นและทีมของพวกเขา
Rounds-- ตรวจสอบว่ารอบเสร็จสิ้นหลังจากแต่ละคะแนนlocal team: Teamlocal score: number = 0while score < TEAM_SCORE_LIMIT doteam, score = Scoring.teamScoreChanged:Wait()end-- แสดงทีมที่ชนะfor _, player in Players:GetPlayers() do-- ส่งว่าใครอยู่ในทีมใดเมื่อสิ้นสุดรอบ-- เนื่องจากทีมของผู้เล่นกำลังจะถูกลบ ดังนั้นไคลเอนต์-- จะไม่สามารถตรวจสอบทีมของตนเองได้roundWinnerRemote:FireClient(player, team, player.Team)end
สคริปต์ ReplicatedStorage ⟩ RoundResultsGuiSetup บนแต่ละไคลเอนต์จะฟังเหตุการณ์ roundWinnerRemote เพื่อให้สามารถ:
- แสดง UI หน้าจอ StarterGui ⟩ RoundResultsGui ที่ประกาศผลลัพธ์ของรอบและถ้าผู้เล่นอยู่ในทีมที่ชนะ
- เล่นเพลงเสียงชัยชนะหรือเสียงพ่ายแพ้
ตัวอย่างเช่น หากผู้เล่นอยู่ในทีมที่ทำคะแนนชัยชนะ เขาจะได้รับการตอบกลับหลายรูปแบบเกี่ยวกับผลลัพธ์ของรอบในรูปแบบของ UI หน้าจอที่แสดงข้อความชัยชนะ และเสียงเพลงที่เล่นเสียงดีใจ ในทางกลับกัน หากผู้เล่นไม่ได้อยู่ในทีมที่ทำคะแนนชัยชนะ เขาจะได้รับ UI หน้าจอที่แสดงข้อความพ่ายแพ้ และเสียงเพลงที่เล่นเสียงที่น่าหวาดหวั่น
RoundResultsGuiSetup
local function onRoundWinner(winner: Team, localTeam: Team?)
local victoryDefeatText = "จบรอบแล้ว!"
if localTeam then
-- ถ้าทีมของเราได้รับชัยชนะ เราจะแสดง Victory! มิฉะนั้นจะแสดง Defeat...
local isVictory = winner == localTeam
if isVictory then
victorySound:Play()
victoryDefeatText = VICTORY_TEXT
else
defeatSound:Play()
victoryDefeatText = DEFEAT_TEXT
end
end
รีเซ็ตทีม
ในขณะที่ ServerScriptService ⟩ Gameplay ⟩ Rounds ยืนยันว่าทีมใดทีมหนึ่งได้บรรลุวัตถุประสงค์ของรอบและสร้าง UI แสดงผลที่เหมาะสมสำหรับผู้เล่นแต่ละคน มันยังส่งผู้เล่นทั้งหมดจากสนามไปยังล็อบบี้โดยการตัดการเชื่อมต่อพวกเขาจากรอบนี้ นี่เริ่มต้นกระบวนการสิ้นสุดรอบอย่างเป็นทางการและรีเซ็ตทั้งสองทีม
โดยใช้ตรรกะเดียวกันใน กำหนดค่าตำแหน่งสปอนร์, Rounds จะตั้งค่าคุณสมบัติ Neutral ของตำแหน่งสปอนร์ Neutral เป็น true เพื่อให้ผู้เล่นสามารถสปอนที่นั่นไม่สนใจสถานะทีมของพวกเขา ซึ่งหมายความว่าล็อบบี้กลายเป็นสถานที่เดียวที่ผู้เล่นสามารถสปอนหลังจากถูกตัดการเชื่อมต่อจากรอบ
Rounds-- ส่งทุกคนไปล็อบบี้playerAddedConnection:Disconnect()neutralSpawn.Neutral = truespawnPlayersInLobby(Players:GetPlayers())
หลังจากรอสิบวินาทีเพื่อทำให้ระยะหยุดชั่วคราว ความสคริปต์ Rounds จะเริ่มลูปใหม่โดยการรีเซ็ตคะแนนของทุกคนและจัดเรียงพวกเขาไปยังทีมใหม่ ตัวอย่างระเบียบนี้จะทำซ้ำกระบวนการรอบแบบวนซ้ำอีกจนกว่าจะไม่มีผู้เล่นอยู่ภายในเซิร์ฟเวอร์
ตอนนี้ที่ผู้เล่นสามารถสปอนเข้าสู่แผนที่กับทีมของตนเองและเล่นรอบเต็มแล้ว ส่วนถัดไปจะสอนเกี่ยวกับสคริปต์ที่อยู่เบื้องหลังพฤติกรรมของปืนแต่ละกระบอก