找回密碼
 注冊帳號

掃一掃,訪問微社區

士郎 Unity3D熱更新實戰演練

28
回復
2717
查看
打印 上一主題 下一主題
[ 復制鏈接 ]
排名
1
昨日變化

8034

主題

8592

帖子

3萬

積分

Rank: 16

UID
1231
好友
186
蠻牛幣
12062
威望
30
注冊時間
2013-7-29
在線時間
4106 小時
最后登錄
2019-8-13

活力之星原創精華達人突出貢獻獎財富之證游戲蠻牛QQ群會員蠻牛妹VIP

馬上注冊,結交更多好友,享用更多功能,讓你輕松玩轉社區。

您需要 登錄 才可以下載或查看,沒有帳號?注冊帳號

x
熱更新
在介紹tolua前,我們首先來了解一下在游戲開發中,熱更新的概念。


熱更新是一種手游及App常用的更新方式,舉例來說,游戲上線后,玩家需要通過應用商店及其他渠道下載第一個版本。在運營的過程中,如游戲需要更換UI、修改邏輯、開放功能等,此時若不使用熱更新技術,就需要重新打包,那么玩家也就需要通過應用商店或其他渠道重新下載游戲。 熱更新可以在不重新下載客戶端的情況下,更新游戲的內容。







目前手游這部分做得普遍比較成熟,大大小小的內容升級基本都通過熱更新來完成
然而c#是一門編譯型語言,其運行之前需要進行編譯,而編譯的過程在移動平臺無法完成,所以當我們游戲的邏輯更改,代碼發生變化時,我們就需要重新在開發環境下編譯,然后重新打包,讓玩家下載最新版本。這個過程中,會下載很多不需要更新的資源,便會增加玩家的時間及流量消耗,造成不好的用戶體驗。因此在移動平臺中便就出現了熱更新技術。

  • 在unity中,主要的熱更新方式有如下三種:


1.使用Lua編寫游戲邏輯;
Lua是一個小巧的腳本語言,由標準C編寫而成,幾乎在所有操作系統和平臺上都可以編譯,運行。


使用lua熱更新就是在Unity環境里內嵌一個lua虛擬機,經常變動的和對執行效率沒要求的邏輯用Lua實現,游戲啟動時加載服務器上最新的lua字節碼來執行游戲。lua代碼都是運行時才編譯的,不運行的時候就如同一張圖片、一段音頻一樣,都是文件資源;所以更新邏輯只需要更新腳本,不需要再編譯,因而lua能輕松實現“熱更新”。


其實諸如python,javascript等腳本語言的話,都是可以實現這個功能的。只不是目前幾個開源的、成熟的熱更新方案都是基于lua的。  

2.C#Light
C#Light是一個簡單的嵌入式腳本,模仿c#的語法風格,完全由pure c#寫成


3.C#反射技術
可以將部分邏輯提取至一個單獨的代碼庫工程中,打包為DLL,將DLL打包為AssetBundle,Unity程序動態加載AssetBundle中的DLL文件,使用反射機制來調用代碼。用C#反射加載程序集的方式可以動態的從assetBundle資源包或其他資源包里加載腳本到工程中。但因為蘋果官方禁止iOS下的程序熱更新,JIT在iOS下無效,所以這種方式無法在ios使用


本文中主要來了解第一種方式,在unity的lua熱更新中,有ulua、slua、xlua、tolua等多種熱更新方案,這些方案提供了C#與Lua的互相調用機制。在本文我們以現今市面最常見的tolua為例,通過一個小項目給讀者介紹tolua在unity中的使用方法。


ToLua使用Tolua是Unity靜態綁定lua的一個解決方案,它通過C#中集成lua的插件,可以自動生成用于在lua中訪問Unity的綁定代碼,并把C#中的常量、變量、函數、屬性、類以及枚舉暴露給lua。其從cstolua衍變而來。




既然要了解Tolua,第一步肯定是先從Tolua作者的GitHub下載Tolua, 同時我們可以通過其GitHub來了解Tolua的主要特性,也可以加tolua技術交流群進行討論及學習。


下載完成后可以看到tolua文件夾中的目錄結構,如下圖:





我們只需要將「Assets」、「.x」、「Luajit64」、「Luajit」四個文件夾復制到我們的工程文件夾中。 加載完成后,Unity中會出現如下提示框,我們點擊確定



然后在unity中就可以看到Tolua的主要文件列表




ToLua案例在了解了基本的熱更新概念,及ToLua資源的加載后,我們通過一個小的案例,來初步的掌握ToLua在Unity中的使用方法。 在本文中,我們使用ToLua來制作一個可以用按鍵控制滾動的小球,如下圖所示:






學習或使用過Unity的讀者應該能夠非常輕松的使用C#寫出這個小游戲,那么我們現在來看使用ToLua是如何達到上圖效果的。
我們直接來看代碼,下面會對代碼進行逐行解釋:


[AppleScript] 純文本查看 復制代碼
Control.lua
Control = {}
local this = Control
require('Music')
local GameObject = UnityEngine.GameObject
local Input = UnityEngine.Input
local AudioSource = UnityEngine.AudioSource
local Rigidbody = UnityEngine.Rigidbody
local Color = UnityEngine.Color
local Sphere
local rigi
local force

function this.Start()
    Sphere = GameObject.Find('Sphere')
    Sphere : GetComponent('Renderer').material.color = Color(1, 0.1, 1)
    Sphere : AddComponent(typeof(AudioSource))
    coroutine.start(Music.PlaySound)
    Sphere : AddComponent(typeof(Rigidbody))
    rigi = Sphere : GetComponent('Rigidbody')
    force = 5
end

function this.Update()
    local h = Input.GetAxis('Horizontal')
    local v = Input.GetAxis('Vertical')
    rigi : AddForce(Vector3(h, 0, v) * force)
end 

Music.lua
--協程下載
--這里使用Tolua中提供的coroutine.www
Music = {}
local this = Music
function this.PlaySound()
    local audio = UnityEngine.GameObject.Find('Sphere') : GetComponent('AudioSource')
    local url = UnityEngine.WWW('https://etnly.oss-cn-shanghai.aliyuncs.com/%E5%B2%A1%E9%83%A8%E5%95%93%E4%B8%80%20-%20%E9%81%BA%E3%82%B5%E3%83%AC%E3%82%BF%E5%A0%B4%E6%89%80%EF%BC%8F%E6%96%9C%E5%85%89.ogg')
    coroutine.www(url)
    audio.clip = url : GetAudioClip()
    audio : Play()
end


  • 首先,我們在project面板中創建Script文件夾,下一層創建Lua文件夾,這個文件夾會存放我們所有的lua腳本。

  • 然后我們來詳細解釋上方的代碼:
  • Control = {} : 在lua中沒有類的概念,第一行中我們用lua表模擬一個類,類名為Control;
  • local this = Control : 既然在lua中不存在類的概念,那也不會存在this的用法,這里同樣的,我們模擬一個this,讓this = Control類;  
  • require('Music’) : lua通過require函數來加載模塊(希望讀者可以自行了解lua中模塊的含義)在本行中Muisc模塊是一個下載并播放音樂的協程模塊,具體代碼在Muisc.lua中;
  • local GameObject = UnityEngine.GameObject : 這里及其以下四行都是對Unity中的類、方法進行加載或者說調用,我們可以直接在代碼中使用UnityEngine.GameObject,或把UnityEngine.GameObject賦給一個變量(如第一行中,lua使用表來模擬類,那這里的GameObject也就是一個table類型);  
  • local Sphere : 這里及以下兩行,我們定義了幾個變量;
  • function this.Start()   end :這是lua中的函數,this的含義在之前有提到,我們也可以寫成Control.Start(), 我們在start函數中進行一些必要的初始化操作,可以把它看成Unity中的start(我們也可以給它起別的名字,這個函數的名字和之后我們在Unity中的調用沒有必然聯系),不要忘了加后面的end,這句話代表此方法的結尾;  
  • Sphere = GameObject.Find('Sphere') : 我們通過GameObject.Find來找到Unity中的小球(需要注意,lua腳本無法綁定在Unity中的物體上,所以也無法直接在Unity的面板中綁定Unity中的對象,我們只有通過查找的方式來找到Unity中的物體);
  • Sphere : GetComponent('Renderer').material.color = Color(1, 0.1, 1) :這一行中,我們使用GetComponent通過獲取Renderer組件,改變小球的顏色 ;  
  • Sphere : AddComponent(typeof(AudioSource)) : 使用AddComponent,給小球添加AudioSource組件;  
  • coroutine.start(Music.PlaySound) : 開啟協程, 我們可以直接看到 Music.lua這個腳本,在腳本中,我們使用ToLua封裝的coroutine.www()方法,來下載音樂,并通過之后的代碼來播放音樂;
  • Sphere : AddComponent(typeof(Rigidbody)) : 給小球添加剛體 ;
  • rigi = Sphere : GetComponent('Rigidbody') : 獲取小球的剛體,將其賦給rigi ;
  • force = 5 : 這里作為力的大小;
  • function this.Update()    end : 與之前start函數類似,我們可以將其看作是Unity中的Update(再次聲明,此處Lua函數名和Unity中的調用沒有必然聯系);
  • local h = Input.GetAxis('Horizontal') : 這一行及下一行,就是獲取按下相應按鍵,相應軸上的位移量 ;
  • rigi : AddForce(Vector3(h, 0, v) * force) : 通過剛體的AddForce方法,給小球施加力;


這就是我們整個例子的Tolua腳本使用說明,那么我們該如何在Unity中來調用這些腳本呢。 下面我們來了解在C#中調用ToLua的方法,代碼如下所示:

[AppleScript] 純文本查看 復制代碼
using UnityEngine;
using LuaInterface;
public class Control : MonoBehaviour {
    LuaState lua = null;
    LuaFunction luaFunc = null;
    void Start () {
        new LuaResLoader();
        lua = new LuaState();
        lua.Start();
        LuaBinder.Bind(lua);
        string luaPath = Application.dataPath + "/Scripts/Lua";//注意這里的文件位置
        lua.AddSearchPath(luaPath);
        lua.DoFile("Control.lua");
        CallFunc("Control.Start", gameObject);//調用lua中的this.Start函數
    }
    void Update () {
        CallFunc("Control.Update", gameObject);////調用lua中的this.Update函數
    }
    private void OnApplicationQuit()
    {
        lua.Dispose();
        lua = null;
    }
    void CallFunc(string func, GameObject obj){
        luaFunc = lua.GetFunction(func);
        luaFunc.Call(obj);
        luaFunc.Dispose();
        luaFunc = null;
    }
}


我們可以通過這段代碼來了解一些C#中調用Tolua的基本操作:
1.new LuaState() : 初始化Lua虛擬機
2.LuaState.Start() :開啟Lua虛擬機
3.LuaState.AddSearchPath(fullPath):添加目錄地址
4.LuaBinder.Bin(LuaState):向Lua虛擬機注冊Wrap類
5.new LuaResLoader() :自定義加載器加載lua文件
6.LuaState.DoFile()、LuaState.Require():加載Lua文件/模塊
7.LuaState.GetFunction:獲取Lua方法
8.LuaState.GetFunction.Call():調用Lua函數
9.Luafunction.Dispose(),LuaState.Dispose():釋放內存  

到此為止,我們已經了解了如何在Unity中使用ToLua來進行邏輯編寫,讀者可以根據以上的例子來擴展,實現更多的功能,或在自己的項目中加入lua代碼來深入學習lua。

在下一篇文章中,我們會通過一個相對復雜一些的例子,給讀者帶來更多Tolua在Unity中的使用方法、技巧及原理。


知乎@朔宇


回復

使用道具 舉報

2初來乍到
100/150
排名
20607
昨日變化

0

主題

44

帖子

100

積分

Rank: 2Rank: 2

UID
210479
好友
0
蠻牛幣
70
威望
0
注冊時間
2017-3-7
在線時間
30 小時
最后登錄
2019-8-1
沙發
2019-5-5 16:27:43 只看該作者
樓主牛叉~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
回復

使用道具 舉報

7日久生情
2527/5000
排名
971
昨日變化

2

主題

889

帖子

2527

積分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
206337
好友
4
蠻牛幣
15698
威望
0
注冊時間
2017-6-5
在線時間
548 小時
最后登錄
2019-8-13
板凳
2019-5-5 16:39:17 只看該作者
謝謝分享
回復

使用道具 舉報

5熟悉之中
799/1000
排名
3723
昨日變化

11

主題

102

帖子

799

積分

Rank: 5Rank: 5

UID
224968
好友
0
蠻牛幣
759
威望
0
注冊時間
2017-6-3
在線時間
272 小時
最后登錄
2019-8-5
地板
2019-5-5 17:47:20 只看該作者
感謝樓主大大
回復

使用道具 舉報

排名
64932
昨日變化
1

0

主題

2

帖子

10

積分

Rank: 1

UID
312187
好友
0
蠻牛幣
40
威望
0
注冊時間
2019-1-19
在線時間
6 小時
最后登錄
2019-7-7
5#
2019-5-5 21:10:04 只看該作者
原來是這樣啊
回復

使用道具 舉報

7日久生情
2075/5000
排名
4092
昨日變化

0

主題

1356

帖子

2075

積分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
254705
好友
1
蠻牛幣
1889
威望
0
注冊時間
2017-11-16
在線時間
357 小時
最后登錄
2019-8-13
6#
2019-5-6 08:03:53 只看該作者
666666666666666666666666
回復 支持 反對

使用道具 舉報

6蠻牛粉絲
1110/1500
排名
2236
昨日變化

1

主題

173

帖子

1110

積分

Rank: 6Rank: 6Rank: 6

UID
232255
好友
1
蠻牛幣
1636
威望
0
注冊時間
2017-7-15
在線時間
308 小時
最后登錄
2019-8-13
7#
2019-5-6 08:21:34 只看該作者
感謝樓主大大
回復

使用道具 舉報

6蠻牛粉絲
1399/1500
排名
1995
昨日變化

4

主題

238

帖子

1399

積分

Rank: 6Rank: 6Rank: 6

UID
130993
好友
0
蠻牛幣
1138
威望
0
注冊時間
2015-12-6
在線時間
475 小時
最后登錄
2019-8-12
QQ
8#
2019-5-6 09:04:52 只看該作者
頂強頂強頂強頂強頂強頂強
回復 支持 反對

使用道具 舉報

3偶爾光臨
157/300
排名
48135
昨日變化

0

主題

9

帖子

157

積分

Rank: 3Rank: 3Rank: 3

UID
305199
好友
0
蠻牛幣
218
威望
0
注冊時間
2018-11-19
在線時間
144 小時
最后登錄
2019-8-13
9#
2019-5-6 09:51:33 只看該作者
66666666666666
回復

使用道具 舉報

3偶爾光臨
244/300
排名
14230
昨日變化

0

主題

52

帖子

244

積分

Rank: 3Rank: 3Rank: 3

UID
276112
好友
0
蠻牛幣
566
威望
0
注冊時間
2018-4-8
在線時間
134 小時
最后登錄
2019-8-13
10#
2019-5-6 09:52:34 只看該作者
樓主牛叉 666  收藏 待更
回復 支持 反對

使用道具 舉報

6蠻牛粉絲
1198/1500
排名
2299
昨日變化

1

主題

145

帖子

1198

積分

Rank: 6Rank: 6Rank: 6

UID
234403
好友
0
蠻牛幣
2850
威望
0
注冊時間
2017-7-26
在線時間
436 小時
最后登錄
2019-8-6
11#
2019-5-6 10:24:45 只看該作者
半年沒寫lua,快忘了
回復 支持 反對

使用道具 舉報

5熟悉之中
799/1000
排名
3723
昨日變化

11

主題

102

帖子

799

積分

Rank: 5Rank: 5

UID
224968
好友
0
蠻牛幣
759
威望
0
注冊時間
2017-6-3
在線時間
272 小時
最后登錄
2019-8-5
12#
2019-5-6 19:37:19 只看該作者
很詳細,很易懂,感謝
回復 支持 反對

使用道具 舉報

7日久生情
2917/5000
排名
2230
昨日變化

1

主題

1892

帖子

2917

積分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
119154
好友
0
蠻牛幣
3251
威望
0
注冊時間
2015-8-21
在線時間
394 小時
最后登錄
2019-8-13
13#
2019-5-7 08:44:22 只看該作者
謝謝樓主大大。
回復

使用道具 舉報

0

主題

38

帖子

95

積分

Rank: 2Rank: 2

UID
319338
好友
0
蠻牛幣
81
威望
0
注冊時間
2019-4-11
在線時間
57 小時
最后登錄
2019-8-13
14#
2019-5-8 08:52:54 只看該作者
頂頂頂-------------------------
回復 支持 反對

使用道具 舉報

7日久生情
2776/5000
排名
394
昨日變化

0

主題

98

帖子

2776

積分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
80613
好友
1
蠻牛幣
4888
威望
0
注冊時間
2015-3-17
在線時間
1006 小時
最后登錄
2019-8-13
15#
2019-5-8 11:38:21 只看該作者
xuexixuexi~~~~~~~~~~~~
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 注冊帳號

本版積分規則

女校游泳队彩金