测试环境
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#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
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会自动施放内存,我会根据场景名来动态初始化脚本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
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#之间的回调,这里每一秒会回调一次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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