การเกิด คือกระบวนการในการสร้างวัตถุหรือบุคคลในประสบการณ์ และ การเกิดใหม่ คือกระบวนการในการนำวัตถุหรือบุคคลกลับเข้าสู่ประสบการณ์หลังจากที่พวกเขาพบเงื่อนไขการกำจัด เช่น สุขภาพของตัวละครลดลงถึงศูนย์หรือหลุดออกจากแผนที่ ทั้งสองกระบวนการมีความสำคัญเพราะทำให้ผู้เล่นสามารถเข้าร่วมประสบการณ์ของคุณและสามารถเล่นต่อเพื่อพัฒนาทักษะของพวกเขา
ในการใช้ ตัวอย่างประสบการณ์เลเซอร์แท็ก เป็นแนวทาง ส่วนนี้ของบทแนะนำจะสอนให้คุณรู้วิธีการใช้และปรับแต่งฟีเจอร์ที่มีอยู่ใน Roblox เพื่อตรวจสอบการเกิดและการเกิดใหม่ รวมถึงแนวทางการเขียนสคริปต์เกี่ยวกับ:
- การกำหนดตำแหน่งการเกิดเพื่อให้ผู้เล่นสามารถเกิดในโซนการเกิดของทีมของตนเท่านั้น
- การเพิ่มผู้เล่นใหม่และตัวละครของพวกเขาเข้าสู่รอบเมื่อพวกเขาเข้าร่วมประสบการณ์
- การปรับแต่งสนามแรงที่ป้องกันความเสียหายเมื่อผู้เล่นเกิดและเกิดใหม่
- การจัดการสถานะของไคลเอนต์เพื่อให้การเล่นเกมทำงานอย่างถูกต้องในช่วงเวลาที่เหมาะสม
- การเกิดใหม่ของตัวละครหลังจากที่พวกเขาถูกทำให้ออกจากรอบ
- การดำเนินการเล็กๆ น้อยๆ ที่สำคัญสำหรับการตั้งค่าการเล่นเกมและพารามิเตอร์ของตัวละคร
ส่วนนี้มีสคริปต์มากมาย แต่แทนที่คุณจะเขียนทุกอย่างจากศูนย์เมื่อสร้างประสบการณ์ มันส่งเสริมให้คุณใช้ส่วนประกอบที่มีอยู่ ทำซ้ำอย่างรวดเร็ว และหาว่าระบบใดต้องการการปรับใช้งานเฉพาะเพื่อตรงตามวิสัยทัศน์ของคุณ หลังจากที่คุณทำส่วนนี้เสร็จสิ้น คุณจะเรียนรู้วิธีการใช้งานการเล่นเกมแบบรอบซึ่งติดตามคะแนน ตรวจสอบสถานะของผู้เล่น และแสดงผลลัพธ์ของรอบ
กำหนดตำแหน่งการเกิด
หากคุณลองทดสอบประสบการณ์ในตอนนี้ ผู้เล่นทั้งหมดจะเกิดแบบสุ่มที่วัตถุ SpawnLocation ในโซนการเกิดของทีมสีเขียว หรือวัตถุ SpawnLocation ในโซนการเกิดของทีมสีชมพู นี่เป็นปัญหาการเล่นเกมที่ผู้เล่นสามารถติดป้ายกันในแต่ละโซนการเกิดได้ทันทีที่สนามแรงของฝ่ายตรงข้ามหายไป
เพื่อแก้ปัญหานี้ ตัวอย่างประสบการณ์เลเซอร์แท็กได้กำหนดตำแหน่งการเกิดทั้งสองแห่งโดยตั้งค่า Neutral เป็น false เพื่อลดความสามารถของผู้เล่นทีมตรงข้ามในการเกิดในโซนการเกิดที่ไม่ถูกต้อง และตั้งค่า TeamColor เป็นค่าตรงกับ Team.Color จาก กำหนดสีทีม ในส่วนก่อนหน้านี้ของบทแนะนำ:


เมื่อผู้เล่นเข้าร่วมประสบการณ์ ServerScriptService ⟩ Gameplay ⟩ Rounds ⟩ spawnPlayersInMap จะตรวจสอบว่ามีผู้เล่นอยู่ในแต่ละทีมกี่คน แล้วส่งกลับทีมที่มีจำนวนผู้เล่นน้อยที่สุด
spawnPlayersInMap
local function getSmallestTeam(): Team
local teams = Teams:GetTeams()
-- จัดเรียงทีมในลำดับที่เพิ่มขึ้นจากน้อยไปหามาก
table.sort(teams, function(teamA: Team, teamB: Team)
return #teamA:GetPlayers() < #teamB:GetPlayers()
end)
-- ส่งคืนทีมที่เล็กที่สุด
return teams[1]
end
เมื่อพบทีมที่มีจำนวนผู้เล่นน้อยที่สุดแล้ว มันจะจัดผู้เล่นในทีมนั้น ตั้งค่า Player.Neutral เป็น false เพื่อให้ผู้เล่นสามารถเกิดและเกิดใหม่ได้ที่ตำแหน่งการเกิดของทีมของตนเท่านั้น จากนั้นตั้งค่า PlayerState ของพวกเขาเป็น SelectingBlaster ซึ่งคุณจะเรียนรู้เพิ่มเติมเกี่ยวกับภายหลังในบทแนะนำ
spawnPlayersInMap
local function spawnPlayersInMap(players: { Player })
for _, player in players do
player.Team = getSmallestTeam()
player.Neutral = false
player:SetAttribute(PlayerAttribute.playerState, PlayerState.SelectingBlaster)
task.spawn(function()
player:LoadCharacter()
end)
end
end
หากคุณตรวจสอบ Workspace ⟩ World ⟩ Map ⟩ Spawns คุณจะเห็นว่ามีตำแหน่งการเกิดอีกหนึ่งที่ในแผนที่: NeutralSpawn ตำแหน่งการเกิดนี้แตกต่างจากตำแหน่งอื่นๆ เพราะมันไม่มีค่าของ TeamColor ตั้งเป็นหนึ่งในสองทีมในประสบการณ์; แทนที่จะเป็นอย่างนั้น ตำแหน่งการเกิดนี้มีคุณสมบัติ Neutral ซึ่งเปลี่ยนตามรอบที่กำลังทำงานอยู่
ตัวอย่างเช่น หากรอบกำลังทำงานอยู่ คุณสมบัติ Neutral จะถูกตั้งค่าเป็น false เพื่อให้ spawnPlayersInMap สามารถจัดผู้เล่นในทีมและเกิดพวกเขาเข้าสู่สนามได้ อย่างไรก็ตาม หากรอบไม่ทำงาน เช่น ในช่วงเวลาระหว่างรอบหนึ่งไปยังรอบถัดไป คุณสมบัติ Neutral จะถูกตั้งค่าเป็น true เพื่อให้ผู้เล่นสามารถเกิดที่นั่นได้โดยไม่คำนึงถึงสถานะทีมของพวกเขา กระบวนการนี้ทำให้ตำแหน่งการเกิด Neutral เป็นล็อบบี้ที่ใช้งานได้

เพื่อแสดงให้เห็น หากคุณตรวจสอบ ServerScriptService ⟩ Gameplay ⟩ Rounds ⟩ SpawnPlayersInLobby ซึ่งทำงานที่สิ้นสุดของรอบ คุณจะเห็นว่า สำหรับผู้เล่นทุกคนที่ถูกส่งไปยังตาราง players: { Player } สคริปต์จะ:
- ตั้งค่า Player.Neutral ของพวกเขาเป็น true เพื่อรีเซ็ต Player.Team เป็น nil โดยอัตโนมัติอนุญาตให้ผู้เล่นเกิดในล็อบบี้เมื่อรอบไม่ทำงาน เนื่องจากคุณสมบัติ Neutral ของตำแหน่งการเกิดก็ถูกตั้งค่าเป็น true ด้วย
- เปลี่ยน PlayerState ของพวกเขาเป็น InLobby เพื่อเอาชนะบลาสเตอร์และภาพ UI มุมมองบุคคลแรกของผู้เล่นออกไป
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับโซนการเกิดกลางและฟังก์ชันการทำงานของมันในแต่ละรอบ คุณสามารถดูที่ การเพิ่มรอบ ในส่วนถัดไปของบทแนะนำ
spawnPlayersInLobby
local function spawnPlayersInLobby(players: { Player })
for _, player in players do
player.Neutral = true
player:SetAttribute(PlayerAttribute.playerState, PlayerState.InLobby)
task.spawn(function()
player:LoadCharacter()
end)
end
end
เชื่อมต่อผู้เล่นใหม่
โค้ด Luau ใน Studio มักขับเคลื่อนด้วยเหตุการณ์ หมายความว่าสคริปต์จะฟังเหตุการณ์จากบริการ Roblox จากนั้นเรียกฟังก์ชันในตอบสนอง ตัวอย่างเช่น เมื่อเพิ่มผู้เล่นใหม่ในการประสบการณ์หลายผู้เล่น จำเป็นต้องมีเหตุการณ์ที่จัดการสิ่งที่จำเป็นสำหรับผู้เล่นในการเชื่อมต่ออย่างสำเร็จ ในตัวอย่างประสบการณ์เลเซอร์แท็ก เหตุการณ์ที่เกี่ยวข้องคือ Players.PlayerAdded:Connect
Players.PlayerAdded:Connect เป็นส่วนหนึ่งของสคริปต์หลายตัวในประสบการณ์ หากคุณใช้คีย์ลัด Ctrl/Cmd+Shift+F และค้นหาคำว่า Players.PlayerAdded:Connect ผลลัพธ์จะช่วยให้คุณเริ่มเข้าใจการตั้งค่าเริ่มต้นของประสบการณ์ได้ดี

เพื่อแสดงให้เห็น เปิด ServerScriptService ⟩ SetupHumanoid ความแตกต่างระหว่าง Player และ Character เป็นสิ่งสำคัญในการเข้าใจสคริปต์นี้:
- ผู้เล่นจำเป็นต้องเลือกบลาสเตอร์และถูกเพิ่มลงในบอร์ดผู้นำ ตัวละครจำเป็นต้องเกิดและรับบลาสเตอร์
SetupHumanoid จะตรวจสอบทันทีว่าผู้เล่นมีตัวละคร (เพิ่งเข้าร่วม) หรือไม่ (อยู่ระหว่างการเกิดใหม่) หลังจากที่พบหนึ่งในสอง มันจะเรียก onCharacterAdded() รับโมเดล Humanoid จากตัวละคร และส่งต่อไปยัง ServerScriptService ⟩ SetupHumanoid ⟩ setupHumanoidAsync เพื่อการปรับแต่ง หลังจากตั้งค่าค่าเหล่านี้แล้ว สคริปต์จะรอจนกว่าพลังชีวิตของตัวละครจะลดลงเป็นศูนย์ คุณจะเรียนรู้เพิ่มเติมเกี่ยวกับการเกิดใหม่ภายหลังในส่วนนี้ของบทแนะนำ
setupHumanoidAsync
local function setupHumanoidAsync(player: Player, humanoid: Humanoid)
humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.Subject
humanoid.NameDisplayDistance = 1000
humanoid.HealthDisplayDistance = 1000
humanoid.NameOcclusion = Enum.NameOcclusion.OccludeAll
humanoid.HealthDisplayType = Enum.HumanoidHealthDisplayType.AlwaysOn
humanoid.BreakJointsOnDeath = false
humanoid.Died:Wait()
onHumanoidDied(player, humanoid)
end
หมายเหตุที่สำคัญกับสคริปต์นี้คือ คุณสมบัติต่างๆ นั้นเป็นตัวเลือกทั้งหมด หมายความว่าหากคุณลบหกบรรทัดแรกของฟังก์ชัน ประสบการณ์ยังคงทำงานได้อย่างถูกต้อง แทนที่จะเป็นข้อกำหนดที่ต้องการ แต่ละคุณสมบัติช่วยให้คุณทำการตัดสินใจด้านการออกแบบที่ตอบสนองต่อเป้าหมายการเล่นเกมของคุณ ตัวอย่างเช่น:
- หากคุณต้องการให้ชื่อของตัวละครแสดงที่ระยะใกล้ให้ลดค่าของ Humanoid.NameDisplayDistance
- หากคุณต้องการให้สุขภาพของตัวละครแสดงเฉพาะเมื่อมันต่ำกว่า 100% ให้ตั้งค่า Humanoid.HealthDisplayType เป็น DisplayWhenDamaged
- หากคุณต้องการให้ตัวละครแตกออกเมื่อสุขภาพถึง 0 ให้ตั้งค่า Humanoid.BreakJointsOnDeath เป็น True
หากคุณเปลี่ยนค่าเหล่านี้ ก็สำคัญที่จะต้องทดสอบการเล่นเพื่อให้คุณสามารถเห็นผลกระทบของการตั้งค่าใหม่ของคุณ คุณสามารถสร้างสิ่งที่ผู้เล่นได้สัมผัสใน การจำลองคลายหลายไคลเอนต์ โดยการเลือกตัวละครอย่างน้อยสองตัวในการทดสอบจากระดับ

อีกตัวอย่างหนึ่งของเหตุการณ์ Players.PlayerAdded:Connect อยู่ใน ServerScriptService ⟩ PlayerStateHandler เช่นเดียวกับในตัวอย่างก่อนหน้านี้ PlayerStateHandler จะตรวจสอบตัวละครทันที หากผู้เล่นไม่อยู่ในล็อบบี้ สคริปต์จะตั้งค่าแอตทริบิวต์ของผู้เล่นเป็นสถานะ SelectingBlaster ซึ่งเป็นสถานะเริ่มต้นสำหรับรอบที่ผู้เล่นสามารถเลือกจากบลาสเตอร์สองประเภทที่แตกต่างกันหลังจากเกิดเข้าสู่สนาม สถานะนี้ยังรวมถึงสนามพลังที่ป้องกันผู้เล่นจากการได้รับความเสียหายระหว่างการเลือกของพวกเขา
PlayerStateHandler
local function onPlayerAdded(player: Player)
player.CharacterAdded:Connect(function()
if not player.Neutral then
player:SetAttribute(PlayerAttribute.playerState, PlayerState.SelectingBlaster)
onPlayerStateChanged(player, PlayerState.SelectingBlaster)
end
end)
ตัวแปรหนึ่งใน PlayerStateHandler มีความสำคัญคือ attributeChangedConnectionByPlayer ตารางนี้เก็บผู้เล่นทั้งหมดและ Connections ของพวกเขาต่อ GetAttributeChangedSignal สาเหตุที่เก็บการเชื่อมต่อนี้ในตารางคือเพื่อให้ PlayerStateHandler สามารถ ตัดการเชื่อมต่อนี้ เมื่อผู้เล่นออกจากประสบการณ์ กระบวนการนี้ทำหน้าที่เหมือนการจัดการหน่วยความจำเพื่อป้องกันจำนวนการเชื่อมต่อนั้นเพิ่มขึ้นเรื่อย ๆ ตามเวลา
PlayerStateHandler
local attributeChangedConnectionByPlayer = {}
local function onPlayerAdded(player: Player)
-- จัดการกับการอัปเดตทั้งหมดในสถานะของผู้เล่น
attributeChangedConnectionByPlayer[player] = player
:GetAttributeChangedSignal(PlayerAttribute.playerState)
:Connect(function()
local newPlayerState = player:GetAttribute(PlayerAttribute.playerState)
onPlayerStateChanged(player, newPlayerState)
end)
end
-- ตัดการเชื่อมต่อจากการเปลี่ยนแปลงแอตทริบิวต์เมื่อผู้เล่นออก
local function onPlayerRemoving(player: Player)
if attributeChangedConnectionByPlayer[player] then
attributeChangedConnectionByPlayer[player]:Disconnect()
attributeChangedConnectionByPlayer[player] = nil
end
end
คุณจะเห็นว่าสองฟังก์ชันที่เชื่อมต่อใน onPlayerAdded() จะเรียก onPlayerStateChanged() ในระหว่างการตั้งค่าเริ่มต้นหลังจากที่ผู้เล่นจัดกลุ่มเข้าทีม onPlayerAdded() ตั้งค่า PlayerState เป็น SelectingBlaster ดังนั้นเงื่อนไข if แรกจะมีค่าผิดและปิดการทำงานของ BlasterState ในส่วนของ Implement blasters ในบทแนะนำคุณจะได้เรียนรู้รายละเอียดเพิ่มเติมเกี่ยวกับกระบวนการนี้
PlayerStateHandler
local function onPlayerStateChanged(player: Player, newPlayerState: string)
-- สถานะของบลาสเตอร์คือ 'พร้อม' เฉพาะเมื่อสถานะของผู้เล่นคือ 'กำลังเล่น'
local newBlasterState = if newPlayerState == PlayerState.Playing then BlasterState.Ready else BlasterState.Disabled
-- กำหนดลำดับการทำลายสนามพลังเมื่อผู้เล่นเริ่มเล่น
if newPlayerState == PlayerState.Playing then
scheduleDestroyForceField(player)
end
player:SetAttribute(PlayerAttribute.blasterStateServer, newBlasterState)
end
หากคุณเพิ่มจุดหยุดหรือแม้แต่คำสั่ง print() คุณสามารถเห็นว่า onPlayerStateChanged() ถูกเรียกอย่างถี่ถ้วนทั่วทั้งประสบการณ์ เช่น ในระหว่างการตั้งค่าเริ่มต้นของรอบ เพื่อกำหนดตำแหน่งของมันบนเส้นทางหลักหลังจากที่ผู้เล่นเลือกบลาสเตอร์ และเมื่อผู้เล่นกลับไปที่ล็อบบี้หรือสถานที่เกิด Neutral นอกจากนี้ หลังจากที่ผู้เลือกบลาสเตอร์, ServerScriptService ⟩ BlasterSelectedHandler จะตั้งค่า PlayerState เป็น Playing และ PlayerStateHandler สามารถลบสนามพลังได้โดยการเรียก scheduleDestroyForceField()
ปรับแต่งสนามพลัง
แทนที่จะใช้การปรับใช้แบบกำหนดเอง ตัวอย่างประสบการณ์เลเซอร์แท็กใช้คลาส ForceField ที่มีอยู่ใน Studio เพื่อป้องกันไม่ให้ผู้เล่นได้รับความเสียหายขณะที่พวกเขากำลังเลือกบลาสเตอร์ สิ่งนี้ทำให้ข้อกำหนดเพียงอย่างเดียวสำหรับผู้เล่นที่จะเกิดพร้อมสนามพลังคือการรวมตำแหน่งการเกิดที่มีคุณสมบัติ SpawnLocation.Duration ที่มากกว่า 0 ตัวอย่างดังกล่าวใช้ค่า 9,999 อย่างสุ่มเพื่อเปิดใช้งานสนามพลัง จากนั้นจัดการระยะเวลาที่แท้จริงใน ReplicatedStorage ⟩ ForceFieldClientVisuals
คล้ายกับ setupHumanoidAsync บรรทัดส่วนใหญ่ใน ForceFieldClientVisuals เป็นตัวเลือก ตัวอย่างเช่น หากคุณแสดงความคิดเห็นภายในฟังก์ชันเช่นในสคริปต์ดังต่อไปนี้ ประสบการณ์จะใช้สนามพลังที่เป็นค่าดีฟอลต์แทนที่จะเป็นสคริปต์รูปหกเหลี่ยมใน StarterGui ⟩ ForceFieldGui
Commenting Out Properties in ForceFieldClientVisuals
local function onCharacterAddedAsync(character: Model)
-- local forceField = character:WaitForChild("ForceField", 3)
-- if not forceField then
-- return
-- end
-- forceField.Visible = false
-- localPlayer.PlayerGui:WaitForChild("ForceFieldGui").Enabled = true
-- forceField.Destroying:Wait()
-- localPlayer.PlayerGui.ForceFieldGui.Enabled = false
end
เนื่องจากสนามพลังที่กำหนดเองเป็น GUI ไม่ใช่ ParticleEmitter ใหม่ สคริปต์ ForceFieldClientVisuals จะส่งผลต่อภาพมุมมองบุคคลแรกสำหรับผู้เล่นแต่ละคน ไม่ใช่ มุมมองบุคคลที่สามเมื่อผู้เล่นมองผู้เล่นคนอื่น ภาพมุมมองบุคคลที่สามยังคงมีรูปลักษณ์ตามดีฟอลต์ของ Roblox สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการปรับสนามพลังสามารถดูได้ที่ ForceField.Visible


สนามพลังมีประโยชน์เพราะพวกเขาให้เวลาเพียงพอระหว่างการเกิดและการเกิดใหม่โดยที่ไม่ต้องกังวลเกี่ยวกับผู้เล่นศัตรู แต่ท้ายที่สุดพวกเขาจำเป็นต้องหายไปเพื่อการเล่นเกมเลเซอร์แท็กหลัก สคริปต์ที่จะจัดการการกำจัดสนามพลังอยู่ใน ReplicatedStorage ⟩ scheduleDestroyForceField และมันจะตรวจสอบเงื่อนไขสามประการที่เฉพาะเจาะจง:
- หลังจากที่ผู้เล่นเลือกบลาสเตอร์ สนามพลังจะต้องมีระยะเวลาที่นานพอในการทำให้ผู้เล่นได้รับรู้สภาพแวดล้อมของพวกเขา
- ในระหว่างเวลานี้ สนามพลังไม่สามารถเป็นข้อได้เปรียบ ดังนั้นมันจำเป็นที่จะต้องหายไปในทันทีที่ผู้เล่นยิงบลาสเตอร์ของตน
- สนามพลังต้องหายไปเมื่อผู้เล่นรีเซ็ตตัวละครของพวกเขาก่อนที่จะยิงหรือก่อนที่สนามพลังจะหมดเวลา
การตรวจสอบแต่ละข้อในสคริปต์ scheduleDestroyForceField จะเรียก endForceField() สำหรับเงื่อนไขเหล่านี้
scheduleDestroyForceField
-- สิ้นสุดสนามพลังหากผู้เล่นยิง
local blasterStateAttribute = getBlasterStateAttribute()
attributeChangedConnection = player:GetAttributeChangedSignal(blasterStateAttribute):Connect(function()
local currentBlasterState = player:GetAttribute(blasterStateAttribute)
if currentBlasterState == BlasterState.Blasting then
endForceField()
end
end)
-- สิ้นสุดสนามพลังหากผู้เล่นรีเซ็ต
characterRespawnedConnection = player.CharacterRemoving:Connect(endForceField)
-- สิ้นสุดสนามพลังหลังจาก 8 วินาที
task.delay(MAX_FORCE_FIELD_TIME, endForceField)
endForceField() มีคำสั่ง if ที่ดูเหมือนจะแปลกอยู่รอบ forceFieldEnded บูลีน เนื่องจากการตรวจสอบทำงานเรียงลำดับ สคริปต์สามารถเรียกฟังก์ชัน endForceField() สองหรือสามครั้ง การเป็นบูลีน forceFieldEnded จะทำให้แน่ใจว่าฟังก์ชันพยายามที่จะทำลายสนามพลังเพียงครั้งเดียว
scheduleDestroyForceField
local function endForceField()
if forceFieldEnded then
return
end
forceFieldEnded = true
attributeChangedConnection:Disconnect()
characterRespawnedConnection:Disconnect()
destroyForceField(player)
end
จัดการสถานะไคลเอนต์
ในขณะที่ส่วนใหญ่ของส่วนนี้มุ่งเน้นไปที่ ServerScriptService ⟩ PlayerStateHandler แต่ยังมีสคริปต์อีกตัวที่มีชื่อเดียวกันใน ReplicatedStorage สาเหตุของการแบ่งนี้คือสถ معمาร์าclient-server:
ไคลเอนต์จำเป็นต้องเข้าใจข้อมูลสถานะของผู้เล่นเพื่อให้สามารถตอบสนองได้อย่างเหมาะสมในเวลาจริง เช่น การแสดงองค์ประกอบ UI ที่ถูกต้อง หรือการอนุญาตให้ผู้เล่นเคลื่อนที่และยิง
เซิร์ฟเวอร์จำเป็นต้องมีข้อมูลทั้งหมดนี้เพื่อป้องกันการแฮ็ก เช่น เซิร์ฟเวอร์ยังต้องการสถานะของผู้เล่นเพื่อทำการกระทำต่าง ๆ เช่น การเกิดและจัดการตัวละคร การปิดสนามพลัง และการแสดงบอร์ดผู้นำ นี่คือเหตุผลว่าทำไมสคริปต์นี้จึงอยู่ใน ReplicatedStorage แทนที่จะเป็นสถานที่ที่อยู่ด้านไคลเอนต์เพียงอย่างเดียว
เพื่อดูตรรกะหลักนี้ ให้ตรวจสอบสคริปต์ต่อไปนี้ใน ReplicatedStorage ⟩ PlayerStateHandler ที่ตรวจสอบสถานะปัจจุบันของผู้ใช้ แล้วเรียกฟังก์ชันที่เหมาะสมในการจัดการการกระทำที่เกี่ยวข้องสำหรับสถานะนั้น
PlayerStateHandler
local function onPlayerStateChanged(newPlayerState: string)
if newPlayerState == PlayerState.SelectingBlaster then
onSelectingBlaster()
elseif newPlayerState == PlayerState.Playing then
onPlaying()
elseif newPlayerState == PlayerState.TaggedOut then
onTaggedOut()
elseif newPlayerState == PlayerState.InLobby then
onInLobby()
else
warn(`Invalid player state ({newPlayerState})`)
end
end
การตอบสนองแต่ละเหตุการณ์จะถูกจัดกลุ่มอย่างมีระเบียบในสคริปต์นี้เนื่องจากพวกเขาต้องการพฤติกรรมที่คล้ายกันในการเปิดใช้งานหรือปิดใช้งานการควบคุมของผู้เล่น การเคลื่อนที่ของกล้อง และเลเยอร์ UI ที่มองเห็นอยู่ ตัวอย่างเช่น ในระหว่างการเลือกบลาสเตอร์ ผู้เล่นต้องไม่มีความเสี่ยงและไม่สามารถเคลื่อนที่ได้ บนเซิร์ฟเวอร์จะจัดการสนามพลังแล้ว แต่ในไคลเอนต์จะจัดการการเคลื่อนที่ เพื่อแสดงให้เห็น หากคุณตรวจสอบตรรกะสำหรับฟังก์ชัน onSelectingBlaster() คุณจะเห็นว่าไคลเอนต์จะปิดการเคลื่อนที่ของผู้เล่นในขณะที่พวกเขากำลังเลือกบลาสเตอร์
PlayerStateHandler
local function onSelectingBlaster()
togglePlayerCamera(true)
togglePlayerMovement(false)
setGuiExclusivelyEnabled(playerGui.PickABlasterGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
ฟังก์ชัน onPlaying() ก็เรียบง่ายเช่นกัน โดยเปิดใช้งานการเคลื่อนที่ เปลี่ยนไปยังหน้าจอแสดงผลหลัก (HUD) เปิดใช้งานบลาสเตอร์ และเรียกฟังก์ชันสนามพลังเดียวกันเช่นเดียวกับเซิร์ฟเวอร์
PlayerStateHandler
local function onPlaying()
togglePlayerMovement(true)
setGuiExclusivelyEnabled(playerGui.HUDGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Ready)
scheduleDestroyForceField()
end
การเกิดใหม่ของตัวละคร
ตัวอย่างประสบการณ์เลเซอร์แท็กจัดการการเกิดใหม่ของตัวละครกลับเข้าสู่รอบโดยใช้สถานะ onTaggedOut() ใน ReplicatedStorage ⟩ PlayerStateHandler เช่นเดียวกับสถานะ onSelectingBlaster() และ onPlaying() จะเรียกพฤติกรรมเฉพาะตามการเปลี่ยนแปลงของแอตทริบิวต์ playerState โดยเฉพาะ มันจะปิดการเคลื่อนที่ของผู้เล่น แสดง UI การเกิดใหม่ และปิดการทำงานของบลาสเตอร์
PlayerStateHandler
local function onTaggedOut()
-- ปิดการควบคุมในขณะที่ถูกแท็กออก
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- ปิดบลาสเตอร์ในขณะที่ถูกแท็กออก
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
หากคุณต้องการทดสอบพฤติกรรมนี้ คุณสามารถกด Esc ไปที่แท็บ Settings จากนั้นคลิกปุ่ม Reset Character สังเกตว่าตอนที่คุณกระตุ้นหน้าจอเกิดใหม่ คุณไม่สามารถเคลื่อนที่ หมุนกล้อง หรือยิงบลาสเตอร์ของคุณได้


สิ่งสำคัญที่จะต้องทราบคือ สคริปต์นี้ไม่ได้ทำให้ตัวละครเกิดใหม่จริงๆ แต่มันเพียงแค่หยุดพวกเขาจากการทำกิจกรรมและให้ข้อเสนอแนะทางสายตากับผู้เล่นว่าทำไม เซิร์ฟเวอร์ ถึงกำลังทำให้ตัวละครของพวกเขาเกิดใหม่ เพื่อจะให้เห็น หากคุณตรวจสอบ ServerScriptService ⟩ SetupHumanoid ⟩ setupHumanoidAsync ⟩ onHumanoidDied สคริปต์จะตั้งค่า PlayerState เป็น TaggedOut (ในทางปฏิบัติแจ้งเตือน ReplicatedStorage ⟩ PlayerStateHandler) และเพิ่มตัวบ่งชี้ทางสายตา ข้อเท็จจริงของการเกิดใหม่หลักเป็นพฤติกรรมใน Roblox ที่มี
เมื่อผู้เล่นเกิดใหม่กลับเข้าสู่รอบ พวกเขาจะเกิดที่ตำแหน่งการเกิดของทีมของตนตามค่าของ SpawnLocation.TeamColor เพื่อปรับเวลาการเกิดใหม่ คุณสามารถเพิ่มบรรทัดต่อไปนี้ที่ด้านบนของ SetupHumanoid เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับเทคนิคนี้ สามารถดูได้ที่ Players.RespawnTime.
SetupHumanoidlocal Players = game:GetService("Players")Players.RespawnTime = 10 -- บรรทัดใหม่, ในวินาที
การตั้งค่าอื่น ๆ
ในฐานะที่เป็นส่วนหนึ่งของการตั้งค่าเริ่มต้น ตัวอย่างประสบการณ์เลเซอร์แท็กยังทำบางสิ่งเล็กๆ น้อยๆ แต่มีความสำคัญ:
ประสบการณ์รวมถึงสคริปต์ว่างชื่อ StarterPlayer ⟩ StarterCharacterScripts ⟩ Health ที่ปิดการใช้งานการฟื้นฟูสุขภาพเริ่มต้นของ Roblox สำหรับการอธิบายพฤติกรรมของคุณสมบัตินี้สามารถดูได้ที่ Humanoid.Health
ประสบการณ์ใช้กล้องมุมมองบุคคลแรกโดยตั้งค่า StarterPlayer.CameraMode.LockFirstPerson หมายเหตุว่าหากคุณต้องการให้ผู้ใช้สามารถเปลี่ยนกล้องระหว่างบุคคลแรกและบุคคลที่สาม คุณต้องเปลี่ยนคุณสมบัติโปรแกรมแทนที่จะตั้งค่าเพียงครั้งเดียวใน Studio และปรับเปลี่ยนการควบคุมและ UI เพื่อชดเชยการเปลี่ยนแปลงในมุมมอง
ประสบการณ์ใช้บอร์ดผู้นำที่สร้างขึ้นใน Roblox ด้วยหน่วยของ "คะแนน" ซึ่งผู้เล่นจะได้รับแต่ละครั้งที่พวกเขาทำให้ผู้เล่นคนอื่นถูกแท็กออก คุณสามารถเห็นการตั้งค่าใน ServerScriptService ⟩ SetupLeaderboard แต่ บอร์ดผู้นำในประสบการณ์ เสนอภาพรวมเต็มรูปแบบ หมายเหตุว่า onPlayerTagged จะเพิ่มคะแนนให้กับบอร์ดผู้นำ ซึ่งคุณจะเรียนรู้เกี่ยวกับเรื่องนี้ใน การเพิ่มรอบ และ การตรวจจับการยิง
ตอนนี้ที่ผู้เล่นสามารถเกิดขึ้น เลือกบลาสเตอร์ และเล็งจากมุมมองบุคคลแรก ส่วนถัดไปจะสอนคุณเกี่ยวกับสคริปต์ที่อยู่เบื้องหลังการสร้างการเล่นเกมที่อิงตามรอบ