Spawning là quá trình tạo ra một đối tượng hoặc nhân vật trong một trải nghiệm, và respawning là quá trình đưa một đối tượng hoặc nhân vật trở lại vào một trải nghiệm sau khi họ gặp điều kiện loại bỏ, chẳng hạn như sức khỏe của nhân vật đạt đến 0 hoặc rơi ra khỏi bản đồ. Cả hai quá trình này rất quan trọng vì chúng đảm bảo rằng người chơi có thể tham gia trải nghiệm của bạn và có thể tiếp tục chơi để cải thiện kỹ năng của họ.
Sử dụng trải nghiệm laser tag mẫu làm tham khảo, phần này của hướng dẫn sẽ dạy bạn cách sử dụng và tùy chỉnh các tính năng sẵn có của Roblox để xử lý việc spawning và respawning, bao gồm hướng dẫn scripting về:
- Cấu hình các vị trí spawning để người chơi chỉ có thể spawn vào khu vực spawning của đội mình.
- Thêm người chơi mới và nhân vật của họ vào vòng khi họ tham gia trải nghiệm.
- Tùy chỉnh các force field ngăn ngừa sát thương khi người chơi spawn và respawn.
- Xử lý trạng thái client để gameplay hoạt động chính xác vào thời điểm thích hợp.
- Respawning các nhân vật sau khi họ bị đánh ra khỏi vòng.
- Thực hiện các hành động nhỏ, linh tinh rất quan trọng để thiết lập gameplay và các tham số của nhân vật.
Phần này bao gồm nhiều nội dung scripting, nhưng thay vì viết mọi thứ từ đầu khi tạo ra một trải nghiệm, nó khuyến khích bạn tận dụng các thành phần hiện có, lặp lại nhanh chóng và figure ra hệ thống nào cần triển khai tùy chỉnh để phù hợp với tầm nhìn của bạn. Sau khi bạn hoàn thành phần này, bạn sẽ học cách triển khai gameplay theo vòng đang theo dõi điểm số, theo dõi trạng thái người chơi và hiển thị kết quả vòng đấu.
Cấu hình các vị trí spawning
Nếu bạn thử nghiệm trải nghiệm ngay bây giờ, tất cả người chơi sẽ spawn ngẫu nhiên tại đối tượng SpawnLocation trong khu vực spawning của đội xanh, hoặc đối tượng SpawnLocation trong khu vực spawning của đội hồng. Điều này tạo ra một vấn đề gameplay nơi người chơi có thể đánh nhau trong mỗi khu vực spawning ngay khi force field của đối thủ biến mất.
Để chống lại vấn đề này, trải nghiệm laser tag mẫu cấu hình cả hai vị trí spawning với thuộc tính Neutral được thiết lập là false để hạn chế người chơi của đội đối phương spawn vào khu vực spawning sai, và thuộc tính TeamColor được thiết lập với giá trị tương ứng với Team.Color từ Gán màu cho đội trong phần trước của hướng dẫn:
- TeamASpawn – Vị trí spawning trong khu vực spawning của đội xanh với thuộc tính TeamColor được thiết lập là Mint.
- TeamBSpawn – Vị trí spawning trong khu vực spawning của đội hồng với thuộc tính TeamColor được thiết lập là Carnation Pink.


Khi một người chơi tham gia vào trải nghiệm, ServerScriptService ⟩ Gameplay ⟩ Rounds ⟩ spawnPlayersInMap kiểm tra xem có bao nhiêu người chơi đã có mặt trên mỗi đội, sau đó trả về đội có số lượng người chơi ít nhất.
spawnPlayersInMap
local function getSmallestTeam(): Team
local teams = Teams:GetTeams()
-- Sắp xếp các đội theo thứ tự tăng dần từ nhỏ đến lớn
table.sort(teams, function(teamA: Team, teamB: Team)
return #teamA:GetPlayers() < #teamB:GetPlayers()
end)
-- Trả về đội nhỏ nhất
return teams[1]
end
Khi nó biết đội nào có số lượng người chơi ít nhất, nó phân loại người chơi vào đội đó, đặt thuộc tính Player.Neutral của họ thành false để người chơi chỉ có thể spawn và respawn vào vị trí spawning của đội mình, sau đó đặt trạng thái PlayerState của họ thành SelectingBlaster, mà bạn sẽ tìm hiểu thêm sau trong hướng dẫn.
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
Nếu bạn kiểm tra Workspace ⟩ World ⟩ Map ⟩ Spawns, bạn sẽ thấy rằng còn một vị trí spawning nữa trên bản đồ: NeutralSpawn. Vị trí spawning này khác biệt với những vị trí khác vì nó không có thuộc tính TeamColor được thiết lập cho một trong hai đội trong trải nghiệm; thay vào đó, vị trí spawning này có thuộc tính Neutral thay đổi tùy thuộc vào việc vòng đấu có đang hoạt động hay không.
Ví dụ, nếu vòng đấu đang hoạt động, thuộc tính Neutral được thiết lập thành false để spawnPlayersInMap có thể phân loại người chơi vào các đội và spawn họ vào đấu trường. Tuy nhiên, nếu vòng đấu không hoạt động, chẳng hạn như khoảng thời gian giữa một vòng đấu và vòng đấu tiếp theo, thuộc tính Neutral được thiết lập thành true để người chơi có thể spawn ở đó bất kể trạng thái đội của họ. Quá trình này khiến vị trí spawn Neutral trở thành một hành lang chức năng.

Để chứng minh, nếu bạn kiểm tra ServerScriptService ⟩ Gameplay ⟩ Rounds ⟩ SpawnPlayersInLobby, mà chạy vào cuối một vòng đấu, bạn sẽ thấy rằng đối với mỗi người chơi được truyền vào bảng players: { Player }, script:
- Đặt thuộc tính Player.Neutral của họ thành true để tự động đặt lại thuộc tính Player.Team của họ thành nil, cho phép người chơi respawn trong hành lang khi một vòng đấu không hoạt động, vì thuộc tính Neutral của vị trí spawn cũng được thiết lập thành true.
- Thay đổi trạng thái của họ thành InLobby để xóa blaster và giao diện người dùng từ góc nhìn thứ nhất của người chơi.
Để biết thêm thông tin về khu vực spawn trung lập và chức năng của nó cho mỗi vòng đấu, xem Thêm Vòng đấu trong phần tiếp theo của hướng dẫn.
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
Kết nối người chơi mới
Mã Luau trong Studio thường hướng sự kiện, có nghĩa là các script lắng nghe các sự kiện từ một dịch vụ Roblox, sau đó gọi một chức năng để phản hồi. Ví dụ, khi thêm người chơi mới vào trải nghiệm nhiều người chơi, phải có một sự kiện xử lý mọi điều cần thiết để người chơi kết nối thành công. Trong trải nghiệm laser tag mẫu, sự kiện tương ứng này là Players.PlayerAdded:Connect.
Players.PlayerAdded:Connect là một phần của nhiều script trong trải nghiệm. Nếu bạn sử dụng phím tắt Ctrl/Cmd+Shift+F và tìm kiếm Players.PlayerAdded:Connect, các kết quả cung cấp một điểm khởi đầu tốt để hiểu thiết lập ban đầu của trải nghiệm.

Để chứng minh, mở ServerScriptService ⟩ SetupHumanoid. Sự phân biệt giữa Player và Character là chìa khóa để hiểu script này:
- Người chơi cần chọn một blaster và được thêm vào bảng điều khiển. Nhân vật cần được spawn và nhận blaster.
SetupHumanoid ngay lập tức kiểm tra xem người chơi có nhân vật hay không (vừa tham gia) hoặc không có (đang respawn). Sau khi tìm thấy một, nó gọi onCharacterAdded(), lấy mô hình Humanoid từ nhân vật và truyền nó đến ServerScriptService ⟩ SetupHumanoid ⟩ setupHumanoidAsync để tùy chỉnh. Sau khi thiết lập các giá trị này, script sau đó chờ cho sức khỏe của nhân vật đạt tới 0. Bạn sẽ tìm hiểu thêm về respawning sau trong phần này của hướng dẫn.
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
Lưu ý quan trọng với script này là các thuộc tính hoàn toàn là tùy chọn, có nghĩa là nếu bạn xóa sáu dòng đầu tiên của hàm, trải nghiệm vẫn hoạt động đúng. Thay vì là yêu cầu chức năng, mỗi thuộc tính cho phép bạn đưa ra các quyết định thiết kế đáp ứng các mục tiêu gameplay của bạn. Ví dụ:
- Nếu bạn muốn tên nhân vật hiển thị ở khoảng cách gần hơn, giảm giá trị của Humanoid.NameDisplayDistance.
- Nếu bạn chỉ muốn sức khỏe của nhân vật hiển thị nếu nó dưới 100%, đặt Humanoid.HealthDisplayType thành DisplayWhenDamaged.
- Nếu bạn muốn nhân vật vỡ vụn khi sức khỏe của họ đạt 0, đặt Humanoid.BreakJointsOnDeath thành True.
Nếu bạn thay đổi các giá trị của những thuộc tính này, điều quan trọng là phải thực hiện thử nghiệm để có thể thấy được ảnh hưởng của các thiết lập mới của bạn. Bạn có thể tái tạo những gì người chơi trải nghiệm trong một mô phỏng đa client bằng cách chọn ít nhất hai nhân vật trong một bài kiểm tra Server & Clients từ hành lang.

Một ví dụ khác về sự kiện Players.PlayerAdded:Connect là trong ServerScriptService ⟩ PlayerStateHandler. Giống như trong ví dụ trước, PlayerStateHandler ngay lập tức kiểm tra một nhân vật. Nếu người chơi không ở trong hành lang, script đặt một thuộc tính người chơi thành trạng thái SelectingBlaster, trạng thái ban đầu cho một vòng mà trong đó người chơi có thể chọn từ hai loại blaster khác nhau sau khi spawn vào đấu trường. Trạng thái này cũng bao gồm một force field ngăn ngừa người chơi nhận sát thương trong khi họ đang thực hiện lựa chọn của mình.
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)
Một biến đặc biệt trong PlayerStateHandler đáng được thảo luận: attributeChangedConnectionByPlayer. Bảng này lưu trữ tất cả người chơi và các Connections của họ tới GetAttributeChangedSignal. Lý do lưu trữ kết nối này trong một bảng là để PlayerStateHandler có thể ngắt kết nối nó khi người chơi rời khỏi trải nghiệm. Quá trình này hoạt động như một hình thức quản lý bộ nhớ để ngăn ngừa số lượng kết nối tăng lên theo thời gian.
PlayerStateHandler
local attributeChangedConnectionByPlayer = {}
local function onPlayerAdded(player: Player)
-- Xử lý tất cả các cập nhật tương lai đến trạng thái người chơi
attributeChangedConnectionByPlayer[player] = player
:GetAttributeChangedSignal(PlayerAttribute.playerState)
:Connect(function()
local newPlayerState = player:GetAttribute(PlayerAttribute.playerState)
onPlayerStateChanged(player, newPlayerState)
end)
end
-- Ngắt kết nối khỏi kết nối thay đổi thuộc tính khi người chơi rời đi
local function onPlayerRemoving(player: Player)
if attributeChangedConnectionByPlayer[player] then
attributeChangedConnectionByPlayer[player]:Disconnect()
attributeChangedConnectionByPlayer[player] = nil
end
end
Bạn có thể thấy rằng cả hai chức năng được kết nối trong onPlayerAdded() đều gọi onPlayerStateChanged(). Trong thiết lập ban đầu sau khi một người chơi được phân loại vào một đội, onPlayerAdded() đặt PlayerState thành SelectingBlaster, vì vậy câu lệnh if đầu tiên đánh giá là sai và vô hiệu hóa BlasterState. Trong phần Triển khai blasters sau này của hướng dẫn, bạn sẽ tìm hiểu thêm về quá trình này.
PlayerStateHandler
local function onPlayerStateChanged(player: Player, newPlayerState: string)
-- Trạng thái blaster là 'Sẵn sàng' chỉ khi trạng thái người chơi là 'Đang chơi'
local newBlasterState = if newPlayerState == PlayerState.Playing then BlasterState.Ready else BlasterState.Disabled
-- Lên lịch logic phá hủy force field khi người chơi bắt đầu chơi
if newPlayerState == PlayerState.Playing then
scheduleDestroyForceField(player)
end
player:SetAttribute(PlayerAttribute.blasterStateServer, newBlasterState)
end
Nếu bạn thêm các điểm dừng hoặc thậm chí chỉ một câu lệnh print(), bạn có thể thấy rằng onPlayerStateChanged() được gọi thường xuyên trong suốt trải nghiệm: chẳng hạn như trong giai đoạn thiết lập ban đầu của một vòng, để thiết lập nó trên đường dẫn mã chính, sau khi người chơi chọn một blaster, và khi người chơi trở lại hành lang, hoặc vị trí spawn Neutral. Hơn nữa, sau khi người chơi chọn một blaster, ServerScriptService ⟩ BlasterSelectedHandler thiết lập PlayerState thành Playing, và PlayerStateHandler cuối cùng có thể loại bỏ force field bằng cách gọi scheduleDestroyForceField().
Tùy chỉnh force field
Thay vì sử dụng một triển khai tùy chỉnh, trải nghiệm laser tag mẫu sử dụng lớp ForceField có sẵn trong Studio để ngăn người chơi nhận sát thương trong khi họ đang chọn blaster. Điều này đảm bảo rằng yêu cầu duy nhất để người chơi spawn với một force field là bao gồm các vị trí spawning với thuộc tính SpawnLocation.Duration lớn hơn 0. Mẫu sử dụng một giá trị tùy ý là 9,999 để kích hoạt force fields, sau đó xử lý thời gian thực tế một cách lập trình trong ReplicatedStorage ⟩ ForceFieldClientVisuals.
Tương tự như setupHumanoidAsync, hầu hết các dòng trong ForceFieldClientVisuals là tùy chọn. Ví dụ, nếu bạn bình luận nội dung của hàm như đoạn script sau, trải nghiệm sẽ sử dụng force field lấp lánh mặc định thay vì hexagonal script trong 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
Vì force field tùy chỉnh là một giao diện người dùng thay vì một ParticleEmitter mới, script ForceFieldClientVisuals chỉ ảnh hưởng đến các hình ảnh từ góc nhìn thứ nhất của mỗi người chơi, không phải là hình ảnh từ góc nhìn thứ ba khi người chơi nhìn vào người chơi khác. Hình ảnh từ góc nhìn thứ ba giữ nguyên hình thức mặc định của Roblox. Để biết thêm thông tin về việc chỉnh sửa force fields, xem ForceField.Visible.


Force fields rất hữu ích vì chúng cung cấp đủ thời gian cho người chơi giữa việc spawn và respawn mà không cần lo lắng về những người chơi địch, nhưng cuối cùng chúng cần biến mất để gameplay laser tag chính diễn ra. Script xử lý việc loại bỏ force field nằm trong ReplicatedStorage ⟩ scheduleDestroyForceField, và nó kiểm tra ba điều kiện duy nhất:
- Sau khi người chơi chọn một blaster, force fields cần tồn tại đủ lâu để cho phép người chơi làm quen với môi trường xung quanh.
- Trong thời gian làm quen này, force fields không thể là một lợi thế, vì vậy chúng cần biến mất ngay khi một người chơi bắn blaster của họ.
- Force fields cần biến mất khi người chơi đặt lại nhân vật của họ, hoặc trước khi bắn hoặc trước khi force field hết thời gian.
Mỗi trong số những kiểm tra này trong script scheduleDestroyForceField gọi endForceField() cho những điều kiện này.
scheduleDestroyForceField
-- Kết thúc force field nếu người chơi bắn
local blasterStateAttribute = getBlasterStateAttribute()
attributeChangedConnection = player:GetAttributeChangedSignal(blasterStateAttribute):Connect(function()
local currentBlasterState = player:GetAttribute(blasterStateAttribute)
if currentBlasterState == BlasterState.Blasting then
endForceField()
end
end)
-- Kết thúc force field nếu người chơi đặt lại
characterRespawnedConnection = player.CharacterRemoving:Connect(endForceField)
-- Kết thúc force field sau 8 giây
task.delay(MAX_FORCE_FIELD_TIME, endForceField)
endForceField() bao gồm một câu lệnh if có vẻ lạ xung quanh boolean forceFieldEnded. Bởi vì các kiểm tra chạy theo thứ tự tuần tự, script có thể gọi hàm endForceField() hai hoặc ba lần. Boolean forceFieldEnded đảm bảo rằng hàm chỉ cố gắng phá hủy force field một lần duy nhất.
scheduleDestroyForceField
local function endForceField()
if forceFieldEnded then
return
end
forceFieldEnded = true
attributeChangedConnection:Disconnect()
characterRespawnedConnection:Disconnect()
destroyForceField(player)
end
Xử lý trạng thái client
Trong khi phần lớn phần này tập trung vào ServerScriptService ⟩ PlayerStateHandler, có một script khác cùng tên trong ReplicatedStorage. Lý do cho sự phân chia này là kiến trúc client-server:
Client cần hiểu thông tin trạng thái người chơi để có thể phản ứng phù hợp theo thời gian thực, chẳng hạn như hiển thị các yếu tố giao diện người dùng đúng, hoặc cho phép người chơi di chuyển và bắn.
Server cần tất cả thông tin này để ngăn chặn các khai thác. Ví dụ, server cũng cần trạng thái người chơi để thực hiện các hành động như spawn và trang bị nhân vật, vô hiệu hóa force fields, và hiển thị bảng điều khiển. Đây là lý do mà script này nằm trong ReplicatedStorage và không phải là một vị trí hoàn toàn ở phía client.
Để xem logic cốt lõi này, hãy xem script sau trong ReplicatedStorage ⟩ PlayerStateHandler xác nhận trạng thái hiện tại của người dùng, sau đó gọi hàm thích hợp xử lý các hành động tương ứng với trạng thái đó.
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
Tất cả các phản hồi sự kiện được nhóm lại hợp lý trong script này vì chúng yêu cầu hành vi tương tự về việc kích hoạt hoặc vô hiệu hóa các điều khiển của người chơi, di chuyển camera, và lớp giao diện người dùng nào là hiển thị. Ví dụ, trong quá trình lựa chọn blaster, người chơi cần cả việc không thể bị tổn thương và không thể di chuyển. Server đã xử lý force field, nhưng client xử lý việc di chuyển. Để chứng minh, nếu bạn kiểm tra logic cho hàm onSelectingBlaster(), bạn có thể thấy rằng client vô hiệu hóa việc di chuyển của người chơi trong khi họ đang chọn blaster.
PlayerStateHandler
local function onSelectingBlaster()
togglePlayerCamera(true)
togglePlayerMovement(false)
setGuiExclusivelyEnabled(playerGui.PickABlasterGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
Hàm onPlaying() cũng tương tự là đơn giản. Nó kích hoạt việc di chuyển, chuyển đến hiển thị chính (HUD), kích hoạt blaster, và gọi cùng một hàm force field như server.
PlayerStateHandler
local function onPlaying()
togglePlayerMovement(true)
setGuiExclusivelyEnabled(playerGui.HUDGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Ready)
scheduleDestroyForceField()
end
Respawn các nhân vật
Trải nghiệm laser tag mẫu xử lý việc respawning nhân vật trở lại một vòng thông qua trạng thái onTaggedOut() trong ReplicatedStorage ⟩ PlayerStateHandler. Giống như trạng thái onSelectingBlaster() và onPlaying(), onTaggedOut() kích hoạt hành vi độc đáo theo những thay đổi của thuộc tính playerState. Cụ thể, nó vô hiệu hóa việc di chuyển của người chơi, trình bày giao diện người dùng respawn, và vô hiệu hóa blaster.
PlayerStateHandler
local function onTaggedOut()
-- Vô hiệu hóa điều khiển khi bị đánh ra
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- Vô hiệu hóa blaster khi bị đánh ra
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
Nếu bạn muốn kiểm tra hành vi này, bạn có thể nhấn Esc, điều hướng đến tab Cài đặt, sau đó nhấp vào nút Đặt lại nhân vật. Chú ý rằng khi bạn kích hoạt màn hình respawn, bạn không thể di chuyển, quay camera, hoặc bắn blaster của mình.


Điều quan trọng cần lưu ý rằng script này thực sự không respawn các nhân vật, nó chỉ ngăn họ hành động và cung cấp phản hồi hình ảnh cho người chơi rằng server đang respawn các nhân vật của họ. Để chứng minh, nếu bạn kiểm tra ServerScriptService ⟩ SetupHumanoid ⟩ setupHumanoidAsync ⟩ onHumanoidDied, script đặt PlayerState thành TaggedOut (về cơ bản thông báo cho ReplicatedStorage ⟩ PlayerStateHandler), và thêm một số chỉ báo hình ảnh. Logic thực sự của việc respawning là một hành vi tích hợp của Roblox.
Khi người chơi respawn trở lại vòng đấu, họ spawn tại vị trí spawning của đội mình theo thuộc tính SpawnLocation.TeamColor. Để tùy chỉnh thời gian respawn, bạn có thể thêm dòng sau vào đầu SetupHumanoid. Để tìm hiểu thêm về kỹ thuật này, xem Players.RespawnTime.
SetupHumanoidlocal Players = game:GetService("Players")Players.RespawnTime = 10 -- dòng mới, tính bằng giây
Thiết lập đa dạng
Như một phần của thiết lập ban đầu, trải nghiệm laser tag mẫu cũng thực hiện một số bước nhỏ nhưng quan trọng:
Trải nghiệm bao gồm một script trống có tên StarterPlayer ⟩ StarterCharacterScripts ⟩ Health mà vô hiệu hóa sự phục hồi sức khỏe mặc định của Roblox. Để giải thích về hành vi của thuộc tính này, xem Humanoid.Health.
Trải nghiệm sử dụng camera góc nhìn thứ nhất bằng cách thiết lập thuộc tính StarterPlayer.CameraMode.LockFirstPerson. Lưu ý rằng nếu bạn muốn cho phép người dùng thay đổi giữa camera góc nhìn thứ nhất và thứ ba, bạn phải thay đổi thuộc tính này một cách lập trình thay vì chỉ thiết lập một lần trong Studio, và điều chỉnh các điều khiển và UI để bù đắp cho sự thay đổi trong góc nhìn.
Trải nghiệm sử dụng bảng điều khiển tích hợp của Roblox với đơn vị "điểm", mà người chơi kiếm được mỗi lần họ đánh ra một người chơi khác. Bạn có thể thấy cấu hình trong ServerScriptService ⟩ SetupLeaderboard, nhưng Bảng điều khiển trong trải nghiệm cung cấp một cái nhìn tổng quan đầy đủ. Lưu ý rằng onPlayerTagged thêm điểm vào bảng điều khiển, điều mà bạn sẽ tìm hiểu trong Thêm vòng và Phát hiện cú đánh.
Bây giờ mà người chơi có thể spawn, chọn một blaster và nhắm từ góc nhìn thứ nhất, phần tiếp theo sẽ dạy cho bạn về các script đứng sau việc tạo ra gameplay theo vòng.