跳至正文
版本:最新版 - a1.169.2 ⚖️

玩家生命周期

从玩家连接到离开期间触发的事件,以及执行各操作的恰当时机。

概述​

当有人加入你的服务器时,按顺序触发的主要事件如下:

#事件端发生了什么
1PlayerConnect (Server)Server有人正在尝试连接。 Player 尚不存在
2Player 上的 SpawnServerPlayer 实体已创建。客户端仍在加载地图并下载文件
3SpawnLocalPlayer (Client)Client客户端已完成加载,可以通过 Client.GetLocalPlayer() 获取其自身的 Player
4ReadyServer客户端已完全加载地图和所有实体,准备好开始游戏
5Possess两者Player 开始控制一个 Pawn(例如 Character)
-UnPossess两者Player 停止控制 Pawn
6Player 上的 Destroy两者Player 离开了服务器
7PlayerDisconnect (Server)Server连接已关闭,并附带断开连接的原因
信息

Player 代表已连接的玩家,而 Character 代表世界中的一个身体。 Player 可以在没有 Character 的情况下存在(如作为旁观者飞行),Character 也可以在没有 Player 的情况下存在(如作为 NPC)。请参见玩家 vs 角色 vs Pawn。

拒绝连接​

PlayerConnect (Server) 会在 Player 实体存在之前触发,因此适合在此处拒绝连接,例如当玩家不在白名单中时:

Server/Index.lua
local whitelist = {
["123456789"] = true,
}

Server.Subscribe("PlayerConnect", function(ip, player_account_id, player_name, player_steam_id)
if (not whitelist[player_account_id]) then
Server.KickByAccountID(player_account_id, "你不在白名单中!")
end
end)
提示

你可以调用 Server.KickByAccountID() 或 Server.BanByAccountID() 在未生成完整 Player 实体的状态下踢出或封禁玩家。

赋予玩家角色​

你可以在 Player 生成时立即生成并附身一个 Character,客户端完成加载后就能看到它:

Server/Index.lua
function SpawnCharacterForPlayer(player)
-- 从地图上随机选择一个出生点(若存在)
local spawn_points = Server.GetMapSpawnPoints()
local spawn = spawn_points[math.random(#spawn_points)] or { location = Vector(0, 0, 100), rotation = Rotator() }

local character = Character(spawn.location, spawn.rotation, "nanos-world::SK_Male")
player:Possess(character)
end

Player.Subscribe("Spawn", SpawnCharacterForPlayer)

-- 此外,当包(重新)加载时,也会向已连接的玩家分配角色
Package.Subscribe("Load", function()
for _, player in pairs(Player.GetPairs()) do
if (not player:GetControlledCharacter()) then
SpawnCharacterForPlayer(player)
end
end
end)
提示

当你需要客户端完全加载完毕时(例如发送远程事件、显示欢迎消息或仅在玩家实际能看到时才开始倒计时),请改用 Ready 事件。

重生​

当 Character 死亡时,它不会被销毁,而是保持布娃娃状态。你可以一段时间后使用 :Respawn() 让其重生,这会恢复其生命值并将其移动到指定位置:

Server/Index.lua
Character.Subscribe("Death", function(character, last_damage_taken, last_bone_damaged, damage_type_reason, hit_from_direction, instigator)
-- 仅重生由玩家控制的角色
if (not character:GetPlayer()) then return end

Timer.SetTimeout(function()
-- 在此期间,角色(或玩家)可能已被销毁
if (not character:IsValid()) then return end

character:Respawn(Vector(0, 0, 100), Rotator())
end, 5000)
end)

玩家离开时清理​

当 Player 离开时,Character 不会被自动销毁,因此你通常需要手动销毁它:

Server/Index.lua
Player.Subscribe("Destroy", function(player)
local character = player:GetControlledCharacter()
if (character) then
character:Destroy()
end
end)

在客户端​

在客户端,本地玩家仅在 SpawnLocalPlayer 之后可用。要跟踪本地玩家正在控制的角色(例如更新 HUD),请订阅其 Possess 事件:

Client/Index.lua
Client.Subscribe("SpawnLocalPlayer", function(local_player)
local_player:Subscribe("Possess", function(player, character)
Console.Log("我现在在控制 %s", tostring(character))
end)
end)

有关完整示例,请参见基本 HUD(画布)教程。