Bag = {}

function Bag.Init(isWin32)
    -- 背包容器的可视区域宽度
    -- PC端为338像素,移动端为500像素
    Bag._PWidth       = isWin32 and 338 or 500     
    
    -- 背包容器的可视区域高度
    -- PC端为214像素,移动端为320像素
    Bag._PHeight      = isWin32 and 214 or 320     
    
    -- 背包单个物品格子的宽度
    -- PC端为42.8像素,移动端为62.5像素
    Bag._IWidth       = isWin32 and 42.8 or 62.5   
    
    -- 背包单个物品格子的高度
    -- PC端为40.6像素,移动端为64像素  
    Bag._IHeight      = isWin32 and 40.6 or 64     
    
    -- 背包格子的行数,固定为5行
    Bag._Row          = 5       
    
    -- 背包格子的列数,固定为8列
    Bag._Col          = 8       
    
    -- 每页背包可容纳的物品数量
    -- 由行数和列数相乘得到: 5 * 8 = 40
    Bag._PerPageNum   = 40      
    
    -- 系统默认的每页格子数量
    -- 用于与自定义格子数量进行比较
    Bag._defaultNum   = 40      
    
    -- 背包最大页数限制,最多5页
    Bag._MaxPage      = 5       
    
    -- 是否需要代码动态生成背包格子
    -- 当UI中没有预设格子线或滚动容器时需要代码生成
    Bag._codeInitGrid = false   

    -- 是否处于存入英雄背包的模式
    Bag._changeStoreMode = false
    
    -- 当前开放的背包页数,默认1页
    Bag._bagPage    = 1     
    
    -- 当前选中的背包页签索引,初始为0
    Bag._selPage    = 0     
    
    -- 从系统获取背包开放的最大格子数
    Bag._openNum    = SL:GetMetaValue("MAX_BAG")

    -- 背包格子锁定状态的图标路径
    Bag._lockImg   = "res/public/icon_tyzys_01.png"
    
    -- 摆摊相关图标路径
    -- PC端和移动端使用不同的图标
    Bag._baiTanImg = isWin32 and "res/public/word_bqzy_09_1.png" or "res/public/word_bqzy_09.png"

    -- 存储背包页签按钮的引用
    Bag._bagPageBtns = {}
end

function Bag.main(page)
    local parent = GUI:Attach_Parent() -- 获取当前打开界面挂接点
    local isWin32 = SL:GetMetaValue("WINPLAYMODE")
    GUI:LoadExport(parent, isWin32 and "bag/bag_panel_win32" or "bag/bag_panel")

    Bag._ui = GUI:ui_delegate(parent)
    Bag._UI_ScrollView = Bag._ui["ScrollView_items"]

    -- 初始化数据
    Bag.Init(isWin32)

    -- 适配
    -- 设置背包面板的垂直位置
    -- PC端: 使用预设的PC_POS_Y值作为固定位置
    -- 移动端: 将面板放置在屏幕垂直中心位置(屏幕高度/2)
    GUI:setPositionY(Bag._ui["Panel_1"], isWin32 and SL:GetMetaValue("PC_POS_Y") or SL:GetMetaValue("SCREEN_HEIGHT") / 2)

    -- 界面拖动
    GUI:Win_SetDrag(parent, Bag._ui["Image_bg"])

    -- 界面浮起 设置背包界面在打开时自动浮到其他界面之上
    GUI:Win_SetZPanel(parent, Bag._ui["Image_bg"])

    GUI:addOnClickEvent(Bag._ui["Button_close"], function()
        SL:CloseBagUI()
    end)

    -- 存入英雄背包
    local Button_store_hero_bag = Bag._ui["Button_store_hero_bag"]
    GUI:addOnClickEvent(Button_store_hero_bag, function()
        local changeStoreMode = not Bag._changeStoreMode
        if changeStoreMode then
            local isActiveHero = SL:GetMetaValue("HERO_IS_ACTIVE")
            if not isActiveHero then
                return SL:ShowSystemTips("英雄还未激活")
            end
            local isCallHero = SL:GetMetaValue("HERO_IS_ALIVE")
            if not isCallHero then
                return SL:ShowSystemTips("英雄还未召唤")
            end
        end
        -- 更新背包的存入英雄背包模式状态
        Bag._changeStoreMode = changeStoreMode
        -- 设置存入英雄背包按钮的灰化状态
        -- 当changeStoreMode为true时按钮灰化,表示当前处于存入模式
        -- 当changeStoreMode为false时按钮恢复正常,表示退出存入模式
        GUI:Button_setGrey(Button_store_hero_bag, changeStoreMode)
    end)
    GUI:setVisible(Button_store_hero_bag, SL:GetMetaValue("USEHERO"))

    -- 初始化左侧背包页签
    Bag.InitPage()

    Bag.PageTo(page or 1)

    Bag.OnUpdateGold()

    Bag.RegisterEvent()
end

-- 初始化背包页签,最大页数计算和页数按钮的事件显示和绑定
function Bag.InitPage()
    -- 计算当前背包应该显示的页数
    -- _openNum: 系统允许开放的最大格子数
    -- _PerPageNum: 每页可容纳的格子数
    -- 通过向上取整确保所有格子都有对应的页签
    Bag._bagPage = math.ceil(Bag._openNum / Bag._PerPageNum)
    -- 确保至少有1页
    Bag._bagPage = math.max(Bag._bagPage, 1)
    -- 限制最大页数不超过系统设定值
    Bag._bagPage = math.min(Bag._bagPage, Bag._MaxPage)

    -- 遍历所有可能的页签按钮(最大5页)
    for i = 1, Bag._MaxPage do
        -- 获取对应页签按钮的UI引用
        local pageBtn = Bag._ui["Button_page" .. i]
        -- 默认隐藏所有页签
        GUI:setVisible(pageBtn, false)
        
        -- 当背包页数大于1页且当前页签序号在允许范围内时
        if Bag._bagPage ~= 1 and i <= Bag._bagPage then
            -- 显示当前页签
            GUI:setVisible(pageBtn, true)
            -- 设置页签的标识号
            GUI:setTag(pageBtn, i)
            -- 保存页签按钮引用到全局表中
            Bag._bagPageBtns[i] = pageBtn
            
            -- 为页签按钮添加点击事件
            -- TouchSize是按钮的点击热区节点
            GUI:addOnClickEvent(GUI:getChildByName(pageBtn, "TouchSize"), function()
                -- 如果点击的是当前选中的页签则不处理
                if Bag._selPage == i then
                    return false
                end
                -- 切换到目标页签
                Bag.PageTo(i)
                -- 如果存在更新物品的方法则调用
                -- 用于刷新该页的物品显示
                if Bag.UpdateItems then
                    Bag.UpdateItems()
                end
            end)
        end
    end
end

function Bag.PageTo(page)
    if Bag._selPage == page then
        return false
    end
    SL:SetMetaValue("BAG_PAGE_CUR", page)
    Bag._selPage = page
    Bag.SetPageBtnStatus()
end

-- 更新背包页签按钮的显示状态
-- 根据当前选中的页签索引(Bag._selPage)设置所有页签按钮的视觉效果
function Bag.SetPageBtnStatus()
    -- 遍历所有已开放的背包页签
    for i = 1, Bag._bagPage do
        -- 获取当前页签按钮的引用
        local btnPage = Bag._bagPageBtns[i]
        if btnPage then
            -- 判断当前页签是否被选中
            local isPress = i == Bag._selPage and true or false
            -- 设置按钮的明暗状态
            -- 选中的按钮变暗(not isPress为false),未选中的按钮正常显示
            GUI:Button_setBright(btnPage, not isPress)
            -- 设置按钮的层级顺序
            -- 选中的按钮层级最高(Bag._bagPage + 1),未选中的使用原始标识号
            GUI:setLocalZOrder(btnPage, isPress and Bag._bagPage + 1 or GUI:getTag(btnPage))
            -- 获取页签上的文本节点
            local pageText = GUI:getChildByName(btnPage, "PageText")
            -- 设置文本颜色
            -- 选中状态使用浅色(#f8e6c6),未选中使用深色(#807256)
            GUI:Text_setTextColor(pageText, isPress and "#f8e6c6" or "#807256")
            -- 设置文本缩放
            -- 选中状态正常大小(1),未选中略小(0.9)
            GUI:setScale(pageText, isPress and 1 or 0.9)
        end
    end
end

-- 初始化背包格子的网格线
-- 通过在滚动容器中创建横竖线条来形成背包格子的视觉边界
function Bag.InitGird()
    -- 用于生成格子线的唯一标识符
    local index = 0
    
    -- 遍历生成网格
    -- 行数和列数都+1是因为需要多一条线来封闭最后一个格子
    for i = 1, Bag._Row + 1 do
        for j = 1, Bag._Col + 1 do
            -- 计算当前格子线的坐标
            -- x坐标: 从左到右,每列间隔一个格子宽度
            local x = (j-1) * Bag._IWidth
            -- y坐标: 从上到下,每行间隔一个格子高度
            -- 使用ScrollHeight是因为坐标系原点在左下角
            local y = Bag._ScrollHeight - (i-1) * Bag._IHeight

            -- 创建竖线(除了最后一行都需要创建)
            if i <= Bag._Row then
                -- 创建竖线图片,使用唯一的标识名
                local pGird1 = GUI:Image_Create(Bag._UI_ScrollView, "Grid_1_" .. index, x, y, "res/public/bag_gezi.png")
                -- 设置锚点
                -- 第一列的竖线锚点在底部(0,0),其他列在顶部(0,1)
                GUI:setAnchorPoint(pGird1, 0, j == 1 and 0 or 1)
                -- 将图片旋转90度形成竖线
                GUI:setRotation(pGird1, 90)
                index = index + 1
            end

            -- 创建横线(除了最后一列都需要创建)
            if j <= Bag._Col then
                -- 创建横线图片,使用唯一的标识名
                local pGird2 = GUI:Image_Create(Bag._UI_ScrollView, "Grid_2_" .. index, x, y, "res/public/bag_gezi.png")
                -- 设置锚点
                -- 第一行的横线锚点在顶部(0,1),其他行在底部(0,0)
                GUI:setAnchorPoint(pGird2, 0, i == 1 and 1 or 0)
                index = index + 1
            end
        end
    end
end

-- 重置初始参数
-- 重置背包界面的初始化参数
-- 主要处理PC端特殊的背包格子布局配置和滚动容器的尺寸设置
function Bag.ResetInitData( ... )
    -- 获取当前是否为PC端
    local isWinMode = SL:GetMetaValue("WINPLAYMODE")
    -- 获取PC端特殊的背包行列配置
    -- 格式为: "列数|行数", 例如: "8|5"
    local bag_row_col = SL:GetMetaValue("GAME_DATA", "bag_row_col_max")
    
    -- 仅在PC端且存在特殊配置时处理
    if isWinMode and bag_row_col then 
        -- 分割配置字符串获取行列数
        local slices = string.split(bag_row_col, "|") 
        -- 设置背包行数,如果转换失败则使用默认值5
        Bag._Row = tonumber(slices[2]) or 5
        -- 设置背包列数,如果转换失败则使用默认值8
        Bag._Col = tonumber(slices[1]) or 8
        -- 重新计算每页可容纳的物品数量
        Bag._PerPageNum   = Bag._Row * Bag._Col

        -- 当每页格子数量超过默认值时隐藏页签
        -- 因为此时一页就能容纳所有物品,不需要分页
        if Bag._PerPageNum > Bag._defaultNum then 
            for i = 1, Bag._MaxPage do
                local pageBtn = Bag._ui["Button_page"..i]
                GUI:setVisible(pageBtn, false)
            end
        end 
    end 

    -- 获取背包滚动容器的尺寸
    local pSize = GUI:getContentSize(Bag._UI_ScrollView)
    -- 设置滚动容器的内容区域大小
    GUI:ScrollView_setInnerContainerSize(Bag._UI_ScrollView, pSize)
    -- 保存容器高度用于计算格子位置
    Bag._ScrollHeight = pSize.height
    -- 保存容器宽度
    Bag._PWidth = pSize.width
    -- 保存容器高度
    Bag._PHeight = pSize.height
    -- 计算单个格子宽度(容器宽度/列数)
    Bag._IWidth = Bag._PWidth / Bag._Col
    -- 计算单个格子高度(容器高度/行数)
    Bag._IHeight = Bag._PHeight / Bag._Row

    -- 如果需要代码生成格子,则调用初始化方法
    if Bag._codeInitGrid then
        Bag.InitGird()
    end
end

-- 更新背包界面中的金币显示
-- @param data 金币变化的数据
--      data.id: 货币类型ID, 1表示金币
function Bag.OnUpdateGold(data)
    -- 检查是否是PC端
    if SL:GetMetaValue("WINPLAYMODE") then
        -- 当没有传入数据或传入的是金币(id=1)的数据时才更新
        if not data or (data.id == 1) then
            -- 获取当前金币数量
            -- ITEM_COUNT的第一个参数1表示金币类型
            local goldNum = SL:GetMetaValue("ITEM_COUNT", 1)
            -- 如果金币文本控件存在则更新显示
            if Bag._ui.Text_goldNum then
                GUI:Text_setString(Bag._ui.Text_goldNum, goldNum)
            end
        end
    end
end

-- 是否可单击  这里可以拦截背包单击事件
function Bag.IsCanSingle(data)
    return true
end

-- 是否可以双击  这里可以拦截背包双击事件
function Bag.IsCanDouble(data)
    return true
end

-- 关闭事件
function Bag.OnClose(winID)
    -- 只有当关闭的是背包界面(BagLayerGUI)时才执行取消注册事件的操作
    if winID and winID == "BagLayerGUI" then
        Bag.UnRegisterEvent()
    end
end
--------------------------- 注册事件 -----------------------------
-----使用模块名作为事件监听器的标识符
function Bag.RegisterEvent()
    SL:RegisterLUAEvent(LUA_EVENT_MONEYCHANGE, "Bag", Bag.OnUpdateGold)
    SL:RegisterLUAEvent(LUA_EVENT_CLOSEWIN, "Bag", Bag.OnClose)
end

function Bag.UnRegisterEvent()
    SL:UnRegisterLUAEvent(LUA_EVENT_MONEYCHANGE, "Bag")
    SL:UnRegisterLUAEvent(LUA_EVENT_CLOSEWIN, "Bag")
end
    撰写回复...