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

基本 HUD(画布)

如何使用渲染器的画布功能添加一个基本 HUD,以显示角色的生命值和弹药量。

提示

你也可以使用 HTML + JavaScript + CSS 创建完整且复杂的 UI,快来看看吧:基本 HUD(HTML)

画布(Canvas)可以用来绘制图形。 以下代码展示了如何使用画布添加基础 UI:

Client/Index.lua
-- 生成画布
HUDCanvas = Canvas(true, Color.TRANSPARENT, 0, true)

-- 订阅 Update 事件,我们只能在该事件内部进行绘制
HUDCanvas:Subscribe("Update", function(self, width, height)
-- 获取本地玩家
local local_player = Client.GetLocalPlayer()
if (not local_player) then return end

-- 获取本地角色(由本地玩家控制)
local local_character = local_player:GetControlledCharacter()
if (not local_character) then return end

-- 绘制生命值
self:DrawText(tostring(local_character:GetHealth()), Vector2D(100, height - 100), FontType.PoiretOne, 25, Color.WHITE)

-- 获取本地武器
local character_weapon = local_character:GetPicked()
if (character_weapon and character_weapon:IsA("Weapon")) then
-- 绘制弹夹弹药数
self:DrawText(tostring(character_weapon:GetAmmoClip()), Vector2D(width - 200, height - 100), FontType.PoiretOne, 25, Color.WHITE)

-- 绘制弹药袋弹药数
self:DrawText("/ " .. tostring(character_weapon:GetAmmoBag()), Vector2D(width - 140, height - 87), FontType.PoiretOne, 15, Color.WHITE)
end
end)

上面的示例在每个刻都会重新渲染并更新所有生命值/弹药信息,这可能会影响性能。 幸运的是,我们可以通过在构造函数中修改自动重绘速率来限制它,从而快速改善性能:

-- 在 auto_repaint_rate 参数中不使用 0
HUDCanvas = Canvas(true, Color.TRANSPARENT, 0, true)

-- 使用 0.033,这样它只每 0.033 秒更新一次(即 30 fps)
HUDCanvas = Canvas(true, Color.TRANSPARENT, 0.033, true)

另一种进一步的优化是仅在需要时进行更新,对于这种情况,我们需要实现一些额外的代码。 在这种情况下,我们将 auto_repaint_rate 设置为 -1 以禁用自动重绘:

-- 我们将其设置为 -1 以永不自动重绘
HUDCanvas = Canvas(true, Color.TRANSPARENT, -1, true)

-- 订阅 Update 事件,我们只能在该事件内部进行绘制(像往常一样)
HUDCanvas:Subscribe("Update", function(self, width, height)
-- 获取本地玩家
local local_player = Client.GetLocalPlayer()
if (not local_player) then return end

-- 获取本地角色(由本地玩家控制)
local local_character = local_player:GetControlledCharacter()
if (not local_character) then return end

-- 绘制生命值
self:DrawText(tostring(local_character:GetHealth()), Vector2D(100, height - 100), FontType.PoiretOne, 25, Color.WHITE)

-- 获取本地武器
local character_weapon = local_character:GetPicked()
if (character_weapon and character_weapon:IsA("Weapon")) then
-- 绘制弹夹弹药数
self:DrawText(tostring(character_weapon:GetAmmoClip()), Vector2D(width - 200, height - 100), FontType.PoiretOne, 25, Color.WHITE)

-- 绘制弹药袋弹药数
self:DrawText("/ " .. tostring(character_weapon:GetAmmoBag()), Vector2D(width - 140, height - 87), FontType.PoiretOne, 15, Color.WHITE)
end
end)


-- 现在我们订阅希望它更新的时机:

-- 当 LocalPlayer 生成时,在其上设置一个事件,以便在我们控制新角色时触发,在本地存储本地控制的角色。该事件仅调用一次,请参阅 Package.Subscribe("Load") 以在重新加载包时加载它
Client.Subscribe("SpawnLocalPlayer", function(local_player)
local_player:Subscribe("Possess", function(player, character)
UpdateLocalCharacter(character)
end)
end)

-- 当包加载时,验证 LocalPlayer 是否已存在(例如在重新加载包时),然后尝试获取并存储其控制的角色
Package.Subscribe("Load", function()
local local_player = Client.GetLocalPlayer()
if (local_player ~= nil) then
UpdateLocalCharacter(local_player:GetControlledCharacter())
end
end)

-- 在本地角色上设置所有所需事件的函数(以便在其受到伤害或死亡时更新 UI)
function UpdateLocalCharacter(character)
-- 验证 character 是否不为 nil(例如当 GetControllerCharacter() 未返回角色时)
if (character == nil) then return end

-- 在角色上设置一个事件,以便在其受到伤害后更新生命值 UI
character:Subscribe("TakeDamage", function(charac, damage, type, bone, from_direction, instigator, causer)
HUDCanvas:Repaint()
end)

-- 在角色上设置一个事件,以便在其死亡后更新生命值 UI
character:Subscribe("Death", function(charac)
HUDCanvas:Repaint()
end)

-- 在角色上设置一个事件以更新其抓取的武器(在 UI 上显示弹药)
character:Subscribe("PickUp", function(charac, object)
if (object:IsA("Weapon")) then
HUDCanvas:Repaint()
end
end)

-- 在角色上设置一个事件,以便在其丢弃武器时移除弹药 UI
character:Subscribe("Drop", function(charac, object)
HUDCanvas:Repaint()
end)

-- 在角色上设置一个事件,以便在其开火时更新 UI
character:Subscribe("Fire", function(charac, weapon)
HUDCanvas:Repaint()
end)

-- 在角色上设置一个事件,以便在其换弹时更新 UI
character:Subscribe("Reload", function(charac, weapon, ammo_to_reload)
HUDCanvas:Repaint()
end)

-- 立即更新 UI
HUDCanvas:Repaint()
end

-- 当视口(屏幕)调整大小时更新 UI 位置
Client.Subscribe("ViewportResized", function(NewSize)
HUDCanvas:Repaint()
end)