热更新xLua实践(xLua背包)

概述

学习完xLua后的实践小项目

准备工作

新建工程导入必要资源

VScode环境搭建

包括一些设置

开发工作

1.拼面板

主面板部分

背包面板部分

格子面板

2.Lua基本逻辑准备

InitClass.lua 脚本

Lua 复制代码
--常用别名都在这里面定位
--准备我们之前导入的脚本
--面向对象相关
require("Object")
--字符串拆分
require("SplitTools")
--Json解析
Json = require("JsonUtility")

--Unity相关的
GameObject = CS.UnityEngine.GameObject
Resources = CS.UnityEngine.Resources
Transform = CS.UnityEngine.Transform
RectTransform = CS.UnityEngine.RectTransform
--图集对象类
SpriteAtlas = CS.UnityEngine.U2D.SpriteAtlas

Vector3 = CS.UnityEngine.Vector3
Vector2 = CS.UnityEngine.Vector2

--Unity相关
UI = CS.UnityEngine.UI
Image = UI.Image
Text = UI.Text
Button = UI.Button
Toggle = UI.Toggle
--就是Scroll View
ScrollRect = UI.ScrollRect

--自己写的C#脚本相关
--直接得到AB包资源管理器的 单例对象
ABMgr = CS.ABMgr.GetInstance()

测试

3.数据准备

数据准备

创建图集

excel数据转Json

代码读取

配置表读取到Lua中

玩家数据准备

4.核心面板逻辑处理

MainPanel lua脚本

Lua 复制代码
--只要是一个新的对象(如面板)我们就要新建一张表
MainPanel = {}

--不是必须写 因为lua的特性 不存在声明变量的概念
--这样写的目的 是当别人看这个lua代码时 知道这个表(对象)有什么变量很重要
--关联的面板对象
MainPanel.panelObj = nil
--对应的面板控件
MainPanel.btnRole = nil   --这里只处理了btnRole按钮的逻辑
MainPanel.btnSkill = nil  --btnSkill的逻辑也是一样进行添加即可

--需要做 实例化面板对象
--为这个面板 处理对应的逻辑 比如按钮点击等等

--初始化该面板 实例化对象 控件事件监听
function MainPanel:Init()
    --面板对象没有实例化过 才去实例化处理
    if self.panelObj == nil then
        --1.实例化面板对象 ABMgr + 设置父对象
        self.panelObj = ABMgr:LoadRes("ui", "MainPanel", typeof(GameObject))
        self.panelObj.transform:SetParent(Canvas, false)
        --2.找到对应控件
        --找到子对象 再找到身上挂载的 脚本(如button脚本)
        self.btnRole = self.panelObj.transform:Find("btnRole"):GetComponent(typeof(Button))
        print(self.btnRole)
        --3.为控件加上事件监听 进行点击等等的逻辑处理
        --如果直接用.传入自己的函数 那么在函数内部 没有办法用self获取内容 所有只能用匿名函数包裹一层
        --因为括号里是要传一个函数名,如果用 :那就是调用函数了
        --self.btnRole.onClick:AddListener(self.BtnRoleClick)
        self.btnRole.onClick:AddListener(function()
            self:BtnRoleClick()
        end)
    end    
end

--显示自己的方法
function MainPanel:ShowMe()
    self:Init()
    self.panelObj:SetActive(true)
end

--隐藏自己的方法
function MainPanel:HideMe()
    self.panelObj:SetActive(false)
end

function MainPanel:BtnRoleClick()
    --print(123123)
    --print(self.panelObj)
    --等我们写了背包面板
    --在这显示我们的 背包面板
end

调用

补充

效果演示

BagPanel lua脚本

Lua 复制代码
--一个面板对应一个表
BagPanel = {}
--"成员变量"  方便我们查看
--面板对象没有实例化过
BagPanel.panelObj = nil
--各个控件
BagPanel.btnClose = nil
BagPanel.togEquip = nil
BagPanel.togItem = nil
BagPanel.togGem = nil
BagPanel.svBag = nil
BagPanel.Content = nil

--"成员方法"
--初始化方法
function BagPanel:Init()
    --判空
    if self.panelObj == nill then
        --实例化面板对象 和设置父对象
        self.panelObj = ABMgr:LoadRes("ui", "BagPanel", typeof(GameObject))
        self.panelObj.transform:SetParent(Canvas, false)
        --找控件
        --关闭按钮
        self.btnClose = self.panelObj.transform:Find("btnClose"):GetComponent(typeof(Button))
        --找3个toggle
        local group = self.panelObj.transform:Find("Group")
        self.togEquip = group:Find("togEquip"):GetComponent(typeof(Toggle))
        self.togItem = group:Find("togItem"):GetComponent(typeof(Toggle))
        self.togGem = group:Find("togGem"):GetComponent(typeof(Toggle))
        --Scroll View 控件
        self.svBag = self.panelObj.transform:Find("svBag"):GetComponent(typeof(ScrollRect))
        self.Content = self.svBag.transform:Find("Viewport"):Find("Content")  -- 找到Content
        --加事件
        --关闭按钮
        self.btnClose.onClick:AddListener(function()
            self:HideMe()
        end)
        --单选框事件
        --切页签
        self.togEquip.onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(1)
            end
        end)
        self.togItem.onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(2)
            end
        end)
        self.togGem.onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(3)
            end
        end)
    end
    
end

--显示和隐藏方法
function BagPanel:ShowMe()
    self:Init()
    self.panelObj:SetActive(true)
end

function BagPanel:HideMe()
    self.panelObj:SetActive(false)
end

--逻辑处理函数 用来切页签的
--type 1装备 2道具 3宝石
function BagPanel:ChangeType(type)
    --print("当前类型为"..type)  --测试

    --切页 根据玩家信息 来进行格子创建

end

添加

效果

ItemGrid (在BagPanel里用items来存储格子,并进行逻辑处理)

Lua 复制代码
--一个面板对应一个表
BagPanel = {}
--"成员变量"  方便我们查看
--面板对象没有实例化过
BagPanel.panelObj = nil
--各个控件
BagPanel.btnClose = nil
BagPanel.togEquip = nil
BagPanel.togItem = nil
BagPanel.togGem = nil
BagPanel.svBag = nil
BagPanel.Content = nil
--用来存储当前 显示的格子
BagPanel.items = {}
--当前页签ID  避免重复刷新
BagPanel.nowType = -1

--"成员方法"
--初始化方法
function BagPanel:Init()
    --判空
    if self.panelObj == nill then
        --实例化面板对象 和设置父对象
        self.panelObj = ABMgr:LoadRes("ui", "BagPanel", typeof(GameObject))
        self.panelObj.transform:SetParent(Canvas, false)
        --找控件
        --关闭按钮
        self.btnClose = self.panelObj.transform:Find("btnClose"):GetComponent(typeof(Button))
        --找3个toggle
        local group = self.panelObj.transform:Find("Group")
        self.togEquip = group:Find("togEquip"):GetComponent(typeof(Toggle))
        self.togItem = group:Find("togItem"):GetComponent(typeof(Toggle))
        self.togGem = group:Find("togGem"):GetComponent(typeof(Toggle))
        --Scroll View 控件
        self.svBag = self.panelObj.transform:Find("svBag"):GetComponent(typeof(ScrollRect))
        self.Content = self.svBag.transform:Find("Viewport"):Find("Content")  -- 找到Content
        --加事件
        --关闭按钮
        self.btnClose.onClick:AddListener(function()
            self:HideMe()
        end)
        --单选框事件
        --切页签
        self.togEquip.onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(1)
            end
        end)
        self.togItem.onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(2)
            end
        end)
        self.togGem.onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(3)
            end
        end)
    end
    
end

--显示和隐藏方法
function BagPanel:ShowMe()
    self:Init()
    self.panelObj:SetActive(true)
    --第一次打开面板时显示页签1的数据
    if self.nowType == -1 then
        self:ChangeType(1)
    end
end

function BagPanel:HideMe()
    self.panelObj:SetActive(false)
end

--逻辑处理函数 用来切页签的
--type 1装备 2道具 3宝石
function BagPanel:ChangeType(type)
    --print("当前类型为"..type)  --测试

    --判断如果已经是该页签 就别更新了
    if self.nowType == type then
        return
    end

    --切页 根据玩家信息 来进行格子创建

    --更新之前 把老的格子删除掉 BagPanel.items
    for i = 1, #self.items do
        --销毁格子对象
        GameObject.Destroy(self.items[i].obj)
    end
    self.items = {}
    
    --再根据当前选择的类型 来创建新的格子 BagPanel.items
    --要根据 传入的 type 来选择 显示的数据
    local nowItems = nil
    if type == 1 then
        nowItems = PlayerData.equips
    elseif type == 2 then
        nowItems = PlayerData.items
    else
        nowItems = PlayerData.gems
    end

    --创建格子
    for i = 1, #nowItems do
        --有格子资源 直接加载格子资源 实例化 改变图片 和 文本 以及位置即可
        local grid = {}
        --用一张新表 代表 格子对象 里面的属性 存储对应想要的信息
        grid.obj = ABMgr:LoadRes("ui", "ItemGrid")
        --设置父对象
        grid.obj.transform:SetParent(self.Content, false)
        --继续设置位置  math.floor 向下取整
        grid.obj.transform.localPosition = Vector3((i - 1) % 4 * 140, math.floor((i - 1) / 4) * 140)
        --找控件
        grid.imgIcon = grid.obj.transform:Find("imgIcon"):GetComponent(typeof(Image))
        grid.Text = grid.obj.transform:Find("Text"):GetComponent(typeof(Text))
        --设置它的图标
        --通过 道具ID 去读取 道具配置表 得到 图标信息
        local data = ItemData[nowItems[i].id]
        --想要的是data中的 图标信息
        --根据名字 先加载图集 再加载图集中的 图标信息 (用到字符串分割)
        local strs = string.split(data.icon, "_")
        --加载图集
        local spriteAtlas = ABMgr:LoadRes("ui", strs[1], typeof(SpriteAtlas))
        grid.imgIcon.sprite = spriteAtlas:GetSprite(strs[2])
        --设置它的数量
        grid.Text.text = nowItems[i].num

        --把它存起来
        table.insert(self.items, grid)
    end

end

效果

小总结:其实就是用一个table将格子存储起来

缺点就是不够面向对象

5.面向对象优化

格子面向对象

ItemGrid lua脚本

Lua 复制代码
--用到之前讲过的知识 Object(面向对象)
--生成一个table 集成Object 主要目的是要它里面实现的 继承方法subClass 和 new
Object:subClass("ItemGrid")
--"成员变量"
ItemGrid.obj = nil
ItemGrid.imgIcon = nil
ItemGrid.Text = nil
--成员函数
--实例化格子对象
function ItemGrid:Init(father, posX, posY)
    --实例化格子对象
    self.obj = ABMgr:LoadRes("ui", "ItemGrid")
    --设置父对象
    self.obj.transform:SetParent(father, false)
    --继续设置位置  math.floor 向下取整
    self.obj.transform.localPosition = Vector3(posX, posY, 0)
    --找控件
    self.imgIcon = self.obj.transform:Find("imgIcon"):GetComponent(typeof(Image))
    self.Text = self.obj.transform:Find("Text"):GetComponent(typeof(Text))
end

--初始化格子信息
--data 是外面传入的 道具信息 里面包含了 id和num
function ItemGrid:InitData(data)
    --通过 道具ID 去读取 道具配置表 得到 图标信息
    local itemdata = ItemData[data.id]
    --想要的是data中的 图标信息
    --根据名字 先加载图集 再加载图集中的 图标信息 (用到字符串分割)
    local strs = string.split(itemdata.icon, "_")
    --加载图集
    local spriteAtlas = ABMgr:LoadRes("ui", strs[1], typeof(SpriteAtlas))
    self.imgIcon.sprite = spriteAtlas:GetSprite(strs[2])
    --设置它的数量
    self.Text.text = data.num
end

--加自己的逻辑
function ItemGrid:Destroy()
    GameObject.Destroy(self.obj)
    self.obj = nil
end

BagPanel 脚本的变动

Lua 复制代码
--一个面板对应一个表
BagPanel = {}
--"成员变量"  方便我们查看
--面板对象没有实例化过
BagPanel.panelObj = nil
--各个控件
BagPanel.btnClose = nil
BagPanel.togEquip = nil
BagPanel.togItem = nil
BagPanel.togGem = nil
BagPanel.svBag = nil
BagPanel.Content = nil
--用来存储当前 显示的格子
BagPanel.items = {}
--当前页签ID  避免重复刷新
BagPanel.nowType = -1

--"成员方法"
--初始化方法
function BagPanel:Init()
    --判空
    if self.panelObj == nill then
        --实例化面板对象 和设置父对象
        self.panelObj = ABMgr:LoadRes("ui", "BagPanel", typeof(GameObject))
        self.panelObj.transform:SetParent(Canvas, false)
        --找控件
        --关闭按钮
        self.btnClose = self.panelObj.transform:Find("btnClose"):GetComponent(typeof(Button))
        --找3个toggle
        local group = self.panelObj.transform:Find("Group")
        self.togEquip = group:Find("togEquip"):GetComponent(typeof(Toggle))
        self.togItem = group:Find("togItem"):GetComponent(typeof(Toggle))
        self.togGem = group:Find("togGem"):GetComponent(typeof(Toggle))
        --Scroll View 控件
        self.svBag = self.panelObj.transform:Find("svBag"):GetComponent(typeof(ScrollRect))
        self.Content = self.svBag.transform:Find("Viewport"):Find("Content")  -- 找到Content
        --加事件
        --关闭按钮
        self.btnClose.onClick:AddListener(function()
            self:HideMe()
        end)
        --单选框事件
        --切页签
        self.togEquip.onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(1)
            end
        end)
        self.togItem.onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(2)
            end
        end)
        self.togGem.onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(3)
            end
        end)
    end
    
end

--显示和隐藏方法
function BagPanel:ShowMe()
    self:Init()
    self.panelObj:SetActive(true)
    --第一次打开面板时显示页签1的数据
    if self.nowType == -1 then
        self:ChangeType(1)
    end
end

function BagPanel:HideMe()
    self.panelObj:SetActive(false)
end

--逻辑处理函数 用来切页签的
--type 1装备 2道具 3宝石
function BagPanel:ChangeType(type)
    --print("当前类型为"..type)  --测试

    --判断如果已经是该页签 就别更新了
    if self.nowType == type then
        return
    end

    --切页 根据玩家信息 来进行格子创建

    --更新之前 把老的格子删除掉 BagPanel.items
    for i = 1, #self.items do
        --销毁格子对象
        --GameObject.Destroy(self.items[i].obj)
        self.items[i]:Destroy()
    end
    self.items = {}
    
    --再根据当前选择的类型 来创建新的格子 BagPanel.items
    --要根据 传入的 type 来选择 显示的数据
    local nowItems = nil
    if type == 1 then
        nowItems = PlayerData.equips
    elseif type == 2 then
        nowItems = PlayerData.items
    else
        nowItems = PlayerData.gems
    end

    --创建格子
    for i = 1, #nowItems do
        -- --有格子资源 直接加载格子资源 实例化 改变图片 和 文本 以及位置即可
        -- local grid = {}
        -- --用一张新表 代表 格子对象 里面的属性 存储对应想要的信息
        -- grid.obj = ABMgr:LoadRes("ui", "ItemGrid")
        -- --设置父对象
        -- grid.obj.transform:SetParent(self.Content, false)
        -- --继续设置位置  math.floor 向下取整
        -- grid.obj.transform.localPosition = Vector3((i - 1) % 4 * 140, math.floor((i - 1) / 4) * 140, 0)
        -- --找控件
        -- grid.imgIcon = grid.obj.transform:Find("imgIcon"):GetComponent(typeof(Image))
        -- grid.Text = grid.obj.transform:Find("Text"):GetComponent(typeof(Text))
        -- --设置它的图标
        -- --通过 道具ID 去读取 道具配置表 得到 图标信息
        -- local data = ItemData[nowItems[i].id]
        -- --想要的是data中的 图标信息
        -- --根据名字 先加载图集 再加载图集中的 图标信息 (用到字符串分割)
        -- local strs = string.split(data.icon, "_")
        -- --加载图集
        -- local spriteAtlas = ABMgr:LoadRes("ui", strs[1], typeof(SpriteAtlas))
        -- grid.imgIcon.sprite = spriteAtlas:GetSprite(strs[2])
        -- --设置它的数量
        -- grid.Text.text = nowItems[i].num

        --改
        --根据数据 创建一个格子对象
        local grid = ItemGrid:new()
        --要实例化对象 设置位置
        grid:Init(self.Content, (i - 1) % 4 * 140, math.floor((i - 1) / 4) * 140)
        --初始化它的信息 数量和图标
        grid:InitData(nowItems[i])
        --把它存起来
        table.insert(self.items, grid)
    end

end

面板面向对象

1.先写一个基类 BasePanel

Lua 复制代码
--利用面向对象
Object:subClass("BasePanel")

BasePanel.panelObj = nil
--相当于模拟一个字典 键为 控件名 值为控件本身
BasePanel.controls = {}
--事件监听标识
BasePanel.isInitEvent = false

function BasePanel:Init(name)
    if self.panelObj == nil then
        --公共的实例化对象的方法
        self.panelObj = ABMgr:LoadRes("ui", name, typeof(GameObject))
        self.panelObj.transform:SetParent(Canvas, false)
        --GetComponentsInChildren 可以得到所有挂载某一脚本的子对象  
        --找到所有UI控件 存起来 (因为所有UI控件的父类是UIBehaviour)
        local allControls = self.panelObj:GetComponentsInChildren(typeof(UIBehaviour))
        --如果存入一些对于我们来说没用UI控件
        --为了避免 找各种无用控件 我们定一个规则 拼面板时 控件命名一定按规范来
        --Button btn名字打头
        --Toggle tog名字打头
        --Image img名字打头
        --ScrollRect sv名字打头
        for i = 0, allControls.Length - 1 do
            local controlName = allControls[i].name
            --按照名字的规则 去找控件 必须满足命名规则 才存起来
            if string.find(controlName, "btn") ~= nil or
               string.find(controlName, "tog") ~= nil or
               string.find(controlName, "img") ~= nil or 
               string.find(controlName, "sv") ~= nil or 
               string.find(controlName, "txt") ~= nil then
                --为了让我们在得的时候 能够 确定得的控件类型 所以我们需要存储类型
                --利用反射 Type 得到 控件的类名
                local typeName = allControls[i]:GetType().Name
                --避免出现一个对象上 挂载多个UI控件 出现覆盖的问题
                --都会被存到一个容器中 相当于像列表数组的形式
                --最终存储形式为
                --{ btnRole = { Image = 控件, Button = 控件 }, togItem = {Toggle = 控件 }}
                if self.controls[controlName] ~= nil then
                    --通过自定义索引的形式 去加一个新的 "成员变量"
                    self.controls[controlName][typeName] = allControls[i]
               else
                    self.controls[controlName] = {[typeName] = allControls[i]}
               end
                
            end
            
        end
    end
end

--得到控件 根据 控件依附对象的名字 和 控件的类型字符串名字 Button Image Toggle
function BasePanel:GetControl(name, typeName)
    if self.controls[name] ~= nil then
        local sameNameControls = self.controls[name]
        if sameNameControls[typeName] ~= nil then
            return sameNameControls[typeName]
        end
    end
    return nil
end

function BasePanel:ShowMe(name)
    self:Init(name)
    self.panelObj:SetActive(true)
end

function BasePanel:HideMe()
    self.panelObj:SetActive(false)
end

MainPanel 改

Lua 复制代码
--只要是一个新的对象(如面板)我们就要新建一张表
BasePanel:subClass("MainPanel")

--需要做 实例化面板对象
--为这个面板 处理对应的逻辑 比如按钮点击等等

--初始化该面板 实例化对象 控件事件监听
function MainPanel:Init(name)
    --调用父类里面的逻辑
    self.base.Init(self, name)
    --为了只添加一次事件监听
    if self.isInitEvent == false then
        print(self:GetControl("btnRole", "Image"))
        self:GetControl("btnRole", "Button").onClick:AddListener(function()
            self:BtnRoleClick()
        end) 

        self.isInitEvent = true
    end  
end



function MainPanel:BtnRoleClick()
    --print(123123)
    --print(self.panelObj)
    --等我们写了背包面板
    --在这显示我们的 背包面板
    BagPanel:ShowMe("BagPanel")
end

BagPanel 改

Lua 复制代码
--一个面板对应一个表
BasePanel:subClass("BagPanel")

BagPanel.Content = nil
--用来存储当前 显示的格子
BagPanel.items = {}
--当前页签ID  避免重复刷新
BagPanel.nowType = -1

--"成员方法"
--初始化方法
function BagPanel:Init(name)
    self.base.Init(self, name)
    if self.isInitEvent == false then
        --找没有挂载UI控件的 对象 还是需要手动去找
        self.Content = self:GetControl("svBag", "ScrollRect").transform:Find("Viewport"):Find("Content")  -- 找到Content
        
        --加事件
        --关闭按钮
        self:GetControl("btnClose", "Button").onClick:AddListener(function()
            self:HideMe()
        end)
        --单选框事件
        --切页签
        self:GetControl("togEquip", "Toggle").onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(1)
            end
        end)
        self:GetControl("togItem", "Toggle").onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(2)
            end
        end)
        self:GetControl("togGem", "Toggle").onValueChanged:AddListener(function(value)
            if value == true then
                self:ChangeType(3)
            end
        end)

        self.isInitEvent = true
    end
    
    
end

--显示和隐藏方法
function BagPanel:ShowMe(name)
    self.base.ShowMe(self, name)
    --第一次打开面板时显示页签1的数据
    if self.nowType == -1 then
        self:ChangeType(1)
    end
end

--逻辑处理函数 用来切页签的
--type 1装备 2道具 3宝石
function BagPanel:ChangeType(type)
    --print("当前类型为"..type)  --测试

    --判断如果已经是该页签 就别更新了
    if self.nowType == type then
        return
    end

    --切页 根据玩家信息 来进行格子创建

    --更新之前 把老的格子删除掉 BagPanel.items
    for i = 1, #self.items do
        --销毁格子对象
        --GameObject.Destroy(self.items[i].obj)
        self.items[i]:Destroy()
    end
    self.items = {}
    
    --再根据当前选择的类型 来创建新的格子 BagPanel.items
    --要根据 传入的 type 来选择 显示的数据
    local nowItems = nil
    if type == 1 then
        nowItems = PlayerData.equips
    elseif type == 2 then
        nowItems = PlayerData.items
    else
        nowItems = PlayerData.gems
    end

    --创建格子
    for i = 1, #nowItems do
        -- --有格子资源 直接加载格子资源 实例化 改变图片 和 文本 以及位置即可
        -- local grid = {}
        -- --用一张新表 代表 格子对象 里面的属性 存储对应想要的信息
        -- grid.obj = ABMgr:LoadRes("ui", "ItemGrid")
        -- --设置父对象
        -- grid.obj.transform:SetParent(self.Content, false)
        -- --继续设置位置  math.floor 向下取整
        -- grid.obj.transform.localPosition = Vector3((i - 1) % 4 * 140, math.floor((i - 1) / 4) * 140, 0)
        -- --找控件
        -- grid.imgIcon = grid.obj.transform:Find("imgIcon"):GetComponent(typeof(Image))
        -- grid.Text = grid.obj.transform:Find("Text"):GetComponent(typeof(Text))
        -- --设置它的图标
        -- --通过 道具ID 去读取 道具配置表 得到 图标信息
        -- local data = ItemData[nowItems[i].id]
        -- --想要的是data中的 图标信息
        -- --根据名字 先加载图集 再加载图集中的 图标信息 (用到字符串分割)
        -- local strs = string.split(data.icon, "_")
        -- --加载图集
        -- local spriteAtlas = ABMgr:LoadRes("ui", strs[1], typeof(SpriteAtlas))
        -- grid.imgIcon.sprite = spriteAtlas:GetSprite(strs[2])
        -- --设置它的数量
        -- grid.Text.text = nowItems[i].num

        --改
        --根据数据 创建一个格子对象
        local grid = ItemGrid:new()
        --要实例化对象 设置位置
        grid:Init(self.Content, (i - 1) % 4 * 140, math.floor((i - 1) / 4) * 140)
        --初始化它的信息 数量和图标
        grid:InitData(nowItems[i])
        --把它存起来
        table.insert(self.items, grid)
    end

end

Main

最终效果和之前一样

6.Lua文件迁移工具

编辑器工具开发步骤

1.新建一个脚本

大部分放在Editor编辑器脚本中

2.继承 Editor编辑器 引用命名空间 using UnityEditor;

3.写个方法,加上特性 [MenuItem("XLua/自动生成txt后缀的Lua")]

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

public class LuaCopyEditor : Editor
{
    [MenuItem("XLua/自动生成txt后缀的Lua")]
    public static void CopyLuaToTxt()
    {
        //首先要找到 我们的所有Lua文件
        string path = Application.dataPath + "/Lua/";
        //判断路径是否存在
        if( !Directory.Exists(path))
            return;
        //得到每一个lua文件的路径 才能进行迁移拷贝
        string[] strs = Directory.GetFiles(path, "*.lua");

        //然后把Lua文件拷贝到一个新的文件夹中
        //首先定一个新路径
        string newPath = Application.dataPath + "/LuaTxt/";

        //为了避免一些被删除的lua文件 不再使用 我们应该先清空目标路径的文件

        //判断新路径文件夹 是否存在
        if(!Directory.Exists(newPath))
            Directory.CreateDirectory(newPath);
        else
        {
            //得到该路径中 所有后缀 .txt 的文件 把它们都删除了
            string[] oldFileStrs = Directory.GetFiles(newPath, "*.txt");
            for(int i = 0; i < oldFileStrs.Length; i++){
                File.Delete(oldFileStrs[i]);
            }
        }
        
        List<string> newFileNames = new List<string>();
        string fileName;
        for(int i = 0; i < strs.Length; i++)
        {
            //得到新的文件路径 用于拷贝
            fileName = newPath + strs[i].Substring(strs[i].LastIndexOf("/") + 1) + ".txt";
            newFileNames.Add(fileName);
            File.Copy(strs[i], fileName);
        }

        //调用刷新
        AssetDatabase.Refresh();

        //后面的逻辑只是用代码的形式自动的让生成的lua.txt脚本打包到AssetBundle中,后面直接打包即可,其实就是一些API的调用
        //刷新后再来改指定包 因为 如果不刷新 第一次改变 会没有用
        for(int i = 0; i < newFileNames.Count; i++){
            //用到 Unity API
            //改API传入的路径 必须是 相对Assets文件夹的 Assets/.../...
            AssetImporter importer = AssetImporter.GetAtPath(newFileNames[i].Substring(newFileNames[i].IndexOf("Assets")));
            if(importer != null)
                importer.assetBundleName = "lua";
        }
    }
}

生成完AB包后,资源就可以直接从AB中加载

完成

效果演示:

LuaBag

相关推荐
半夏知半秋44 分钟前
unity打包流程整理-Windows/Mac/Linux平台
windows·笔记·学习·macos·unity·游戏引擎
benben0441 小时前
通过PS和Unity制作2D动画之四:脚本控制动画
unity·游戏引擎
棪燊1 小时前
Unity集成Wwise并进行开发
unity·游戏引擎
林枫依依2 小时前
Unity Newtonsoft遍历json中的键值对
unity·json
虾球xz2 小时前
游戏引擎学习第41天
学习·算法·游戏引擎
ling1s3 小时前
C#核心(16)万物之父和装箱拆箱
开发语言·c#
B1nna3 小时前
外卖开发(七)——校验收货地址是否超出配送范围
开发语言·dubbo·lua
亦世凡华、5 小时前
从模型到视图:如何用 .NET Core MVC 构建完整 Web 应用
前端·经验分享·c#·mvc·.netcore
ue星空6 小时前
虚幻引擎生存建造系统
ue5·游戏引擎·虚幻·虚幻引擎
码猩7 小时前
C# 代理IP的winform
开发语言·c#