生成 是創建體驗中的對象或角色的過程,而 重生 是創建對象或角色後再重新加入體驗的過程。 兩個過程都很重要,因為它們確保玩家能夠加入您的體驗,並且繼續玩遊戲來改善他們的技能。
使用 示例雷射標籤體驗 作為參考,這個教學的第一部分教學你如何使用並自訂 Roblox 的內置功能來處理重生和重生,包括指令碼指南:
- 設置玩家只能在自己的團隊的重生區域重生。
- 在玩家加入體驗時添加新玩家和他們的角色。
- 自訂防止玩家生成和重生時傷害的力場。
- 處理客戶端狀態,以便遊戲正常運行。
- 在標籤結束後重生角色。
- 執行小型、隨機的動作,對於設置遊戲玩法和角色參數至關重要。
此部分包含大量的腳本內容,但而不是從零開始創建體驗時,它會鼓勵您利用現有組件,快速迭代,並解決哪些系統需要自訂實現才能符合您的愿景。 完成此部分後,您將學會如何實現基於回合的遊戲體驗,跟蹤點數、監視玩家狀態和顯示回合結果。
配置重生位置
如果您現在玩測試體驗,所有玩家將會在綠團隊的生成區域中的 SpawnLocation 對象或粉紅團隊的生成區域中的 SpawnLocation 對象隨機生成。這會導致一個遊戲體驗問題,玩家可以在每個生成區域標籤自己在每個生成區域中,當其對手
為了解決此問題,樣本雷射標籤體驗將兩個重要的生成位置設置為 Neutral 以限制對手團隊伍的玩家在錯誤的重生區域生成,並且將
當玩家加入體驗時, ServerScriptService > 遊戲體驗 > 回合 > 1>淘汰輪1> > 4>生成玩家在地圖4> > 7>回合最少玩家7> 檢查,然後將隊團隊與最少玩家返回。
生成玩家在地圖上
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 屬性為 關閉 ,因此玩家只能在他們的團隊伍生成位置重生,然後將其設置為 PlayerState ,這是您在教學中後半部分的內容
生成玩家在地圖上
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
如果您檢查 工作區 > 世界 > 地圖 > 1>生成1> > 4>中立Spawn4> ,
例如,如果回合啟用,Neutral 屬性設為false,因此生成PlayersInMap
要示範,如果您檢查 ServerScriptService > 遊戲播放 > 回合 > 1> 玩家1> > 4> SpawnPlayersInLobby4> ,這在回合結束時您可以看到,每個玩家通過 7> players: Player7> 桌子,指令碼:
- 將其 Player.Neutral 屬性設為 true,自動將其 Player.Team 重設為 nil,允許玩家在回合未啟用時在大廳重生,因為這個 Spawn 位置的 Neutral 屬性也設為 1> true1>。
- 將 PlayerState 變更為 InLobby 以移除玩家的虛擬實境用戶界面視覺效果。
有關中立生成區的功能和結構,請在在教學的下一個部分中參閱<Add Rounds>。
生成玩家在大廳
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
連接新玩家
Studio 中的 Luau 代碼通常是事件駕駛,這意味著腳本會從 Roblox 服務中聽取事件,然後按照回應呼叫函數。例如,當添加新玩家到多人遊戲體驗時,必須有一個事件處理所有必要玩家連接成功的事件。在示例雷射標籤體驗中,這個相應的事件是 Players.PlayerAdded:Connect
Players.PlayerAdded:Connect 是體驗中的一部分多個指令碼。如果您使用 Ctrl/Command+Shift+F 快捷方式並搜尋 Players.PlayerAdded:Connect,結果為您提供了一個良好的起始點來了解體驗的初始設定。
要示範,請打開 ServerScriptService > 設定人形號碼 。 與 Player 和 1> Class.Player.Character|Character1> 之間的區別是了解此指令碼的關鍵:
- 玩家需要選擇一個噴射器,並被添加到排行榜。玩家需要重生並接受一個噴射器。
SetupHumanoid 立即檢查玩家是否有角色(剛剛加入)或不(重生)。找到一個後,它會呼叫 onCharacterAdded()
設定人形錯誤
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 為 顯示受損時間 。
- 如果你想要角色在其生命值達到 0 時分解,設定 Humanoid.BreakJointsOnDeath 為 真 。
如果您變更這些屬性的值,重要的是,您需要進行游戲測試,以便您可以看到新設定的影響。 您可以在多個玩家環境中重現玩家體驗,選擇在 客戶和伺服器 標籤的至少兩個角色。
另一個例子的 Players.PlayerAdded:Connect 事件在 ServerScriptService > PlayerStateHandler 中。與上一個示例相同,2>PlayerStatusHandler2> 立即檢
玩家狀態處理器
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 。這個表存儲所有玩家和其的 Datatype.RBXScriptConnection|Connections
玩家狀態處理器
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() 設置 1>
玩家狀態處理器
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
如果你在體驗中添加生成地點或甚至
自訂力場
而不是使用自訂實現,示例雷射標籤體驗使用 Studio 的內置 ForceField 類來防止玩家在選擇他們的雷射時受到傷害。這確保玩家只需要具有 Class.S
與 setupHumanoidAsync 類似,大多數線在 ForceFieldClientVisuals 中是可選的。例如,如果您評論評論評論評論評論評論評論評論評論評論評論評論評論評論評論評論評論評論評論評論
在 ForceFieldClientVisuals 中評論特性
local function onCharacterAddedAsync(character: Model)
-- 本地 forceField = character:WaitForChild("ForceField", 3)
-- 如果不是 forceField 則
-- 傳回回
-- 結束
-- forceField.Visible = 關閉
-- localPlayer.PlayerGui:WaitForChild("ForceFieldGui")
-- forceField.Destroying:等待()
-- 本地玩家.PlayerGui.ForceFieldGui.Enabled = false
end
因為自訂力場是一個 GUI 而不是新的 ParticleEmitter ,因此 ForceFieldClientVisuals 指令只會影響每個玩家的第一人稱視圖,而不是第三人稱視圖,當玩家看向其他玩家時。 第三人稱視圖會保留 Roblox 外觀。
力場很有用,因為它們提供玩家足夠的時間來在重生和重生之間,而不需要擔心敵人玩家,但最終它們需要消失以獲得主要雷射標籤遊玩的玩法。處理力場移除的腳本在 ReplicatedStorage > scheduleDestroyForceField 中,檢查三個獨特條件:
- 玩家選擇了一個噴射器後,力場需要足夠的時間才能允許玩家適應環境。
- 在這段時間內,力場不能是優勢,因此它們需要在玩家發射他們的激光器時消失。
- 強制力場需要在玩家重設他們的角色時前方或強制力場時間到達前方。
這些檢查在 scheduleDestroyForceField 指令碼 endForceField() 中對於這些條件 endForceField 的 1>endForceField1> 。
訂程DestroyForceField
-- 玩家爆炸時結束力場
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 Boolean 周圍。因為檢查是順序的,因此腳本可以呼叫 0> endForceField0> 函數兩次或三次。endForceField()3> 保證腳功
訂程DestroyForceField
local function endForceField()
if forceFieldEnded then
return
end
forceFieldEnded = true
attributeChangedConnection:Disconnect()
characterRespawnedConnection:Disconnect()
destroyForceField(player)
end
處理客戶狀態
雖然這個部分大多數是關於 ServerScriptService > PlayerStateHandler ,但在 ReplicatedStorage 裡有另一個名為相同的指令碼。 理由是客戶端-伺服器架構:
客戶端需要了解玩家狀態信息,以便能夠在實時回應中合適地回應,例如顯示正確的使用者介面元素或啟用玩家移動和爆炸。
為了能夠防止惡意損壞,伺服器需要這些相同的資訊。例如,伺服器還需要玩家狀態才能執行生成和裝備角色、關閉力場和顯示排行榜。這就是為什麼這個指令在 ReplicatedStorage 中,而不是單獨的客戶端位置。
要查看此核心原理,請在 ReplicatedStorage > 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 層可以顯示。 例如,在選擇玩具時,玩家需要同時具有無法移移動工具的狀態和無法移動的狀態。 服務器處理
玩家狀態處理器
local function onSelectingBlaster()
togglePlayerCamera(true)
togglePlayerMovement(false)
setGuiExclusivelyEnabled(playerGui.PickABlasterGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
onPlaying() 函數的結構與 onPlayer 相同。它啟用移動、轉換到主頭顯示器 (HUD)、啟用雷射和呼叫與服務伺服器相同的力場功能。
玩家狀態處理器
local function onPlaying()
togglePlayerMovement(true)
setGuiExclusivelyEnabled(playerGui.HUDGui)
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Ready)
scheduleDestroyForceField()
end
重生角色
樣本雷射標籤體驗處理重生角色返回onTaggedOut() 狀態在 ReplicatedStorage > PlayerStateHandler 。像1> onSelecting
玩家狀態處理器
local function onTaggedOut()
-- 在被標籤為 "關閉" 時停用控制
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- 在被標記為 "關閉" 時停用爆破器
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
如果您想測試此行為,您可以按下 Esc ,移動到 設定 標籤,然後按一下 重設角色 按鈕。注意,當您啟動重生屏幕時,您無法移動工具、旋轉相攝影機或爆炸您的衝擊劍。
重要的是,這個指令不會重生角色,它只會停止他們行動並提供視
玩家重生時,會在他們的團隊的重生位置按照 SpawnLocation.TeamColor 屬性的位置重生。要自訂重生時間,您可以在 SetupHumanoid 的頂部添加以下線。要了解更多關於此技術的內容,請參閱 Players.RespawnTime 。
人形設定
local Players = game:GetService("Players")Players.RespawnTime = 10 -- new line, in seconds
其他設定
初始設定的一部分,也會執行一些小,但非常重要的步驟:
體驗包含名為 StarterPlayer > StarterCharacterScripts > Health 的空腳本,這會停用預設 Roblox 生命值重生。對此屬性的說明,請參閱 1>Class.Humanoid.Health1> 。
體驗使用第一人稱視角設置 StarterPlayer.CameraMode.LockFirstPerson 屬性來設置視頻攝影機。如果您想要讓用戶在第一人稱和第三人稱攝影機之間切換,您必須在 Studio 中設置程式碼而不是只是設置一次,並修改控制和用戶界面來補償這次變更。
體驗使用內置的 Roblox 排行榜,其單位是「點」,玩家每次標記其他玩家時會獲得。 您可以在 ServerScriptService > 設置排行榜 中查看配置,但 In-Experience Leader
現在玩家可以重生,選擇一把槍枝,並且從第一人稱模式查檢視,下一個部分教你關於創建回合制遊玩的腳本。