饥荒通用升级组件

1. 组件介绍

  1. 组件只负责处理等级数值的改变和调用传入的函数,等级改变时执行的函数和最高级时执行的函数应该在每个预制体里定义。
  2. 组件含有一个标签"前缀_upgradable",当处于可升级的状态时就自动添加该标签,可用于在AddComponentAction中判断,这个前缀是文件名的前缀,因此不同mod的升级组件相互独立。
  3. 组件含有配套附件,有一个网络变量current,可用于在客户端读取对象的等级。
  4. 组件只负责保存等级和调用两个函数,并且在加载时会根据保存的等级自动调用函数。

下面给出组件源码,统一采用前缀upt_

  1. 组件代码
-- scripts/components/upt_upgrade.lua

local componentPre = debug.getinfo(1, 'S').source:match("([^/]+)_upgrade%.lua$") --当前文件前缀
local componentName = componentPre .. "_upgrade"
local upgradableTag = componentPre .. "_upgradable" --可升级标签,在这里值为upt_upgradable

local function OnChanged(self)
    local has = self.inst:HasTag(upgradableTag)
    if self.current and self.maxLevel and self.current < self.maxLevel then
        if not has then
            self.inst:AddTag(upgradableTag)
        end
    else
        if has then
            self.inst:RemoveTag(upgradableTag)
        end
    end
end

local function oncurrent(self, current)
    self.inst.replica[componentName]:SetLevel(current)

    OnChanged(self)
end

--- 简单通用升级组件,只保存当前等级,其他东西都需要每次设置
local Upgrade = Class(function(self, inst)
    self.inst = inst

    self.initLevel = 0                                 --初始等级
    self.current = self.initLevel                      --当前等级
    self.maxLevel = 0                                  --满级
    self.onLevelChangeFn = nil                         --当等级改变时
    self.onMaxLevelFn = nil                            --当最高级时

    self.upSound = "dontstarve/wilson/equip_item_gold" --升级音效
end, nil, {
    current = oncurrent,
    maxLevel = OnChanged
})

---初始配置
---@param initLevel number|nil 初始等级
---@param maxLevel number 最高级
---@param onLevelChangeFn function|nil 当等级改变时,(inst,doer,count,isLoading)
---@param onMaxLevelFn function|nil 当最高级时,(inst,isLoading)
function Upgrade:Configure(initLevel, maxLevel, onLevelChangeFn, onMaxLevelFn)
    self.initLevel = initLevel or self.initLevel
    self.maxLevel = maxLevel or self.maxLevel
    self.current = self.initLevel
    self.onMaxLevelFn = onMaxLevelFn
    self.onLevelChangeFn = onLevelChangeFn
end

function Upgrade:Upgrade(doer, count)
    if count > 0 and self.current >= self.maxLevel then
        return false, "MAX_LEVEL" --不应该发生,升级前应该判断标签
    elseif count < 0 and self.current <= self.initLevel then
        return false, "MIN_LEVEL"
    end

    count = count or 1
    self.current = math.min(self.current + count, self.maxLevel) --虽然这里判断了,但是主要判断应该在调用之前,因为同时也涉及到物品的消耗数量

    if self.onLevelChangeFn then
        self.onLevelChangeFn(self.inst, doer, count, false)
    end

    if self.onMaxLevelFn and self.current >= self.maxLevel then
        self.onMaxLevelFn(self.inst, false)
    end

    if self.upSound then
        if doer and doer.SoundEmitter then
            doer.SoundEmitter:PlaySound(self.upSound)
        elseif self.inst.SoundEmitter then
            self.inst.SoundEmitter:PlaySound(self.upSound)
        end
    end

    return true
end

function Upgrade:GetNeed()
    return self.maxLevel - self.current
end

function Upgrade:GetPercent()
    return self.current / self.maxLevel
end

function Upgrade:IsFull()
    return self.current >= self.maxLevel
end

function Upgrade:OnSave()
    return {
        current = self.current
    }
end

function Upgrade:OnLoad(data)
    if not data then return end
    if data.current then
        self.current = data.current
        if self.current > self.initLevel then
            self.inst:DoTaskInTime(0, function() --一般初始化都需要等其他东西加载后
                if self.onLevelChangeFn then
                    self.onLevelChangeFn(self.inst, nil, self.current, true)
                end
                if self.current >= self.maxLevel and self.onMaxLevelFn then
                    self.onMaxLevelFn(self.inst, true)
                end
            end)
        end
    end
end

return Upgrade
  1. 组件副本
-- scripts/components/upt_upgrade_replica.lua

local componentPre = debug.getinfo(1, 'S').source:match("([^/]+)_upgrade_replica%.lua$") --当前文件前缀
local componentName = componentPre .. "_upgrade"

local Upgrade = Class(function(self, inst)
    self.inst = inst

    self.current = net_smallbyte(inst.GUID, componentName .. ".current") --[0..63]
end)

function Upgrade:SetLevel(level)
    self.current:set(level)
end

function Upgrade:GetLevel()
    return self.current:value()
end

return Upgrade

2. 使用方法

  1. 为可升级对象添加upt_upgrade组件,并且调用Configure方法配置,可配置的数据有:
  • 初始等级
  • 满级等级
  • 当等级改变时调用的函数
  • 当满级时的调用的函数
  1. 创建带有升级逻辑的Actions,在函数中调用升级组件的Upgrade方法。
  2. 定义AddComponentAction,设置触发升级动作的条件。

3. 使用案例

这是一个用木头升级万物的例子,初始等级为0级,满级为20级,鼠标移动到对象上可查看当前等级。

案例代码

posted @ 2024-04-30 10:09  高价领主  阅读(113)  评论(0)    收藏  举报