unity遊戲熱更新

什麼是熱更新?html

舉例來講編程

     遊戲上線後,玩家下載第一個版本(70M左右或者更大),在運營的過程當中,若是須要更換UI顯示,或者修改遊戲的邏輯,這個時候,若是不使用熱更新,就須要從新打包,而後讓玩家從新下載(浪費流量和時間,體驗很差)。c#

     熱更新能夠在不從新下載客戶端的狀況下,更新遊戲的內容。windows

     熱更新通常應用在手機網遊上。數組

爲何C#腳本不能夠直接更新?數據結構

     C#是一門編程語言,它運行以前須要進行編譯,而這個編譯的過程在移動平臺沒法完成,因此當咱們遊戲的邏輯更改,C#代碼發生改變的時候,咱們就須要從新在開發環境下編譯,而後從新打包,而後讓玩家去下載更新最新的版本。app

     這個體驗差:包下載須要的時間長,並且不少資源沒有更新,也須要從新下載,浪費流量。框架

熱更新有哪些實現方式?dom

1,使用Lua腳本編寫遊戲的UI或者其餘的邏輯編程語言

      Lua是一個精悍小巧的腳本語言,能夠跨平臺運行解析,並且不須要編譯的過程

2,使用C#Light

3,使用C#反射技術

什麼是AssetBundle?

     Unity提供了一個資源更新技術,就是經過AssetBundle,咱們能夠經過AssetBundle更新遊戲UI,也能夠把腳本或者其餘代碼當成資源打包成AssetBundle而後更新到客戶端。

      在全部的熱更新技術中都須要AssetBundle

如何利用Lua進行熱更新?

     在移動端能夠編寫Lua的解析器,經過這個解析器,能夠運行最新的Lua腳本,而後咱們把控制遊戲邏輯的代碼都寫成Lua腳本。

Lua的解析技術有哪些?

1,uLua

  駿擎【CP】   ulua.org

2,Nlua

  unity支持Riley G  nlua.org

3,UniLua

  阿楠同窗

4,sLua

如何學習熱更新技術?

1,學習Lua編程

2,學習經過LuaInterface和luanet進行Lua和C#的交互通訊

3,學習使用AssetBundle進行資源更新

4,學習uLua SimpleFramework

  利用us建立本身的熱更新遊戲

 

第 2 章 : Lua

課時2:201-Lua介紹和luaforwindows的安裝 07:36

Lua 是一個小巧的腳本語言。是巴西里約熱內盧天主教大學(Pontifical Catholic University of Rio de Janeiro)裏的一個研究小組,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所組成並於1993年開發。 其設計目的是爲了嵌入應用程序中,從而爲應用程序提供靈活的擴展和定製功能。Lua由標準C編寫而成,幾乎在全部操做系統和平臺上均可以編譯,運行。Lua並無提供強大的庫,這是由它的定位決定的。因此Lua不適合做爲開發獨立應用程序的語言。Lua 有一個同時進行的JIT項目,提供在特定平臺上的即時編譯功能。

1,Lua的官網 lua.org

2,Luaforwindows

  http://luaforge.net/projects/luaforwindows/

  http://luaforwindows.luaforge.net/ (可安裝的exe文件,一整套的Lua開發環境,有Lua的解釋器,參考手冊,範例和庫,文檔,和編輯器)

3,安裝Luaforwindows,關於Luaforwindows的目錄介紹

1,找到luaforwindows的安裝目錄,找到SciTE

2,打開SciTE,寫入第一行Lua代碼

  print("Hello World")

3,保存代碼,保存爲HelloWorld.lua

4,按下F5運行

課時3:202-編寫第一個Lua程序HelloWorld 03:58

程序分析:

1,print()是Lua內置的方法

2,在Lua中字符串用 "" 或者 '' 均可以表示

3,Lua中每一條語句後面是沒有;號的

如何定義變量?

num = 100

  這裏定義了一個全局變量叫作num,賦值爲100

  在Lua中定義變量是沒有類型的,根據存儲什麼數據,來決定是什麼類型

  變量的命名不能以數字開頭

  儘可能避免下劃線加大寫字母開頭,這種格式Lua自身保留

  推薦使用C#中的命名規範和駝峯命名

如何添加註釋?

1,單行註釋 --註釋內容

2,多行註釋 --[[ 這裏是註釋內容 ]]--

課時4:203-變量的定義 10:03

Lua變量類型以下:

1,nil表示空數據,等同於null

2,boolean 布爾類型,存儲true和false

3,string 字符串類型,字符串能夠用雙引號也可使用單引號表示

4,number小數類型(Lua中沒有整數類型)

5,table表類型

  myTable = {34,,34,2,342,4}

  myTable[3]    --從1開始

咱們可使用type()來取得一個變量的類型

注:漢字爲兩個字節,因此刪除要按兩下

注意事項:

默認定義的變量都是全局的,定義局部變量須要在前面加一個local;

在代碼塊中聲明的局部變量,當代碼塊運行結束的時候,這個變量就會被釋放;

temp = 34

local var = 345

課時5:204-運算符和流程控制語句if語句 07:31

Lua運算符有哪些?

1,算數運算符 + - * /   % (Lua中沒++ -- 這樣是運算符)

2,關係運算符 <= < > >= ==

3,邏輯運算符 and or not 分別表示 與 或 非(相似於C#中的 && ||   !)

if語句的三種用法

1,  if [condition] then

  end

2,  if [condition] then

  else

  end

3,  if [condition] then

  elseif [condition]

  else

  end

num1=10

num2=20

num3=30

res1=num1 and num2

res2=true or num2

res3=not num3

print(res1,res2,res3)

local hp=40

if hp<=0 then

    print("die")

elseif hp>=50 then

    print("good")

else

    print("bad")

end

課時6:205- 循環結構之while循環和repeat循環 07:27    Lua中沒有+=這個運算符

循環結構while循環

1,while語法結構

  while [condition] do

  end

2,輸出1到100

index=1

while index<=100 do

    print(index)

    index=index+1

end

3,實現1加到100

sum=0

index=1

while index<=100 do

    sum=sum+index

    index=index+1

end

print(sum)

4,遍歷1-100中全部的奇數的和

sum=0

index=1

while index<=100 do

    if index%2==1 then

        sum=sum+index

    end

    index=index+1

end

print(sum)

循環結構repeat循環(至關於do - while)

1,語法結構

  repeat

  [code to execute]

  until [condition]

2,輸出1到100

index=1

repeat

    print(index)

    index=index+1

until index>100

3,實現1加到100

sum=0

index=1

repeat

    sum=sum+index

    index=index+1

until index>100

print(sum)

4,遍歷1-100中全部的奇數的和

sum=0

index=1

repeat

    if index%2==1 then

        sum=sum+index

    end

    index=index+1

until index>100

print(sum)

課時7:206- 循環結構之for循環 02:51

for循環結構

1,語法結構

  for index = [start],[end] do

  [code to execute]

  end

2,輸出1到100

for index=1,100 do

    print(index)

end

3,實現1加到100

sum=0

for index=1,100 do

    sum=sum+index

end

print(sum)

4,遍歷1-100中全部的奇數的和

sum=0

for index=1,100 do

    if index%2==1 then

        sum=sum+index

    end

end

print(sum)

break能夠終止循環 沒有continue語法

課時8:207- 函數的定義和math數學函數 05:16

函數(方法)

1,如何定義函數

  function [function name](param1,param2)

  [function code]

  end

2,定義一個函數用來求得兩個數字的和

  function Plus(num1,num2)

  return num1+num2

  end

標準庫(標準函數)

Lua內置提供了一些經常使用的函數幫助咱們開發

  1,數學處理的math相關函數

  2,字符串處理的string相關函數

  3,表處理的table相關函數

  4,文件操做的io相關函數

數學運算函數

math.abs

math.cos

math.max

math.maxinteger

math.min

math.random

math.sin

math.sqrt

math.tan

print(math.abs(-90))

print(math.max(12,34,56,76,43,2))

print(math.random())

課時9:208- 字符串處理 03:14

字符串處理相關函數

string.byte

string.char

string.find

sting.format

string.lower

string.sub

string.upper

.. 字符串相加

tostring() 把一個數字轉化成字符串

tonumber() 把一個字符串轉化成數字

name="kerHHHHHven"

print(string.lower(name))

print(string.sub(name,1,4))

print("http://"..name)

課時10:209- Lua中的table表 10:02

在Lua中的table相似C#中的字典,其實就是一個 key-value鍵值對的數據結構。

1,table的建立

  myTable = {}

  表名後面使用{}賦值,表示一個空的表

2,table的賦值

  myTable[3]=34 當鍵是一個數字的時候的賦值方式

  myTable["name"]="taikr" 當鍵是一個字符串的賦值方式

  myTable.name = "siki"當鍵是一個字符串的賦值方式

3,table的訪問

  myTable[3] 當鍵是數字的時候,只有這一種訪問方式

  myTable.name 當鍵是字符串的時候有兩種訪問方式

  myTable["name"]

4,table的第二種建立方式

  myTable = {name="taikr",age=18,isMan = false}

  (表建立以後依然能夠添加數據)

  數據訪問

  myTable.name

  myTable["name"]

5,table的第三種方式(相似數組的使用)

  myTable = {34,34,34,3,4,"sdfdsf"}

  當沒有鍵的時候,編譯器會默認給每個值,添加一個數字的鍵,該鍵從1開始

課時11:210- 表相關函數,使用表實現面向對象編程 08:07

表的遍歷

表的遍歷分爲兩種

  1,若是是隻有數字鍵,而且是連續的可使用下面的遍歷

  for index = 1,table.getn(myTable) do

  [code to execute]

  end

  2,全部的表均可以經過下面的方式遍歷

  for index,value in pairs(myNames) do

  print(index,value)

  end

表相關的函數

1.table.concat

  把表中全部數據連成一個字符串

2,table.insert

  向指定位置插入一個數據

3,table.move

  移動數據

4,table.pack

  包裝成一個表

5,table.remove

  移除指定位置的數據

6,table.sort

  排序

7,table.unpack

  返回一個數組,指定範圍的數組

經過表來實現面向對象

myTable={} 申明對象

local this = myTable聲明this關鍵字表明當前對象

--定義並聲明對象中的屬性

myTable.name="siki"

myTable.age = 110

--定義並聲明對象中的方法

myTable.function = function ()

  [code to execute]

end

function myTable.function ()

  [code to execute]

end

 

第 3 章 :

課時12:301- LuaInterface學習,在CLR(C#)中執行lua代碼 05:07(只須要引入LuaInterface.dll)

什麼是LuaInterface

LuaInterface包括兩個核心庫一個是LuaInterface.dll,一個是Luanet.dll,咱們能夠經過LuaInterface完成Lua和C#(CLR)之間的互相調用

在CLR(C#)中執行lua代碼

Lua lua = new Lua();  //建立Lua解析器

  lua["num"]=2;  //定義一個num

  lua["str"]="a string";  //定義一個字符串

  lua.newTable("tab");  //建立一個表 tab={}

取得Lua環境

double num = (double)lua["num"];

  string str = (string)lua["str"];

課時13:302-在C#中執行Lua腳本文件,或者腳本字符串 13:02

lua.DoFile("script.lua");//執行script.lua腳本

  lua.DoString("num=2");

  lua.DoString("str='a string'");

  object[] retVals = lua.DoString("return num,str");

在熱更新中,只須要寫好解析lua腳本的代碼,而後c#代碼不須要變更,只須要修改lua腳本就好,經過lua腳本控制遊戲邏輯。lua腳本和使用的C#腳本須要在同一個目錄下,既是在Debug目錄下

using System;

namespace LuaInterface

{

    class Program

    {

        static void Main(string[] args)

        {

            Lua lua = new Lua();//建立Lua的解釋器

            lua["num"] = 34;

            Console.WriteLine(lua["num"]);

            lua.DoString("num=2");

            lua.DoString("str='a string'");

            object[] retVals = lua.DoString("return num,str");

            foreach (object obj in retVals)

            {

                Console.WriteLine(obj);

            }

            lua.DoFile("hello.lua");

            Console.ReadKey();

        }

    }

}

課時14:303-把一個C#方法註冊進Lua的一個全局方法 07:26

Lua和C#中對應的類型

     nil   null

  string   System.String

  number   System.Double

  boolean   System.Boolean

  table  LuaInterface.LuaTable

  function   LuaInterface.LuaFunction

把一個C#方法註冊進Lua的一個全局方法

//把一個類中的普通方法註冊進去

lua.RegisterFunction("NormalMethod",obj,obj.GetType().GetMethod("NormalMethod"))

lua.DoString(" NormalMethod()");

using System;

namespace LuaInterface

{

    class Program

    {

        static void Main(string[] args)

        {

            Lua lua = new Lua();//建立Lua的解釋器

            #region把一個類中的普通方法註冊進去

            Program p = new Program();

            lua.RegisterFunction("CLRMethod", p, p.GetType().GetMethod("CLRMethod"));

            lua.DoString("CLRMethod()");

            #endregion

            Console.ReadKey();

        }

        public void CLRMethod()

        {

            Console.WriteLine("普通c#方法");

        }

    }

}

// 把一個類的靜態方法註冊進去

lua.RegisterFunction("StaticMethod",null,typeof(ClassName).GetMethod("StaticMethod"))

lua.DoString(" StaticMethod()")

using System;

namespace LuaInterface

{

    class Program

    {

        static void Main(string[] args)

        {

            Lua lua = new Lua();//建立Lua的解釋器

            #region 把一個類的靜態方法註冊進去

            lua.RegisterFunction("MyStaticMethod", null, typeof(Program).GetMethod("MyStaticMethod"));

            lua.DoString("MyStaticMethod()");

            #endregion

            Console.ReadKey();

        }

        public static void MyStaticMethod()

        {

            Console.WriteLine("靜態方法");

        }

    }

}

課時15:304-在Lua中使用c#中的類 08:43

require "luanet"

--加載CLR的類型、實例化CLR對象

luanet.load_assembly("System.Windows.Forms")

luanet.load_assembly("System.Drawing")

Form = luanet.import_type("System.Windows.Forms.Form")

StartPosition = luanet.import_type("System.Windows.Forms.FormStartPosition")

print(Form)

print(StartPosition)

在Lua中使用C#中的類建立對象的時候,會自動匹配最合適的構造方法

require "luanet"

luanet.load_assembly("System")

Int32=luanet.import_type("System.Int32")

num=Int32.Parse("3435")

print(Int32)

print(num)

課時16:305-在Lua中訪問C#中的屬性和方法 03:25

Lua代碼中,訪問C#對象的屬性的方式和訪問table的鍵索引同樣,好比obj.name 或者 obj["name"]

Lua代碼中,訪問C#對象的普通函數的方式和調用table的函數同樣,好比obj:method1()

require "luanet"

luanet.load_assembly("System")

luanet.load_assembly("testLuaInterface")

Program =luanet.import_type("testLuaInterface.Program")

program1= Program()

print(program1.name)

program1:Method()

課時17:306-在Lua中訪問C#中的屬性和方法-特殊狀況-帶有out和ref關鍵字 07:01

當函數中有out或ref參數時,out參數和ref參數和函數的返回值一塊兒返回,而且調用的時候,out參數不須要傳入

C#函數定義

class Obj{

int OutMethod1(int parameter1,out parameter2,out parameter3){

  parameter2=34;parameter3=213;

  return parameter1;

}

int OutMethod2(int parameter1,ref parameter2){

  parameter2=parameter2+2;

  return parameter1+parameter2;

Lua中的調用和返回值

obj:OutMethod1(34)

--out參數不須要參數,這個返回一個table,裏面的值爲parameter1,parameter2,parameter3

(34,34,213)

obj:OutMethod2(10,10)

--ref參數須要傳入,返回一個table有兩個值(value1,value2)

require "luanet"

luanet.load_assembly("System")

luanet.load_assembly("testLuaInterface")

Program =luanet.import_type("testLuaInterface.Program")

program1= Program()

void,strLength=program1:TestOut("www.kerven.com.cn")

print(void,strLength)

void,count=program1:TestRef("www.kerven.com",20)

print(void,count)

當有重載函數的時候,調用函數會自動匹配第一個能匹配的函數

可使用get_method_bysig函數獲得C#中指定類的指定參數的函數用法

luaMethod = get_method_bysig(Obj,"CSharpMethod","System.String")

           luaMethod("siki")

在Lua中註冊C#中的事件委託(event delegate)

在Lua中經過Add方法或者Remove方法把一個Lua的函數註冊或者註銷從C#中的事件委託中

  function method()

  end

  obj.SomeEvent:Add(methodname(不用帶引號))

 

第 4 章 : AssetBundle

課時18:401-什麼是AssetBundle以及如何打包AssetBundle 11:04

利用AssetBundle進行簡單的打包

using System.IO;

using UnityEditor;

public class CreateAssetBundles{

    [MenuItem("Assets/Build AssetBundles")]

    static void BuildAllAssetBundles()

    {

        string dir = "AssetBundles";

        if (Directory.Exists(dir) == false)

        {

            Directory.CreateDirectory(dir);

        }

        BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None,

            BuildTarget.StandaloneWindows64);

    }

}

課時19:402-Manifest文件介紹 04:52

AssetBundles.manifest記錄裏面的資源

課時20:403-如何下載並記載AssetBundle 10:07

using System.Collections;

using UnityEngine;

public class LoadAssetBundle : MonoBehaviour {

    /// <summary>

    /// 第三種加載方式:www

    /// </summary>

    /// <returns></returns>

    IEnumerator Start()

    {

        string path = @"file:///F:\經典學習案例,忘記了能夠回頭看的案例\siki的熱更新專題\HotUpdateProject\AssetBundles\player.unity3d";

        while (Caching.ready == false)

        {

            yield return null;

        }

        WWW www = WWW.LoadFromCacheOrDownload(path, 1);

        yield return www;

        if (string.IsNullOrEmpty(www.error) == false)

        {

            Debug.Log(www.error);

            yield break;

        }

        AssetBundle ab = www.assetBundle;

        //使用裏面的資源

        var wallPrefab = ab.LoadAsset<GameObject>("player");

        Instantiate(wallPrefab);

    }

}

 

第 5 章 : ulua

課時21:501-ulua介紹和uLua SimpleFramework下載 06:29

看官網的撕逼文章 http://ulua.org/index.html

課時22:502-ulua simpleframework目錄介紹 05:09

導入工程到unity,介紹目錄結構

課時23:503-案例解釋LuaState和LuaScriptMgr 13:10

using UnityEngine;

using System.Collections;

using LuaInterface;

public class HelloWorld : MonoBehaviour {

    // Use this for initialization

    void Start () {

        LuaState l = new LuaState();

        string str = "print('hello world 世界')";

        l.DoString(str);

    }

}

using UnityEngine;

using System.Collections;

using LuaInterface;

public class CreateGameObject01 : MonoBehaviour {

    private string script = @"

            luanet.load_assembly('UnityEngine')

            GameObject = luanet.import_type('UnityEngine.GameObject')       

        ParticleSystem = luanet.import_type('UnityEngine.ParticleSystem')           

            local newGameObj = GameObject('NewObj')

            newGameObj:AddComponent(luanet.ctype(ParticleSystem))

        ";

    //反射調用

    void Start () {

        LuaState lua = new LuaState();

        lua.DoString(script);

    }

}

using UnityEngine;

using System.Collections;

using LuaInterface;

public class CreateGameObject02 : MonoBehaviour {

    private string script = @"

            luanet.load_assembly('UnityEngine')

            GameObject = UnityEngine.GameObject

            ParticleSystem = UnityEngine.ParticleSystem

            local newGameObj = GameObject('NewObj')

            newGameObj:AddComponent(ParticleSystem.GetClassType())

        ";

    //非反射調用

    void Start () {

        LuaScriptMgr lua = new LuaScriptMgr();

        lua.Start();

        lua.DoString(script);

    }

}

課時24:504-在Unity中訪問Lua中的變量 07:01

using UnityEngine;

using System.Collections;

using LuaInterface;

public class AccessingLuaVariables01 : MonoBehaviour {

    private string script = @"

            luanet.load_assembly('UnityEngine')

            GameObject = luanet.import_type('UnityEngine.GameObject')

ParticleSystem = luanet.import_type('UnityEngine.ParticleSystem')

            particles = {}

            for i = 1, Objs2Spawn, 1 do

                local newGameObj = GameObject('NewObj' .. tostring(i))

                local ps = newGameObj:AddComponent(luanet.ctype(ParticleSystem))

                ps:Stop()

                table.insert(particles, ps)

            end

            var2read = 42

        ";

    // Use this for initialization

    void Start () {

        LuaState l = new LuaState();

        // Assign to global scope variables as if they're keys in a dictionary (they are really)

        l["Objs2Spawn"] = 5;

        l.DoString(script);

        // Read from the global scope the same way

        print("Read from lua: " + l["var2read"].ToString());

        // Get the lua table as LuaTable object

        LuaTable particles = (LuaTable)l["particles"];

        // Typical foreach over values in table

        foreach( ParticleSystem ps in particles.Values )

        {

            ps.Play();

        }

    }

}

using UnityEngine;

using System.Collections;

using LuaInterface;

public class AccessingLuaVariables02 : MonoBehaviour

{

    //cstolua要求必需要先定義變量才能使用

    private string var = @"Objs2Spawn = 0";

    private string script = @"           

            particles = {}

ParticleSystem = luanet.import_type('UnityEngine.ParticleSystem')

            for i = 1, Objs2Spawn, 1 do

                local newGameObj = GameObject('NewObj' .. tostring(i))

                local ps = newGameObj:AddComponent(luanet.ctype(ParticleSystem))

                ps:Stop()

                table.insert(particles, ps)

            end

            var2read = 42

        ";

    // Use this for initialization

    void Start () {       

        LuaScriptMgr mgr = new LuaScriptMgr();

        mgr.Start();

        // Assign to global scope variables as if they're keys in a dictionary (they are really)

        LuaState l = mgr.lua;

        l.DoString(var);

        l["Objs2Spawn"] = 5;

        l.DoString(script);

        // Read from the global scope the same way

        print("Read from lua: " + l["var2read"].ToString());

        // Get the lua table as LuaTable object

        LuaTable particles = (LuaTable)l["particles"];

        // Typical foreach over values in table

        foreach( ParticleSystem ps in particles.Values )

        {

            ps.Play();

        }

    }

}

課時25:505-執行Lua腳本文件,調用Lua方法,在Lua中使用協程 07:24

講述了第4、5、六個例子。

using UnityEngine;

using System.Collections;

using LuaInterface;

public class LuaCoroutines : MonoBehaviour

{

    private string script = @"                                  

            function fib(n)

                local a, b = 0, 1

                while n > 0 do

                    a, b = b, a + b

                    n = n - 1

                end

                return a

            end

            function CoFunc()

                print('Coroutine started')

                local i = 0

                for i = 0, 10, 1 do

                    print(fib(i))                   

                    coroutine.wait(1)

                end

                print('Coroutine ended')

            end

            function myFunc()

                coroutine.start(CoFunc)

            end

        ";

    private LuaScriptMgr lua = null;

    void Awake ()

    {

        lua  = new LuaScriptMgr();

        lua.Start();

        lua.DoString(script);       

        LuaFunction f = lua.GetLuaFunction("myFunc");

        f.Call();

        f.Release();

    }

    // Update is called once per frame

    void Update ()

    {       

        lua.Update();

    }

    void LateUpdate()

    {

        lua.LateUpate();

    }

    void FixedUpdate()

    {

        lua.FixedUpdate();

    }

}

課時26:506-框架啓動第一步GlobalGenerator,生成appview和gamemanager 12:43

GlobalGenerator--全局管理器

Image(17)

Image(18)

Image(19)

Image(20)

課時27:507-GameManager中對資源的更新處理 10:16

GameManager的工做流程

Image(21)

課時28:508-GameManager處理Lua的View的加載和初始化 11:51

課時29:509-Lua代碼中的結構和調用順序和對資源的處理和對遊戲邏輯的控制 14:19

課時30:510-建立開發UI界面 08:18

課時31:511-打包資源,建立GameManager的lua腳本 10:33

課時32:512-開發View視圖層下的Lua代碼,來獲取UI中的組件 14:31

課時33:513-開發Controller控制層下的Lua代碼,控制UI控件的產生和事件監聽 23:32

課時34:514-發佈到手機上,啓動Server,進行Lua代碼的更新 15:24

課時35:515-熱更新完結篇-遊戲資源更新和遊戲邏輯的更新

相關文章
相關標籤/搜索