开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

教程分享

关注:562

当前位置:游戏蛮牛 技术专区 教程分享

查看: 831|回复: 3

[基础知识] Unity热更新专题(八)uLua示例Demo简析及SimpleFramework工作流程

[复制链接]  [移动端链接]
7日久生情
3264/5000
排名
2618
昨日变化

1270

主题

1271

帖子

3264

积分

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

UID
132510
好友
17
蛮牛币
20661
威望
0
注册时间
2015-12-24
在线时间
248 小时
最后登录
2017-1-23
发表于 2016-1-12 15:15:38 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
  我们在进行热更新的完整案例之前。有必要分析一下uLua的实例代码,了解一下SimpleFramework工作流程,在我们制作实例时便于理解。

  1、LuaState

[AppleScript] 纯文本查看 复制代码
  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);

  }

  // Update is called once per frame

  void Update () {

  }

  }



  这个示例代码中就使用了LuaState。

  2、LuaScriptMgr

[AppleScript] 纯文本查看 复制代码
  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);

  }

  // Update is called once per frame

  void Update () {

  }

  }



  这个示例代码中就使用了LuaScriptMgr。

  上面的两个示例中,要注意一下的代码:

[AppleScript] 纯文本查看 复制代码
  private string script = @"

  luanet.load_assembly('UnityEngine')

  GameObject = UnityEngine.GameObject

  ParticleSystem = UnityEngine.ParticleSystem

  local newGameObj = GameObject('NewObj')

  newGameObj:AddComponent(ParticleSystem.GetClassType())

  ";



  大概工作流程就是先加载UnityEngine,然后创建一个GameObject变量,再调用AddComponent方法。其实就和Unity里面使用的差不多。很简单。不多说。

  3、在Unity中访问Lua中的变量

[AppleScript] 纯文本查看 复制代码
  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')

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

  ps:Stop()

  table.insert(particles, ps)

  end

  var2read = 42

  ";

  void Start () {

  LuaState l = new LuaState();

  l["Objs2Spawn"] = 5;            //就是这里

  l.DoString(script);

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

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

  foreach( ParticleSystem ps in particles.Values )

  {

  ps.Play();

  }

  }

  void Update () {

  }

  }



  4、执行Lua脚本文件,调用Lua方法,在Lua中使用协程

[AppleScript] 纯文本查看 复制代码
  using UnityEngine;

  using System.Collections;

  using LuaInterface;

  public class ScriptsFromFile_01 : MonoBehaviour

  {

  public TextAsset scriptFile;

  // Use this for initialization

  void Start()

  {

  LuaState l = new LuaState();

  l.DoString(scriptFile.text);

  }

  // Update is called once per frame

  void Update()

  {

  }

  }



  而我们的File文件就是在同目录下的与类同名的txt文件。

1.png


  注意,我们这里定义的File文件,是TextAsset类型。

[AppleScript] 纯文本查看 复制代码
  public TextAsset scriptFile;



  接下来就是调用Lua的方法。也很简单。

[AppleScript] 纯文本查看 复制代码
  using UnityEngine;

  using System.Collections;

  using LuaInterface;

  public class CallLuaFunction_01 : MonoBehaviour {

  private string script = @"

  function luaFunc(message)

  print(message)

  return 42

  end

  ";

  void Start () {

  LuaState l = new LuaState();

  l.DoString(script);

  LuaFunction f = l.GetFunction("luaFunc");

  object[] r = f.Call("I called a lua function!");

  print(r[0]);

  }

  void Update () {

  }

  }



  协程的使用:

[AppleScript] 纯文本查看 复制代码
  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();

  }

  void Update ()

  {

  lua.Update();

  }

  void LateUpdate()

  {

  lua.LateUpate();

  }

  void FixedUpdate()

  {

  lua.FixedUpdate();

  }

  }



  好了。uLua的示例代码我们就分析到这里了。接下来的可以自己琢磨,对于我们的案例来说已经够了。下面我们来分析一下自带热更新的案例的工作流程。也就是我们的SimpleFramework的工作流程。

  5、框架启动GlobalGenerator,生成appview和gamemanager

  在这里我们首先要看一下框架的目录。

  整个SimpleFramework采用的是PureMVC的框架。看下图。

2.png


  GlobalGenerator.cs

[AppleScript] 纯文本查看 复制代码
  using UnityEngine;

  using System.Collections;

  namespace SimpleFramework {

  /// <summary>

  /// 全局构造器,每个场景里都有,所以每个场景都会初始化一遍,也会初始化游戏管理器一次

  /// 如果游戏管理器已经存在了,就跳过了,否则创建游戏管理器,来保证游戏里只有一个GameManager

  /// </summary>

  public class GlobalGenerator : MonoBehaviour {

  void Awake() {

  InitGameMangager();

  }

  /// <summary>

  /// 实例化游戏管理器

  /// </summary>

  public void InitGameMangager() {

  string name = "GameManager";

  gameObject.AddComponent<AppView>();

  GameObject manager = GameObject.Find(name);

  if (manager == null) {

  manager = new GameObject(name);

  manager.name = name;

  AppFacade.Instance.StartUp();   //启动游戏

  }

  }

  }

  }



  这段代码就是我们热更新的入口。

  这里GlobalGenerator的任务就完成了。

  appview和gamemanager都是框架相关的东西。这里我们就只对GameManager进行分析。

  6、GameManager中对资源的更新处理及处理Lua的View的加载和初始化

  GameManager的功能就如这个标题所说。

  代码中也有详细注释。

  我们就不贴代码了。

  我们关注一下GameManager组件下的脚本。

3.png


  然后。我们要重点分析Lua文件夹下的Lua脚本。

4.png


  GameManager.cs:

  ①加载所有Lua脚本

[AppleScript] 纯文本查看 复制代码
  public LuaScriptMgr uluaMgr;

  private List<string> downloadFiles = new List<string>();



  ②初始化


[AppleScript] 纯文本查看 复制代码
  void Init() {

  DontDestroyOnLoad(gameObject);  //防止销毁自己

  CheckExtractResource(); //释放资源

  Screen.sleepTimeout = SleepTimeout.NeverSleep;

  Application.targetFrameRate = AppConst.GameFrameRate;

  }



  我们可以看看AppConst.cs文件,里面主要是一些配置。

[AppleScript] 纯文本查看 复制代码
  using UnityEngine;

  using System;

  using System.Collections;

  using System.Collections.Generic;

  namespace SimpleFramework {

  public class AppConst {

  public const bool DebugMode = false;                       //调试模式-用于内部测试

  /// <summary>

  /// 如果想删掉框架自带的例子,那这个例子模式必须要

  /// 关闭,否则会出现一些错误。

  /// </summary>

  public const bool ExampleMode = true;                       //例子模式

  /// <summary>

  /// 如果开启更新模式,前提必须启动框架自带服务器端。

  /// 否则就需要自己将StreamingAssets里面的所有内容

  /// 复制到自己的Webserver上面,并修改下面的WebUrl。

  /// </summary>

  public const bool UpdateMode = false;                       //更新模式-默认关闭

  public const int TimerInterval = 1;

  public const int GameFrameRate = 30;                       //游戏帧频

  public const bool UsePbc = true;                           //PBC

  public const bool UseLpeg = true;                          //LPEG

  public const bool UsePbLua = true;                         //Protobuff-lua-gen

  public const bool UseCJson = true;                         //CJson

  public const bool UseSproto = true;                        //Sproto

  public const bool LuaEncode = false;                        //使用LUA编码

  public const string AppName = "SimpleFramework";           //应用程序名称

  public const string AppPrefix = AppName + "_";             //应用程序前缀

  public const string ExtName = ".assetbundle";              //素材扩展名

  public const string AssetDirname = "StreamingAssets";      //素材目录

  public const string WebUrl = "http://localhost:6688/";      //测试更新地址

  public static string UserId = string.Empty;                 //用户ID

  public static int SocketPort = 0;                           //Socket服务器端口

  public static string SocketAddress = string.Empty;          //Socket服务器地址

  }

  }



  ④资源初始化结束

[AppleScript] 纯文本查看 复制代码
  public void OnResourceInited() {

  LuaManager.Start();

  LuaManager.DoFile("Logic/Network");      //加载游戏

  LuaManager.DoFile("Logic/GameManager");   //加载网络

  initialize = true;

  NetManager.OnInit();    //初始化网络

  object[] panels = CallMethod("LuaScriptPanel");

  //---------------------Lua面板---------------------------

  foreach (object o in panels) {

  string name = o.ToString().Trim();

  if (string.IsNullOrEmpty(name)) continue;

  name += "Panel";    //添加

  LuaManager.DoFile("View/" + name);

  Debug.LogWarning("LoadLua---->>>>" + name + ".lua");

  }

  //------------------------------------------------------------

  CallMethod("OnInitOK");   //初始化完成

  }



  我们看到熟悉的字眼了。

[AppleScript] 纯文本查看 复制代码
  LuaManager.DoFile("Logic/Network");      //加载游戏

  LuaManager.DoFile("Logic/GameManager");   //加载网络



  这正是我们Lua文件夹Logic文件夹下的脚本,我们来看看这两个脚本。

  Network.lua文件主要是网络相关的文件,我们就不分析了,重点看GameManager.lua。它相当于Lua脚本文件的起点。

[AppleScript] 纯文本查看 复制代码
  require "3rd/pblua/login_pb"

  require "3rd/pbc/protobuf"

  local lpeg = require "lpeg"

  local json = require "cjson"

  local util = require "3rd/cjson.util"

  local sproto = require "3rd/sproto/sproto"

  local core = require "sproto.core"

  local print_r = require "3rd/sproto/print_r"

  require "Logic/luaclass"

  require "Logic/CtrlManager"

  require "Common/functions"

  require "Controller/PromptCtrl"



  文件相关。不解释。

[AppleScript] 纯文本查看 复制代码
  GameManager = {};

  local this = GameManager;



  单例。你懂的。

[AppleScript] 纯文本查看 复制代码
  function GameManager.LuaScriptPanel()

  return 'Prompt', 'Message';

  end



  返回我们的UI相关类。

  我们结合两个文件一起看。


[AppleScript] 纯文本查看 复制代码
  function GameManager.LuaScriptPanel()

  return 'Prompt', 'Message';

  end



[AppleScript] 纯文本查看 复制代码
  object[] panels = CallMethod("LuaScriptPanel");

  //---------------------Lua面板---------------------------

  foreach (object o in panels) {

  string name = o.ToString().Trim();

  if (string.IsNullOrEmpty(name)) continue;

  name += "Panel";    //添加

  LuaManager.DoFile("View/" + name);

  Debug.LogWarning("LoadLua---->>>>" + name + ".lua");

  }



  这两段代码是相关联的。


[AppleScript] 纯文本查看 复制代码
  local transform;

  local gameObject;

  PromptPanel = {};

  local this = PromptPanel;

  --启动事件--

  function PromptPanel.Awake(obj)

  gameObject = obj;

  transform = obj.transform;

  this.InitPanel();

  warn("Awake lua--->>"..gameObject.name);

  end

  --初始化面板--

  function PromptPanel.InitPanel()

  this.btnOpen = transform:FindChild("Open").gameObject;

  this.gridParent = transform:FindChild('ScrollView/Grid');

  end

  --单击事件--

  function PromptPanel.OnDestroy()

  warn("OnDestroy---->>>");

  end



[AppleScript] 纯文本查看 复制代码
  local transform;

  local gameObject;

  MessagePanel = {};

  local this = MessagePanel;

  --启动事件--

  function MessagePanel.Awake(obj)

  gameObject = obj;

  transform = obj.transform;

  this.InitPanel();

  warn("Awake lua--->>"..gameObject.name);

  end

  --初始化面板--

  function MessagePanel.InitPanel()

  this.btnClose = transform:FindChild("Button").gameObject;

  end

  --单击事件--

  function MessagePanel.OnDestroy()

  warn("OnDestroy---->>>");

  end



  这两段代码得以执行。初始化UI界面。

  这里有个疑问?初始化界面是怎么得以实现的?

  其实也很简单,结合工程来看:

  这是初始化后得到的界面。

5.png


  其实我们早就把界面打包成Prefab了。

6.png


  对,就是这么来的,每个prefab对应生成AssetBundle。达到热的目的。

  好多啊。写得挺乱的。将就着看吧。

unity示例;protobuf unity使用;unity 示例 在哪里;unity protobuf 3;protobuf unity

回复

使用道具 举报

排名
15124
昨日变化
11

0

主题

22

帖子

60

积分

Rank: 2Rank: 2

UID
163925
好友
0
蛮牛币
65
威望
0
注册时间
2016-8-24
在线时间
18 小时
最后登录
2016-9-29
发表于 2016-9-1 18:24:43 | 显示全部楼层
确实很乱,案例在哪里

回复 支持 反对

使用道具 举报

排名
15741
昨日变化
11

0

主题

16

帖子

48

积分

Rank: 1

UID
20210
好友
0
蛮牛币
110
威望
0
注册时间
2014-4-4
在线时间
14 小时
最后登录
2016-12-22
发表于 2016-12-12 10:55:15 | 显示全部楼层
不错,谢谢楼主!!!!!!!!!!!!!!!

回复

使用道具 举报

6蛮牛粉丝
1273/1500
排名
1354
昨日变化
2

2

主题

127

帖子

1273

积分

Rank: 6Rank: 6Rank: 6

UID
54396
好友
0
蛮牛币
1073
威望
0
注册时间
2014-11-10
在线时间
520 小时
最后登录
2017-1-23
发表于 2017-1-4 11:11:05 | 显示全部楼层
这个教程,懂得人看了能懂,不懂的人看了还是不懂

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表