测试环境
1.红米手机一枚。
2.4张1024的Atals图集。
3.脚本中实例化400个UISprite。
4.随机设置UISprite的深度,这样可以让UI的drawCall 数量非常恐怖。
以上参数已经非常恐怖了。如下图所示在电脑上 230个DrawCall 23帧。 测试环境每一张UISprite没1秒随即移动到另外一个位置。所有控制代码均在脚本中完成,我们来分别测试一下 预编译DLL、CSLight、uLua的效率怎么样。
装红米手机上运行一下看看。预编译DLL 加载400个UISprite耗时 0.16s,运行时帧数 16.83FPS
使用CSLight来 加载400个UISprite耗时 0.78s,运行时帧数 13.81FPS
使用uLua来 加载400个UISprite耗时 0.53s,运行时帧数 11.87FPS
测试结果:
在脚本中调用Unity自身的方法,比如Resource.Load、 Instantiate 、uLua效率要高一些。
但是如果处理脚本与C#之间的来回调用,那么CSLight效率更高一些。
测试到这里,我觉得无论你用uLua还是CSLight都可以进行Unity的热更新,因为它俩效率差不多呵呵。就看你的个人喜好了!
测试代码比较丑,不过能说明问题,因为 C# 的代码和 CSLight的代码完全一样,所以这里我只贴C#和ulua的代码。
C#
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class UIMain {
private static int SpriteCount = 100;
private static List<UISprite>spriteList;
// Use this for initialization
static public void Start (string root)
{
spriteList = new List<UISprite>();
Transform rootUI = GameObject.Find(root).transform;
GameObject yusongPrefab = Resources.Load("yusong") as GameObject;
GameObject ruoruoPrefab = Resources.Load("ruoruo") as GameObject;
GameObject yusongPrefab1 = Resources.Load("yusong1") as GameObject;
GameObject ruoruoPrefab1 = Resources.Load("ruoruo1") as GameObject;
for(int i =0; i< SpriteCount; i++)
{
GameObject go = Object.Instantiate(yusongPrefab) as GameObject;
go.transform.parent = rootUI;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
UISprite sprite = go.GetComponent("UISprite") as UISprite;
sprite.depth = Random.Range(0,SpriteCount);
spriteList.Add(sprite);
go = Object.Instantiate(ruoruoPrefab) as GameObject;
go.transform.parent = rootUI;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
sprite = go.GetComponent("UISprite") as UISprite;
sprite.depth = Random.Range(0,SpriteCount);
spriteList.Add(sprite);
go = Object.Instantiate(yusongPrefab1) as GameObject;
go.transform.parent = rootUI;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
sprite = go.GetComponent("UISprite") as UISprite;
sprite.depth = Random.Range(0,SpriteCount);
spriteList.Add(sprite);
go = Object.Instantiate(ruoruoPrefab1) as GameObject;
go.transform.parent = rootUI;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
sprite = go.GetComponent("UISprite") as UISprite;
sprite.depth = Random.Range(0,SpriteCount);
spriteList.Add(sprite);
}
}
static public void Move()
{
for(int i =1; i<spriteList.Count; i++ )
{
UISprite sprite = spriteList[i];
Vector3 next = new Vector3( Random.Range(-400,400) , Random.Range(-260,260),0);
TweenPosition position = TweenPosition.Begin(sprite.gameObject,1,next);
}
Vector3 firstNext = new Vector3( Random.Range(-400,400) , Random.Range(-260,260),0);
TweenPosition firstPosition = TweenPosition.Begin(spriteList[0].gameObject,1,firstNext);
UIEventCommon.EventMove(firstPosition);
}
}
uLua
luanet.load_assembly('UnityEngine')
GameObject = luanet.import_type('UnityEngine.GameObject')
Transform = luanet.import_type('UnityEngine.Transform')
Resources = luanet.import_type('UnityEngine.Resources')
Vector3 = luanet.import_type('UnityEngine.Vector3')
Random = luanet.import_type('UnityEngine.Random')
UISprite = luanet.import_type('UISprite')
TweenPosition = luanet.import_type('TweenPosition')
UIEventCommon = luanet.import_type('UIEventCommon')
local SpriteCount =400
local myData = {}
function Start(name)
local go = GameObject.Find(name)
local yusongPrefab = Resources.Load("yusong")
local ruoruoPrefab = Resources.Load("ruoruo");
local yusongPrefab1 = Resources.Load("yusong1");
local ruoruoPrefab1 = Resources.Load("ruoruo1");
for a=0,SpriteCount,4 do
local go = GameObject.Instantiate(yusongPrefab);
go.transform.parent = rootUI;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
local sprite = go:GetComponent('UISprite');
sprite.depth = Random.Range(0,SpriteCount);
myData[a] = sprite;
local go = GameObject.Instantiate(ruoruoPrefab);
go.transform.parent = rootUI;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
local sprite = go:GetComponent('UISprite');
sprite.depth = Random.Range(0,SpriteCount);
myData[a+1] = sprite;
local go = GameObject.Instantiate(yusongPrefab1);
go.transform.parent = rootUI;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
local sprite = go:GetComponent('UISprite');
sprite.depth = Random.Range(0,SpriteCount);
myData[a+2] = sprite;
local go = GameObject.Instantiate(ruoruoPrefab1);
go.transform.parent = rootUI;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
local sprite = go:GetComponent('UISprite');
sprite.depth = Random.Range(0,SpriteCount);
myData[a+3] = sprite;
end
end
function Move()
for key, value in pairs(myData) do
local sprite = value
local next = Vector3(Random.Range(-400,400),Random.Range(-260,260),0);
TweenPosition.Begin(sprite.gameObject,1,next);
end
local firstNext = Vector3( Random.Range(-400,400) , Random.Range(-260,260),0);
local firstPosition = TweenPosition.Begin(myData[0].gameObject,1,firstNext);
UIEventCommon.EventMove(firstPosition);
end
UICommon.cs 测试入口脚本,为了公平我分别把这个脚本挂在了三个场景中。每次切场景Unity会自动施放内存,我会根据场景名来动态初始化脚本。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using LuaInterface;
public class UICommon : MonoBehaviour {
static public LuaState luaState ;
private float InitTime;
void Start()
{
float time = Time.realtimeSinceStartup;
if(Application.loadedLevel == 0)
{
//C# DLL方式加载
CUIMain.Start(name);
CUIMain.Move();
}else if(Application.loadedLevel == 1)
{
//CSLight方式加载
ScriptMgr.Instance.LoadProject(new string[]{"UIMain"});
ScriptMgr.Instance.Execute("UIMain.Start(""+name+"");");
ScriptMgr.Instance.Execute("UIMain.Move();");
}else
{
//uLua方式加载
TextAsset scriptFile = Resources.Load<TextAsset>("UIMain.lua");
luaState= new LuaState();
luaState.DoString(scriptFile.text);
LuaFunction f = luaState.GetFunction("Start");
f.Call(name);
f = luaState.GetFunction("Move");
f.Call();
}
InitTime = Time.realtimeSinceStartup - time;
}
void OnGUI()
{
GUI.color = Color.red;
if(GUILayout.Button("CS加载",GUILayout.Width(100),GUILayout.Height(100))){
Application.LoadLevel(0);
}
if(GUILayout.Button("CSLight加载",GUILayout.Width(100),GUILayout.Height(100))){
Application.LoadLevel(1);
}
if(GUILayout.Button("uLua加载",GUILayout.Width(100),GUILayout.Height(100))){
Application.LoadLevel(2);
}
GUILayout.Label("加载时间 :" + InitTime);
}
}
UIEventCommon.cs 用来测试脚本与C#之间的回调,这里每一秒会回调一次。
using UnityEngine;
using System.Collections;
using LuaInterface;
public class UIEventCommon {
static public void EventMove(TweenPosition tweenPostion)
{
EventDelegate.Add(tweenPostion.onFinished,delegate() {
if(Application.loadedLevel == 0)
CUIMain.Move();
else if(Application.loadedLevel == 1)
ScriptMgr.Instance.Execute("UIMain.Move();");
else
{
LuaFunction f = UICommon.luaState.GetFunction("Move");
f.Call();
}
});
}
}
最后是下载地址,欢迎大家在下面给我留言,也欢迎大家一起讨论Unity的热更新。谢谢。
http://pan.baidu.com/s/1o6NWyX8
工程下载完以后,大家可以直接打包装在Android手机上或者IOS上 。iOS我没上真机看,没找到iPhone4,如果你有机器的话帮我测试一下嘿嘿。
我在iPhone5s上看了一下 全程无压力,有iPhone4的朋友帮我看看哦。。
- 本文固定链接: https://www.xuanyusong.com/archives/3123
- 转载请注明: 雨松MOMO于 雨松MOMO程序研究院 发表





雨松哥您好,目前我们在使用ToLua请问有时间可以发布一份相关介绍吗?
雨松,能就ulua和slua在性能和易用性上面简单分析下各自优劣吗?最近项目准备引入热更新,基本上就在这2个之中选一个了
@雨松 请问下 你们用的slua框架现在游戏上线了吗 使用起来感觉怎么样
嗯,挺好的。
雨松,Unity5x 下 mac 上运行 uLua的方式要崩!
请问下,使用CSLight只能使用Static的函数,对于Unity提供的Invoke、InvokeRepeating之类的API应该怎么调用呢?
没有啊。
这语言官网在哪,或者官方论坛,我想看个release note来决定用哪个版本啊
用slua吧。 现在我们就在用这个。。
最近也在开始用slua,但是一直没有找到调试lua的方法,这个很不方便,不知道雨神你是怎么解决的= =
vs上有个插件 就可以调试。
slua不是被ulua作者举报剽窃代码被封了么?
大大 看你留言说是用SLUA 我也是用SLUA做 能不能做个建议的DEMO 或者写点文章让我也学习一下 谢谢
我们还在做调研。。
雨神, 现在你们项目。用的是C#Light还是uLua。我下载你这个在Unity5中运行,点击运行uLua的时候。Unity直接崩溃了。
slua
slua你们现在用下来有什么坑不?
怎麼最後沒有用C#Light了呢,可以分享下是甚麼考量嗎
hi,请问,你用slua的时候,写lua脚本,用什么编辑器,如何做到代码提示呢?没有代码提示好难受
vs 有lua 的插件
谢谢
事先保存文件名,后用www加载
MOMO请问一下,ScriptMgr.Instance.LoadProject();中的实现是否在安卓下是有问题的,我看其中用的是System.IO.Directory.GetFiles(Application.streamingAssetsPath。应该怎么处理安卓下的遍历路径内文件呀?
c#light目前还不完善,缺少luajit的安全编译,缺少国内众多游戏公司流行的Protobuffer-lua的动态协议解析,效率还低于tolua c#,所以目前还不具备实用性。选用的人慎用!!~~
CSEvil就是个垃圾,千万别用.写的垃圾脚本解释器,各种不支持,各种崩溃. 跟ulua根本不在一个级别上.
LuaFunction f = UICommon.luaState.GetFunction(“Move”); f.Call();uLua里的LuaFunction需要缓存的,不然每次都会new出一个function出来,你这样对测试结果是有影响的。修正下测试看看呢
谢谢你的留言。。
支持,测试数据结果最有说服力。
很有说服力。不错。接下去,这方面再研究什么更新呢,期待。。。。
你们俩口字这头像是谁做的啊???好羡慕
v5