LuaFramework实现一个排行榜

唉,我好菜啊,本来想自己实现一套热更的,但是毫无思路,还是一步一步来吧,先抄抄看看别人的东西怎么样吧,写了个helloworld,支持资源和代码热更。
在这里插入图片描述
读取的json数据,在公司里面应该是读取服务器下发的协议数据,应该更麻烦。
json:

{
  "nodes": [
    {
      "Name": "kk",
      "Exp": 100,
      "Job": "AK1",
      "CombatPower": 300
    },
    {
      "Name": "lisi",
      "Exp": 1000,
      "Job": "AK2",
      "CombatPower": 15
    },
    {
      "Name": "lufei",
      "Exp": 200,
      "Job": "AK3",
      "CombatPower": 150
    },
    {
      "Name": "solong",
      "Exp": 300,
      "Job": "AK4",
      "CombatPower": 2
    }
  ]
}

define.lua:
在这里插入图片描述
我添加了RankView和RankCtrl
在这里插入图片描述
这里没有操作,其实可以把后面常用的luacomponent(都是静态方法)添加进来;
functions.lua
在这里插入图片描述
添加了全局函数,方便查找子节点
注意这里用cjson来操控json的加载和序列化。
json就放到指定文件夹下就可以了,看下面代码路径。
RankCtrl:

RankCtrl = {};
local this = RankCtrl;

local luaBehaviour;
local transform;
local gameObject;
local data;
local json = require "cjson"
local util = require "3rd/cjson/util"
local isExp = false;
require "Controller/RankItem"
--构建函数--
function RankCtrl.New()
    logWarn("RankCtrl.New--->>");
    return this;
end

function RankCtrl.Awake()
    logWarn("RankCtrl.Awake--->>");
    panelMgr:CreatePanel('Rank', this.OnCreate);
end

--启动事件--
function RankCtrl.OnCreate(obj)
    gameObject = obj;

    luaBehaviour = gameObject:GetComponent('LuaBehaviour');
    logWarn("Start lua--->>"..gameObject.name);
    resMgr:LoadPrefab('rank', { 'RankItem' }, this.InitPanel);

    -- 事件注册
    luaBehaviour:AddClick(RankPanel.btnClose, this.OnClick);
    luaBehaviour:AddClick(RankPanel.btnExp,function()
        RankPanel.txtRankValue:GetComponent("Text").text = "经验值";
        this.isExp = true;
        this.Refresh();
    end);
    luaBehaviour:AddClick(RankPanel.btnCombatPower,function ()
        RankPanel.txtRankValue:GetComponent("Text").text = "战力";
        this.isExp = false;
        this.Refresh();
    end);
end

--初始化面板--
function RankCtrl.InitPanel(objs)
    ---@type table
    this.data = this.LoadData();
    table.sort(this.data.nodes,function (d1,d2)
        return d1.CombatPower<d2.CombatPower;
    end);
    local parent =RankPanel.RankItemParent;
    for i=1,#this.data.nodes do
        local go = newObject(objs[0])
        go.name = 'RankItem';
        go.transform:SetParent(parent.transform,false);
        go.transform.localScale = Vector3.one;
        go.transform.localPosition = Vector3.zero;
        local item = LuaFramework.LuaComponent.Add(go,RankItem);
        item.obj = go;
        item.rank = i;
        item.name = this.data.nodes[i]["Name"];
        item.job = this.data.nodes[i]["Job"];
        item.rankValue = this.data.nodes[i].CombatPower;
    end
end

function RankCtrl.Refresh()
    if this.isExp then
        table.sort(this.data.nodes,function (d1,d2)
            return d1.Exp<d2.Exp;
        end);
    else
        table.sort(this.data.nodes,function (d1,d2)
            return d1.CombatPower<d2.CombatPower;
        end);
    end
    ---@type UnityEngine.GameObject
    local parent =RankPanel.RankItemParent;
    -- 先删再加
    local tmp= {};
    for i = 1, parent.transform.childCount do
        tmp[i] = parent.transform:GetChild(i-1)
    end
    for i=1,#tmp do
        destroy(tmp[i].gameObject)
    end
    tmp = nil;
    resMgr:LoadPrefab('rank', { 'RankItem' }, this.CallBack);
end

function RankCtrl.CallBack(objs)
    ---@type UnityEngine.GameObject
    local parent =RankPanel.RankItemParent;
    for i=1,#this.data.nodes do
        local go = newObject(objs[0])
        go.name = 'RankItem';
        go.transform:SetParent(parent.transform,false);
        go.transform.localScale = Vector3.one;
        go.transform.localPosition = Vector3.zero;
        local item = LuaFramework.LuaComponent.Add(go,RankItem);
        item.obj = go;
        item.rank = i;
        item.name = this.data.nodes[i]["Name"];
        item.job = this.data.nodes[i]["Job"];
        if this.isExp then
            item.rankValue = this.data.nodes[i].Exp;
        else
            item.rankValue = this.data.nodes[i].CombatPower;
        end
    end
end
--cjson--
function RankCtrl.LoadData()
    local path = Util.DataPath.."lua/3rd/cjson/rank.json";
    local text =util.file_load(path);
    local t = json.decode(text)
    return t;
end

function RankCtrl.OnClick()
    destroy(gameObject)
end
--关闭事件--
function RankCtrl.Close()
    LuaFramework.Util.Log("Rank 销毁!!!")
    panelMgr:ClosePanel(CtrlNames.Rank);
end

唉。
RankView:

local transform;
local gameObject;

RankPanel = {};
local this = RankPanel;

--启动事件--
function RankPanel.Awake(obj)
    gameObject = obj;
    transform = obj.transform;
    this.InitPanel();
    logWarn("Awake lua--->>"..gameObject.name);
end

--初始化面板--
function RankPanel.InitPanel()
    this.btnClose = FindChildNode(transform,"btnClose").gameObject;
    this.txtRankValue=  FindChildNode(transform,"txtRankValue").gameObject;
    this.RankItemParent=FindChildNode(transform,"LstItemParent").gameObject;
    this.btnCombatPower = FindChildNode(transform,"btnCombatPower").gameObject;
    this.btnExp = FindChildNode(transform,"btnExp").gameObject;
end

--单击事件--
function RankPanel.OnDestroy()
    logWarn("OnDestroy---->>>");
end

RankItem:
每个Item保存自己的数据

RankItem = {
    --里面可以放一些属性
    name = "RankItem",
    rank = -1, --索引
    job = "ice",
    rankValue = 100,
    obj = nil,
}
function RankItem:Start()
    -- 设置Id
    FindChildNode(self.obj.transform,"txtRank"):GetComponent("Text").text = self.rank;
    -- 设置name
    FindChildNode(self.obj.transform,"txtName"):GetComponent("Text").text = self.name;
    -- 设置score
    FindChildNode(self.obj.transform,"txtJob"):GetComponent("Text").text = self.job;
    FindChildNode(self.obj.transform,"txtRankValue"):GetComponent("Text").text = self.rankValue;
end

--创建对象
function RankItem:New(obj)
    local o = {}
    setmetatable(o, self)
    self.__index = self
    return o
end

还有events这个鬼东西没有用到。
用到网上他们常用的一个LuaComponent类。

/*
 * 让Lua脚本也能挂载到游戏物体上的组件
 * 
 * LuaComponent主要有Get和Add两个静态方法,其中Get相当于UnityEngine中的GetComponent方法,Add相当于AddComponent方法,
 * 只不过这里添加的是lua组件不是c#组件。每个LuaComponent拥有一个LuaTable(lua表)类型的变量table,它既引用上述的Component表。
 * Add方法使用AddComponent添加LuaComponent,调用参数中lua表的New方法,将其返回的表赋予table。
 * Get方法使用GetComponents获取游戏对象上的所有LuaComponent(一个游戏对象可能包含多个lua组件,由参数table决定需要获取哪一个),
 * 通过元表地址找到对应的LuaComponent,返回lua表
 * 
 * Add by TYQ
 */

using LuaInterface;
using UnityEngine;

namespace LuaFramework
{
    public class LuaComponent : View
    {
        //Lua表
        public LuaTable table;
        //添加LUA组件  
        public static LuaTable Add(GameObject go, LuaTable tableClass)
        {
            LuaFunction fun = tableClass.GetLuaFunction("New");
            if (fun == null)
                return null;
            //lua升级后不,Call方法不再返回对象,因此改为Invoke方法实现
            object rets = fun.Invoke<LuaTable, object>(tableClass);
            if (rets == null)
            {
                return null;
            }
            LuaComponent cmp = go.AddComponent<LuaComponent>();
            cmp.table = (LuaTable)rets;

            cmp.CallAwake();
            return cmp.table;
        }

        //添加LUA组件,允许携带额外一个参数(args)
        public static LuaTable Add(GameObject go, LuaTable tableClass, LuaTable args)
        {
            LuaFunction fun = tableClass.GetLuaFunction("New");
            if (fun == null)
                return null;

            object rets = fun.Invoke<LuaTable, object>(tableClass);
            if (rets == null)
            {
                return null;
            }
            LuaComponent cmp = go.AddComponent<LuaComponent>();
            cmp.table = (LuaTable)rets;

            cmp.CallAwake(args);
            return cmp.table;
        }

        //添加LUA组件  
        // isAllowOneComponent为true时,表示只添加一次组件,如果已存在,就不再添加
        public static LuaTable Add(GameObject go, LuaTable tableClass, bool isAllowOneComponent)
        {
            //如果已存在,则不再添加
            LuaComponent luaComponent = go.GetComponent<LuaComponent>();
            if (luaComponent != null)
            {
                return null;
            }

            LuaFunction fun = tableClass.GetLuaFunction("New");

            if (fun == null)
                return null;

            object rets = fun.Invoke<LuaTable, object>(tableClass);
            if (rets == null)
            {
                return null;
            }
            LuaComponent cmp = go.AddComponent<LuaComponent>();
            cmp.table = (LuaTable)rets;

            cmp.CallAwake();
            return cmp.table;
        }

        //获取lua组件

        public static LuaTable Get(GameObject go, LuaTable table)

        {
            LuaComponent cmp = go.GetComponent<LuaComponent>();
            string mat1 = table.ToString();
            string mat2 = cmp.table.GetMetaTable().ToString();
            if (mat1 == mat2)
            {
                return cmp.table;
            }

            return null;

        }

        //删除LUA组件的方法略,调用Destory()即可  

        //调用lua表的Awake方法
        void CallAwake()
        {

            LuaFunction fun = table.GetLuaFunction("Awake");

            if (fun != null)
                fun.Call(table, gameObject);
        }

        //调用lua表的Awake方法(携带一个参数)
        void CallAwake(LuaTable args)
        {

            LuaFunction fun = table.GetLuaFunction("Awake");
            if (fun != null)
                fun.Call(table, gameObject, args);
        }


        private void OnEnable()
        {
            // Debug.Log("================================================================================");
            //Debug.Log(table);

            if (table == null)
            {
                //Debug.LogWarning("Table is Null---------------------");
                return;
            }

            LuaFunction fun = table.GetLuaFunction("OnEnable");


            if (fun != null)
            {
                fun.Call(table, gameObject);
            }
        }

        void Start()
        {
            LuaFunction fun = table.GetLuaFunction("Start");
            if (fun != null)
                fun.Call(table, gameObject);
        }

        void Update()
        {
            //效率问题有待测试和优化
            //可在lua中调用UpdateBeat替代
            LuaFunction fun = table.GetLuaFunction("Update");

            if (fun != null)

                fun.Call(table, gameObject);
        }


        private void FixedUpdate()
        {
            LuaFunction fun = table.GetLuaFunction("FixedUpdate");

            if (fun != null)

                fun.Call(table, gameObject);
        }

        private void LateUpdate()
        {
            LuaFunction fun = table.GetLuaFunction("LateUpdate");

            if (fun != null)

                fun.Call(table, gameObject);
        }

        //更多函数略

        private void OnDisable()
        {
            if (table != null)
            {
                LuaFunction fun = table.GetLuaFunction("OnDisable");

                if (fun != null)
                {
                    fun.Call(table, gameObject);
                }
            }
        }

        private void OnDestroy()
        {
#if ASYNC_MODE
            string abName = name.ToLower().Replace("item", "");
            ResManager.UnloadAssetBundle(abName + AppConst.ExtName);
#endif
            Util.ClearMemory();
            Debug.Log("~" + name + " was destroy!");

            if (table != null)
            {
                LuaFunction fun = table.GetLuaFunction("OnDestroy");
                if (fun != null)
                {
                    fun.Call(table, gameObject);
                }
            }
        }

    }
}


其实这代码写的也不全面,他原作者的ondetory就写的很low,完全没有资源销毁之后item的ab包引用计数的问题,我这里补充了一下。
还有ctrlmanager里面ctrl全部初始化new,返回this,以及initallpanels,包括你rankitem实例化出来的名称问题这些细节要注意一下。
想看源码这里:helloworld

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
热更新框架设计系列课程总体介绍:        本系列课程由《热更新框架设计之Xlua基础》、《热更新框架设计之热更流程与热补丁技术》、《热更新框架设计之游戏客户端框架》三套课程组成。 三套课程是一个不可分割有机的整体,笔者带领大家由浅入深逐级深入 ,领悟热更精髓的基础之上,通过高端架构设计设计出“低耦合”、“低侵入”、“高复用”性的游戏(VR/AR)客户端热更框架。《热更新框架设计之客户端热更框架》课程介绍:        本作是热更框架系列课程中的客户端框架设计与实现部分。理解本作需要之前的所有知识点积累,在其基础之上给学员展现当今商业热更框架中,商业级热更框架的基本原理、设计全过程、实现框架产品等全过程。通过本作学习可以让资深开发人员晋升为游戏架构师、主程、技术总监等职位。        为了更好更快的服务广大学员,本课程分为上、中、下三部分,内容如下:        上部:               UI框架与AB框架整合,重构整合为 “热更新UI框架”。        中部:            “热更新UI框架”与热更流程技术重构整合。              纯Lua框架设计理念与实现。        下部:               复合型热更框架设计与实现。               框架产品加入HotFix功能模块,且功能演示与测试完善。《热更新框架设计之客户端热更框架(中部)》课程介绍:        热更客户端中部,主要就两大部分进行讲解:        第一部分:  “热更新UI框架”与热更流程技术重构整合         这部分“热更新流程实现脚本”与之前的UI框架、AB框架进行无缝的重构与整合进行开发。         这里涉及到很多地方的重构与处理:         1: Unity编辑器脚本中的创建校验文件、拷贝资源文件等的重构。         2: 由于单机版本框架所使用的Resources 目录被彻底取消,所以整个框架中,凡是涉及到Resources的编码部分,均要进行深入加工与修改,例如: ConfigManagerByJson.cs、UIManager.cs、SysDefine、Log、LauguageMgr等。        第二部分: “纯lua框架”整体设计与实现:        本部分是中部课程的核心,也是整个热更新框架的核心部分!        我们需要对商业项目中,业务功能面临经常频繁改动的部分,设计一套可复用、灵活、可扩展、高效率执行的lua框架系统。本框架系统,我们整体考虑采用类似MVC的“分层”结构进行整体架构设计,然后配之以Xlua技术,实现C#脚本与同名lua脚本之间的一对一映射关系。 这样可以使得每个3D/2D的预设对象,自动映射(预设)同名的一个lua控制脚本与一个“lua显示”脚本。        这里的“lua控制”脚本负责加载从服务器端传来的AB(AssetBundle)包资源,以及解析与显示AB包中的资源预设等。这些均为玩家所看不到的部分,所以都定义在控制层的lua脚本中。       对于需要显示的3D/2D 预设资源,我们使用“lua显示”脚本,控制显示的方式、内容与行为(包含事件注册)等。而本部分我们采用了xlua的映射技术,也使得“lua显示”脚本具备了Unity的常用生命周期函数,进一步大大简化了lua编写业务的难度,例如常见的:Awake()、Start()、Update()、OnDestroy()等。具体lua的架构设计如下图所示:           温馨提示:         1: 本套课程需要具备一定的框架理解与驾驭能力,为了更好的理解本作,强烈推荐广大学员首先学完必要的前导课程:“UI客户端框架设计”、“AssetBundle 框架设计”、“lua基础与中级篇”、以及本课程热更新框架的前两部(Xlua基础、热更流程与热补丁)。         2: 本课程使用Unity2017版本讲解,但是本课程主要讲解开发思想与具体实现技术,所以对Unity版本不敏感。 学员使用后续的Unity2018/19/2020..... 等版本基本没有影响。一、热更新系列(技术含量:中高级):A:《lua热更新技术中级篇》https://edu.csdn.net/course/detail/27087B:《热更新框架设计之Xlua基础视频课程》https://edu.csdn.net/course/detail/27110C:《热更新框架设计之热更流程与热补丁技术》https://edu.csdn.net/course/detail/27118D:《热更新框架设计之客户端热更框架(上)》https://edu.csdn.net/course/detail/27132E:《热更新框架设计之客户端热更框架(中)》https://edu.csdn.net/course/detail/27135F:《热更新框架设计之客户端热更框架(下)》https://edu.csdn.net/course/detail/27136二:框架设计系列(技术含量:中级): A:《游戏UI界面框架设计系列视频课程》https://edu.csdn.net/course/detail/27142B:《Unity客户端框架设计PureMVC篇视频课程(上)》https://edu.csdn.net/course/detail/27172C:《Unity客户端框架设计PureMVC篇视频课程(下)》https://edu.csdn.net/course/detail/27173D:《AssetBundle框架设计_框架篇视频课程》https://edu.csdn.net/course/detail/27169三、Unity脚本从入门到精通(技术含量:初级)A:《C# For Unity系列之入门篇》https://edu.csdn.net/course/detail/4560B:《C# For Unity系列之基础篇》https://edu.csdn.net/course/detail/4595C: 《C# For Unity系列之中级篇》https://edu.csdn.net/course/detail/24422D:《C# For Unity系列之进阶篇》https://edu.csdn.net/course/detail/24465四、虚拟现实(VR)与增强现实(AR):(技术含量:初级)A:《虚拟现实之汽车仿真模拟系统 》https://edu.csdn.net/course/detail/26618五、Unity基础课程系列(技术含量:初级) A:《台球游戏与FlappyBirds—Unity快速入门系列视频课程(第1部)》 https://edu.csdn.net/course/detail/24643B:《太空射击与移动端发布技术-Unity快速入门系列视频课程(第2部)》https://edu.csdn.net/course/detail/24645 C:《Unity ECS(二) 小试牛刀》https://edu.csdn.net/course/detail/27096六、Unity ARPG课程(技术含量:初中级):A:《MMOARPG地下守护神_单机版实战视频课程(上部)》https://edu.csdn.net/course/detail/24965B:《MMOARPG地下守护神_单机版实战视频课程(中部)》https://edu.csdn.net/course/detail/24968C:《MMOARPG地下守护神_单机版实战视频课程(下部)》https://edu.csdn.net/course/detail/24979
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JustEasyCode

谢谢您

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值