唉,我好菜啊,本来想自己实现一套热更的,但是毫无思路,还是一步一步来吧,先抄抄看看别人的东西怎么样吧,写了个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