การเกิดและการเกิดใหม่

*เนื้อหานี้แปลโดยใช้ AI (เวอร์ชัน Beta) และอาจมีข้อผิดพลาด หากต้องการดูหน้านี้เป็นภาษาอังกฤษ ให้คลิกที่นี่

การเกิด คือกระบวนการสร้างวัตถุหรืออักขระในเกม และ การเกิดใหม่ คือกระบวนการเพิ่มวัตถุหรืออักขระกลับเข้าสู่เกมหลังจากที่พวกเขาเผชิญกับเงื่อนไขการลบ เช่น สุขภาพของอักขระลดลงถึงศูนย์หรือการตกจากแผนที่ ทั้งสองกระบวนการนี้มีความสำคัญเพราะช่วยให้ผู้เล่นสามารถเข้าร่วมเกมของคุณได้ และสามารถเล่นต่อไปเพื่อพัฒนาทักษะของพวกเขา

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

  • การกำหนดตำแหน่งการเกิดเพื่อให้ผู้เล่นสามารถเกิดได้เฉพาะในโซนการเกิดของทีมของตน
  • การเพิ่มผู้เล่นใหม่และอักขระของพวกเขาเข้าสู่รอบเมื่อพวกเขาเข้าร่วมเกม
  • การปรับแต่งฟิลด์แรงที่ป้องกันความเสียหายเมื่อผู้เล่นเกิดและเกิดใหม่
  • การจัดการสถานะของไคลเอนต์เพื่อให้การเล่นเกมทำงานได้อย่างถูกต้องในเวลาที่เหมาะสม
  • การเกิดใหม่ของอักขระหลังจากที่พวกเขาถูกแท็กออกจากรอบ
  • การทำกิจกรรมเล็ก ๆ น้อย ๆ ที่สำคัญสำหรับการตั้งค่าการเล่นเกมและพารามิเตอร์ของอักขระ

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

กำหนดตำแหน่งการเกิด

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

เพื่อแก้ไขปัญหานี้ เกมเลเซอร์แท็กตัวอย่างได้กำหนดตำแหน่งการเกิดทั้งสองตำแหน่งด้วยคุณสมบัติ Neutral ที่ตั้งค่าเป็น false เพื่อจำกัดไม่ให้ผู้เล่นของทีมตรงข้ามเกิดในโซนการเกิดที่ผิด และคุณสมบัติ TeamColor ที่ตั้งค่าเป็นค่าของ Team.Color ที่สอดคล้องจาก กำหนดสีทีม ในส่วนก่อนหน้าของบทเรียน:

  • TeamASpawn – ตำแหน่งการเกิดในโซนการเกิดของทีมสีเขียวที่มีคุณสมบัติ TeamColor ตั้งค่าเป็น Mint.
  • TeamBSpawn – ตำแหน่งการเกิดในโซนการเกิดของทีมสีชมพูที่มีคุณสมบัติ TeamColor ตั้งค่าเป็น Carnation Pink.
TeamASpawn
TeamBSpawn

เมื่อผู้เล่นเข้าร่วมเกม ServerScriptServiceGameplayRoundsspawnPlayersInMap จะตรวจสอบว่ามีผู้เล่นกี่คนที่อยู่ในแต่ละทีมแล้วจะส่งคืนทีมที่มีจำนวนผู้เล่นน้อยที่สุด

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

หากคุณตรวจสอบ WorkspaceWorldMapSpawns คุณจะเห็นว่ามีตำแหน่งการเกิดอีกหนึ่งตำแหน่งในแผนที่: NeutralSpawn ตำแหน่งการเกิดนี้มีความแตกต่างจากตำแหน่งอื่น ๆ เพราะมันไม่มีคุณสมบัติ TeamColor ที่ตั้งค่าเป็นหนึ่งในสองทีมในเกม; แทนที่ตำแหน่งการเกิดนี้มีคุณสมบัติ Neutral ที่เปลี่ยนแปลงขึ้นอยู่กับว่ารอบนั้นใช้งานอยู่หรือไม่

ตัวอย่างเช่น หากรอบนั้นใช้งานอยู่ คุณสมบัติ Neutral จะตั้งค่าเป็น false เพื่อให้ spawnPlayersInMap สามารถจัดผู้เล่นไปยังทีมและเกิดพวกเขาเข้าสู่สนาม อย่างไรก็ตาม หากรอบนั้นไม่ใช้งาน เช่น ช่วงเวลาระหว่างรอบหนึ่งไปยังรอบถัดไป คุณสมบัติ Neutral จะตั้งค่าเป็น true เพื่อให้ผู้เล่นสามารถเกิดที่นั่นได้โดยไม่คำนึงถึงสถานะทีมของพวกเขา กระบวนการนี้ทำให้ตำแหน่งการเกิด Neutral เป็นล็อบบี้ที่ใช้งานได้

Neutral

เพื่อแสดงให้เห็น หากคุณตรวจสอบ ServerScriptServiceGameplayRoundsSpawnPlayersInLobby ซึ่งทำงานที่สิ้นสุดรอบ คุณจะเห็นว่าสำหรับผู้เล่นแต่ละคนที่ถูกส่งไปยังตาราง players: { Player } สคริปต์จะ:

  • ตั้งค่าคุณสมบัติ Player.Neutral ของพวกเขาเป็น true เพื่อรีเซ็ตอัตโนมัติ Player.Team ของพวกเขาเป็น nil ทำให้ผู้เล่นสามารถเกิดใหม่ในล็อบบี้เมื่อรอบไม่ใช้งาน เนื่องจากคุณสมบัติ Neutral ของตำแหน่งการเกิดนั้นก็ถูกตั้งค่าเป็น true ด้วย
  • เปลี่ยนสถานะของพวกเขาเป็น 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 ผลลัพธ์จะให้จุดเริ่มต้นที่ดีในการเข้าใจการตั้งค่าเริ่มต้นของเกม

หน้าต่าง Find All ของ Studio ที่มีผลลัพธ์ Players.PlayerAdded เน้น

เพื่อแสดงให้เห็น เปิด ServerScriptServiceSetupHumanoid ความแตกต่างระหว่าง Player และ Character เป็นกุญแจสำคัญในการเข้าใจสคริปต์นี้:

  • ผู้เล่น คือไคลเอนต์ที่เชื่อมต่อ และ อักขระ คือโมเดล Humanoid
  • ผู้เล่นต้องเลือกบลาสเตอร์และถูกเพิ่มลงในกระดานคะแนน อักขระต้องเกิดและรับบลาสเตอร์

SetupHumanoid จะตรวจสอบทันทีว่าผู้เล่นมีอักขระ (เพิ่งเข้าร่วม) หรือไม่มี (กำลังเกิดใหม่) หลังจากที่มันพบหนึ่ง มันจะเรียก onCharacterAdded() รับโมเดล Humanoid จากอักขระ และส่งไปยัง ServerScriptServiceSetupHumanoidsetupHumanoidAsync เพื่อการปรับแต่ง หลังจากตั้งค่าค่าต่าง ๆ เหล่านี้แล้ว สคริปต์จะรอให้สุขภาพของอักขระลดลงถึงศูนย์ คุณจะได้เรียนรู้เพิ่มเติมเกี่ยวกับการเกิดใหม่ในภายหลังในส่วนนี้ของบทเรียน

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

หากคุณเปลี่ยนค่าของคุณสมบัติเหล่านี้ สิ่งสำคัญคือต้องทดสอบเกมเพื่อให้คุณเห็นผลกระทบจากการตั้งค่าใหม่ของคุณ คุณสามารถสร้างสิ่งที่ผู้เล่นประสบใน การจำลองหลายไคลเอนต์ โดยการเลือกอักขระอย่างน้อยสองตัวในการทดสอบ Server & Clients จาก mezzanine

ตัวเลือก Server & Clients ในเมนูการทดสอบของ Studio's mezzanine.

อีกตัวอย่างหนึ่งของเหตุการณ์ Players.PlayerAdded:Connect อยู่ใน ServerScriptServicePlayerStateHandler เช่นเดียวกับในตัวอย่างก่อนหน้านี้ 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 แรกจะประเมินเป็น false และปิด BlasterState ในภายหลังในส่วน การดำเนินการบลาสเตอร์ ของบทเรียน คุณจะได้เรียนรู้รายละเอียดเพิ่มเติมเกี่ยวกับกระบวนการนี้

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 นอกจากนี้ หลังจากที่ผู้เล่นเลือกบลาสเตอร์ ServerScriptServiceBlasterSelectedHandler จะตั้งค่า PlayerState เป็น Playing และ PlayerStateHandler สามารถลบฟิลด์แรงได้โดยการเรียก scheduleDestroyForceField()

ปรับแต่งฟิลด์แรง

แทนที่จะใช้การนำไปใช้ที่กำหนดเอง เกมเลเซอร์แท็กตัวอย่างใช้คลาส ForceField ที่มีอยู่ใน Studio เพื่อป้องกันไม่ให้ผู้เล่นได้รับความเสียหายในขณะที่พวกเขากำลังเลือกบลาสเตอร์ของตน สิ่งนี้ทำให้ข้อกำหนดเดียวสำหรับผู้เล่นในการเกิดพร้อมฟิลด์แรงคือการรวมตำแหน่งการเกิดที่มีคุณสมบัติ SpawnLocation.Duration ที่มากกว่า 0 ตัวอย่างใช้ค่าที่ไม่แน่นอนที่ 9,999 เพื่อเปิดใช้งานฟิลด์แรง จากนั้นจัดการระยะเวลาจริงใน ReplicatedStorageForceFieldClientVisuals

คล้ายกับ setupHumanoidAsync ส่วนใหญ่ของบรรทัดใน ForceFieldClientVisuals เป็นทางเลือก ตัวอย่างเช่น หากคุณคอมเมนต์เนื้อหาของฟังก์ชันเหมือนกับที่สคริปต์ต่อไปนี้ทำ เกมจะใช้ฟิลด์แรงที่มีการกระพริบตามค่าเริ่มต้นแทนที่จะเป็นสคริปต์หกเหลี่ยมใน StarterGuiForceFieldGui

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

ภาพมุมมองฟิลด์แรงบุคคลแรกประกอบด้วยกริดหกเหลี่ยมที่ทันสมัยรอบขอบของหน้าจอ
ภาพมุมมองฟิลด์แรงบุคคลแรก
ภาพมุมมองฟิลด์แรงบุคคลที่สามประกอบด้วยลูกบอลส่องแสงสีน้ำเงินรอบผู้เล่นที่เกิดเข้าสู่เกม
ภาพมุมมองฟิลด์แรงบุคคลที่สาม

ฟิลด์แรงมีประโยชน์เพราะให้เวลาผู้เล่นเพียงพอระหว่างการเกิดและการเกิดใหม่โดยไม่ต้องกังวลเกี่ยวกับผู้เล่นศัตรู แต่ในที่สุดพวกเขาต้องหายไปสำหรับการเล่นเกมเลเซอร์แท็กหลัก สคริปต์ที่จัดการการลบฟิลด์แรงอยู่ใน ReplicatedStoragescheduleDestroyForceField และมันจะตรวจสอบสามเงื่อนไขที่ไม่ซ้ำกัน:

  • หลังจากที่ผู้เล่นเลือกบลาสเตอร์ ฟิลด์แรงต้องมีอายุยาวพอที่จะให้ผู้เล่นปรับตัวเข้ากับสภาพแวดล้อมของพวกเขา
  • ในระหว่างเวลาปรับตัวนี้ ฟิลด์แรงไม่สามารถเป็นข้อได้เปรียบได้ ดังนั้นมันต้องหายไปในทันทีที่ผู้เล่นยิงบลาสเตอร์ของพวกเขา
  • ฟิลด์แรงต้องหายไปเมื่อผู้เล่นรีเซ็ตอักขระของพวกเขาไม่ว่าจะก่อนการยิงหรือก่อนที่ฟิลด์แรงจะหมดเวลา

การตรวจสอบแต่ละรายการในสคริปต์ 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

จัดการสถานะของไคลเอนต์

ในขณะที่ส่วนใหญ่ของส่วนนี้มุ่งเน้นไปที่ ServerScriptServicePlayerStateHandler ยังมีสคริปต์อีกตัวหนึ่งที่มีชื่อเดียวกันใน ReplicatedStorage สาเหตุของการแยกนี้คือสถาปัตยกรรมไคลเอนต์-เซิร์ฟเวอร์:

  • ไคลเอนต์ต้องเข้าใจข้อมูลสถานะของผู้เล่นเพื่อให้สามารถตอบสนองได้อย่างเหมาะสมในเวลาจริง เช่น การแสดงองค์ประกอบ UI ที่ถูกต้อง หรือการอนุญาตให้ผู้เล่นเคลื่อนที่และยิง

  • เซิร์ฟเวอร์ต้องการข้อมูลทั้งหมดนี้เช่นกันเพื่อป้องกันการแสวงหาประโยชน์ ตัวอย่างเช่น เซิร์ฟเวอร์ยังต้องการสถานะของผู้เล่นเพื่อดำเนินการต่าง ๆ เช่น การเกิดและการติดตั้งอักขระ การปิดฟิลด์แรง และการแสดงกระดานคะแนน นี่คือเหตุผลที่สคริปต์นี้อยู่ใน ReplicatedStorage และไม่ใช่สถานที่ที่เป็นไคลเอนต์ล้วน ๆ

เพื่อดูตรรกะหลักนี้ ตรวจสอบสคริปต์ต่อไปนี้ใน ReplicatedStoragePlayerStateHandler ที่ตรวจสอบสถานะปัจจุบันของผู้ใช้ จากนั้นเรียกฟังก์ชันที่เหมาะสมซึ่งจัดการการกระทำที่เกี่ยวข้องสำหรับสถานะนั้น

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() ใน ReplicatedStoragePlayerStateHandler เช่นเดียวกับสถานะ onSelectingBlaster() และ onPlaying() สถานะ onTaggedOut() จะกระตุ้นพฤติกรรมเฉพาะตามการเปลี่ยนแปลงในคุณสมบัติ playerState โดยเฉพาะ มันจะปิดการเคลื่อนไหวของผู้เล่น แสดง UI การเกิดใหม่ และปิดบลาสเตอร์

PlayerStateHandler
local function onTaggedOut()
-- ปิดการควบคุมในขณะที่ถูกแท็กออก
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- ปิดบลาสเตอร์ในขณะที่ถูกแท็กออก
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end

หากคุณต้องการทดสอบพฤติกรรมนี้ คุณสามารถกด Esc ไปที่แท็บ การตั้งค่า จากนั้นคลิกที่ปุ่ม รีเซ็ตอักขระ สังเกตว่าเมื่อคุณกระตุ้นหน้าจอการเกิดใหม่ คุณไม่สามารถเคลื่อนที่ หมุนกล้อง หรือยิงบลาสเตอร์ของคุณได้

เมนูการตั้งค่าของ Roblox ที่มีปุ่ม Reset Character เน้น
ปุ่มรีเซ็ตอักขระ
หน้าจอการเกิดใหม่แสดงเมื่อผู้เล่นเกิดกลับเข้าสู่รอบ
หน้าจอการเกิดใหม่

สิ่งสำคัญคือต้องทราบว่าสคริปต์นี้ไม่ได้ทำการเกิดใหม่ของอักขระจริง ๆ มันเพียงแค่หยุดพวกเขาจากการกระทำและให้ข้อเสนอแนะแก่ผู้เล่นว่าผู้เล่น เซิร์ฟเวอร์ กำลังทำการเกิดใหม่ของอักขระของพวกเขา เพื่อแสดงให้เห็น หากคุณตรวจสอบ ServerScriptServiceSetupHumanoidsetupHumanoidAsynconHumanoidDied สคริปต์จะตั้งค่า PlayerState เป็น TaggedOut (ซึ่งเป็นการแจ้งเตือน ReplicatedStoragePlayerStateHandler) และเพิ่มตัวบ่งชี้ภาพบางอย่าง ลอจิกจริงของการเกิดใหม่เป็นพฤติกรรมที่สร้างขึ้นใน Roblox

เมื่อผู้เล่นเกิดกลับเข้าสู่รอบ พวกเขาจะเกิดที่ตำแหน่งการเกิดของทีมของพวกเขาตามคุณสมบัติ SpawnLocation.TeamColor เพื่อปรับแต่งเวลาการเกิดใหม่ คุณสามารถเพิ่มบรรทัดต่อไปนี้ที่ด้านบนของ SetupHumanoid เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับเทคนิคนี้ ดูที่ Players.RespawnTime

SetupHumanoid
local Players = game:GetService("Players")
Players.RespawnTime = 10 -- บรรทัดใหม่, เป็นวินาที

การตั้งค่าอื่น ๆ

เป็นส่วนหนึ่งของการตั้งค่าเริ่มต้น เกมเลเซอร์แท็กตัวอย่างยังทำขั้นตอนเล็ก ๆ แต่สำคัญบางอย่าง:

  • เกมรวมถึงสคริปต์ว่างชื่อ StarterPlayerStarterCharacterScriptsHealth ที่ปิดการฟื้นฟูสุขภาพเริ่มต้นของ Roblox สำหรับคำอธิบายเกี่ยวกับพฤติกรรมของคุณสมบัตินี้ ดูที่ Humanoid.Health

  • เกมใช้กล้องมุมมองบุคคลแรกโดยการตั้งค่าคุณสมบัติ StarterPlayer.CameraMode.LockFirstPerson โปรดทราบว่าหากคุณต้องการให้ผู้ใช้เปลี่ยนระหว่างกล้องมุมมองบุคคลแรกและบุคคลที่สาม คุณต้องเปลี่ยนคุณสมบัตินี้ในโปรแกรมแทนที่จะตั้งค่าเพียงครั้งเดียวใน Studio และปรับเปลี่ยนการควบคุมและ UI เพื่อชดเชยการเปลี่ยนแปลงในมุมมอง

  • เกมใช้กระดานคะแนนที่สร้างขึ้นใน Roblox โดยมีหน่วยเป็น "คะแนน" ซึ่งผู้เล่นจะได้รับทุกครั้งที่พวกเขาแท็กผู้เล่นคนอื่นออก คุณสามารถดูการกำหนดค่าใน ServerScriptServiceSetupLeaderboard แต่ กระดานคะแนนในเกม มีภาพรวมทั้งหมด โปรดทราบว่า onPlayerTagged เพิ่มคะแนนลงในกระดานคะแนน ซึ่งคุณจะได้เรียนรู้เกี่ยวกับใน เพิ่มรอบ และ ตรวจจับการโจมตี

ตอนนี้ผู้เล่นสามารถเกิด เลือกบลาสเตอร์ และเล็งจากมุมมองบุคคลแรก ส่วนถัดไปจะสอนคุณเกี่ยวกับสคริปต์ที่อยู่เบื้องหลังการสร้างการเล่นเกมแบบรอบ

©2026 Roblox Corporation. Roblox, โลโก้ Roblox และ Powering Imagination เป็นส่วนหนึ่งของเครื่องหมายการค้าที่จดทะเบียน และไม่ได้จดทะเบียนของเราในสหรัฐฯ และประเทศอื่นๆ