Unity3D集成Lua
关于Lua、C# 的语法,这里不做介绍,之前有很多文章都有涉及,可以翻看一下(本文参考资料部分会列出相关文章),OK,接下来专注于C# Lua 热更新技术
LuaInterface
LuaInterface 包括两个核心库,一个是LuaInterface.dll,一个是Luanet.dll,可以通过LuaInterface.dll 完成Lua 与C#(CLR)之间的互相调用
去http://files.luaforge.net/releases/luainterface/luainterface 下载相应版本的LuaInterface,比如我下载1.5.3版本
参考Visual Studio下使用Protobuf,将解压后的lua51.dll、LuaInterface.dll、luanet.dll 放到Unity 项目的Plugins 目录下即可
测试一下,在C# 中执行Lua 代码,编写代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LuaInterface;
public class CSharpCallLua : MonoBehaviour
{
private void Start()
{
// 创建Lua解释器
Lua lua = new Lua();
<span class="c1">// 创建Lua整形变量</span>
<span class="n">lua</span><span class="p">[</span><span class="s">"num"</span><span class="p">]</span> <span class="p">=</span> <span class="m">34</span><span class="p">;</span>
<span class="c1">// 创建Lua字符串变量</span>
<span class="n">lua</span><span class="p">[</span><span class="s">"str"</span><span class="p">]</span> <span class="p">=</span> <span class="s">"string"</span><span class="p">;</span>
<span class="c1">// 创建表 tab = []</span>
<span class="n">lua</span><span class="p">.</span><span class="nf">NewTable</span><span class="p">(</span><span class="s">"tab"</span><span class="p">);</span>
<span class="n">Debug</span><span class="p">.</span><span class="nf">Log</span><span class="p">((</span><span class="kt">string</span><span class="p">)</span><span class="n">lua</span><span class="p">[</span><span class="s">"str"</span><span class="p">]);</span>
<span class="p">}</span>
}
结果在运行的时候出现报错
查阅一些资料,发现LuaInterface.dll 是C# 的DLL,但是Luanet.dll、lua51.dll 是C 的DLL,依赖于Windows,所以无法在MacOS 上运行
ToLua
直接在https://github.com/topameng/tolua/releases下载,解压后是这样的目录结构
直接将Assets、Unity5.x 目录拖到Unity 项目目录下,与原有的目录合并、覆盖即可
等待Unity 加载完成,点击确认,目录结构如下
Editor/CustomSettings 主要是定义哪些类作为静态类、哪些类需要导出、哪些委托需要导出,注册到Lua 中的类型也都需要在这里导入,ToLua 已经提供了Unity 大部分的基础类型,如果需要导入我们自己的类,也可以在这里添加
开始编写测试代码,看C# 与Lua 的相互调用,先编写一个C# 代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CSharpCode : MonoBehaviour
{
public static string GetString()
{
// 直接返回一个字符串
return "CSharp Code";
}
}
编写这个脚本是为了给Lua 调用的,接下来再在CustomSettings 中添加我们的这个类,以供Lua 调用
然后在Unity 的【菜单栏】–>【Lua】–>【Clear wrap file】,可以看到重新生成新的wrap 文件
然后在Assets/Lua 下新增一个lua 文件,可以在这里调用刚才写的C# 代码,LuaCode.lua
local s = CSharpCode.GetString()
print(s)
再编写一个C# 脚本,在这里调用LuaCode.lua 中的源码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LuaInterface;
public class TestCallLua : MonoBehaviour
{
private LuaState lua = null;
<span class="k">void</span> <span class="nf">Start</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// 定义Lua加载器,加载Lua文件</span>
<span class="k">new</span> <span class="nf">LuaResLoader</span><span class="p">();</span>
<span class="c1">// 初始化Lua虚拟机</span>
<span class="n">lua</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LuaState</span><span class="p">();</span>
<span class="c1">// 开启Lua虚拟机</span>
<span class="n">lua</span><span class="p">.</span><span class="nf">Start</span><span class="p">();</span>
<span class="c1">// 向虚拟机注册wrap类</span>
<span class="n">LuaBinder</span><span class="p">.</span><span class="nf">Bind</span><span class="p">(</span><span class="n">lua</span><span class="p">);</span>
<span class="c1">// 打开Lua文件</span>
<span class="n">lua</span><span class="p">.</span><span class="nf">DoFile</span><span class="p">(</span><span class="s">"LuaCode.lua"</span><span class="p">);</span>
<span class="p">}</span>
}
运行效果如下
使用ToLua实现游戏逻辑
之前写的一些文章中,都是使用C# 来编写游戏逻辑的,现在有了ToLua,以及后续热更新的考虑,我们将游戏逻辑写到Lua 中
编写Controller.lua 如下
Controller = {}
local this = Controller
local GameObject = UnityEngine.GameObject
local Input = UnityEngine.Input
local Rigidbody = UnityEngine.Rigidbody
local Color = UnityEngine.Color
local Sphere – Unity中的一个球体
local rigid – 刚体
local force – 力
– 下面在Lua 中使用Start、Update函数名,与C# 中使用Start、Update没有任何关系
– 我们可以在Lua 中取任何名字
function this.Start()
Sphere = GameObject.Find("Sphere")
– 设置颜色
Sphere : GetComponent("Renderer").material.color = Color(1, 0.1, 1)
– 添加刚体
Sphere : AddComponent(typeof(Rigidbody))
rigid = Sphere : GetComponent("Rigidbody")
<span class="c1">-- 设置力</span>
<span class="n">force</span> <span class="o">=</span> <span class="mi">5</span>
end
function this.Update()
– 获取键盘输入
local h = Input.GetAxis("Horizontal")
local y = Input.GetAxis("Vertical")
<span class="c1">-- 在对应方向上对刚体施加力</span>
<span class="n">rigid</span> <span class="p">:</span> <span class="n">AddForce</span><span class="p">(</span><span class="n">Vector3</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> <span class="o">*</span> <span class="n">force</span><span class="p">)</span>
end
使用Lua 编写游戏逻辑的时候,没办法像在Visual Studio 中编写C# 那样有语法提示,所以极有可能写错且无法及时得到通知,当代码量很大的时候,一定要注意Lua 代码可能存在的各种语法、逻辑问题!
Lua 原生并不支持面向对象,可以用Lua 表来模拟面向对象的语法!
编写C# 代码如下,可以在C# 中直接调用Lua 代码,然后将这个C# 文件拖到某个游戏物体上即可实现对其的逻辑控制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LuaInterface;
public class TestCallLua : MonoBehaviour
{
private LuaState lua = null;
<span class="k">void</span> <span class="nf">Start</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// 定义Lua加载器,加载Lua文件</span>
<span class="k">new</span> <span class="nf">LuaResLoader</span><span class="p">();</span>
<span class="c1">// 初始化Lua虚拟机</span>
<span class="n">lua</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LuaState</span><span class="p">();</span>
<span class="c1">// 开启Lua虚拟机</span>
<span class="n">lua</span><span class="p">.</span><span class="nf">Start</span><span class="p">();</span>
<span class="c1">// 向虚拟机注册wrap类</span>
<span class="n">LuaBinder</span><span class="p">.</span><span class="nf">Bind</span><span class="p">(</span><span class="n">lua</span><span class="p">);</span>
<span class="c1">// 打开Lua文件</span>
<span class="n">lua</span><span class="p">.</span><span class="nf">DoFile</span><span class="p">(</span><span class="s">"Controller.lua"</span><span class="p">);</span>
<span class="nf">CallLuaFunc</span><span class="p">(</span><span class="s">"Controller.Start"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">void</span> <span class="nf">Update</span><span class="p">()</span>
<span class="p">{</span>
<span class="nf">CallLuaFunc</span><span class="p">(</span><span class="s">"Controller.Update"</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// 调用函数</span>
<span class="k">void</span> <span class="nf">CallLuaFunc</span><span class="p">(</span><span class="kt">string</span> <span class="n">func_name</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// 获取Lua 方法</span>
<span class="n">LuaFunction</span> <span class="n">luaFunc</span> <span class="p">=</span> <span class="n">lua</span><span class="p">.</span><span class="nf">GetFunction</span><span class="p">(</span><span class="n">func_name</span><span class="p">);</span>
<span class="c1">// 执行Lua 方法</span>
<span class="n">luaFunc</span><span class="p">.</span><span class="nf">Call</span><span class="p">();</span>
<span class="p">}</span>
}
测试的时候,每次启动程序就直接崩溃,单步调试发现,将TestCallLua.cs 一次拖到两个Unity 对象上,导致Start() 中创建Lua 执行环境、加载Lua 脚本的逻辑执行两遍,导致直接崩溃!
写代码的时候一定要特别小心、注意这种情况
操控方向键可以控制小球的移动
播放音乐(ogg)
先编写一个使用协程下载ogg 音乐并进行播放的Lua 代码
Music = {}
local this = Music
function this.PlaySound()
– 获取音乐组件(在Controller.lua 中添加的)
local audio = UnityEngine.GameObject.Find("Sphere") : GetComponent("AudioSource")
<span class="c1">-- 下载音乐</span>
<span class="kd">local</span> <span class="n">url</span> <span class="o">=</span> <span class="n">UnityEngine</span><span class="p">.</span><span class="n">WWW</span><span class="p">(</span><span class="s2">"https://www.music.com/music.ogg"</span><span class="p">)</span>
<span class="c1">-- 使用协程下载</span>
<span class="n">coroutine</span><span class="p">.</span><span class="n">www</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="c1">-- 播放</span>
<span class="n">audio</span><span class="p">.</span><span class="n">clip</span> <span class="o">=</span> <span class="n">url</span> <span class="p">:</span> <span class="n">GetAudioClip</span><span class="p">()</span>
<span class="n">audio</span> <span class="p">:</span> <span class="n">Play</span><span class="p">()</span>
end
然后修改原来的Controller.lua,使用协程执行Music.PlaySound
Controller = {}
local this = Controller
– 加载Music.lua 模块
require(modname: "Music")
local GameObject = UnityEngine.GameObject
local Input = UnityEngine.Input
local Rigidbody = UnityEngine.Rigidbody
local AudioSource = UnityEngine.AudioSource
local Color = UnityEngine.Color
local Sphere – Unity中的一个球体
local rigid – 刚体
local force – 力
– 下面在Lua 中使用Start、Update函数名,与C# 中使用Start、Update没有任何关系
– 我们可以在Lua 中取任何名字
function this.Start()
Sphere = GameObject.Find("Sphere")
– 设置颜色
Sphere : GetComponent("Renderer").material.color = Color(1, 0.1, 1)
<span class="c1">-- 添加音乐组件</span>
<span class="n">Sphere</span> <span class="p">:</span> <span class="n">AddComponent</span><span class="p">(</span><span class="n">typeof</span><span class="p">(</span><span class="n">AudioSource</span><span class="p">))</span>
<span class="c1">-- 启动协程调用Music.PlaySound() 方法</span>
<span class="n">coroutine</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="n">Music</span><span class="p">.</span><span class="n">PlaySound</span><span class="p">)</span>
<span class="c1">-- 添加刚体</span>
<span class="n">Sphere</span> <span class="p">:</span> <span class="n">AddComponent</span><span class="p">(</span><span class="n">typeof</span><span class="p">(</span><span class="n">Rigidbody</span><span class="p">))</span>
<span class="n">rigid</span> <span class="o">=</span> <span class="n">Sphere</span> <span class="p">:</span> <span class="n">GetComponent</span><span class="p">(</span><span class="s2">"Rigidbody"</span><span class="p">)</span>
<span class="c1">-- 设置力</span>
<span class="n">force</span> <span class="o">=</span> <span class="mi">5</span>
end
function this.Update()
– 获取键盘输入
local h = Input.GetAxis("Horizontal")
local y = Input.GetAxis("Vertical")
<span class="c1">-- 在对应方向上对刚体施加力</span>
<span class="n">rigid</span> <span class="p">:</span> <span class="n">AddForce</span><span class="p">(</span><span class="n">Vector3</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> <span class="o">*</span> <span class="n">force</span><span class="p">)</span>
end
参考资料
如果本篇文章对您有所帮助,您可以通过微信(左)或支付宝(右)对作者进行打赏!
上一篇 下一篇
<div id="uyan_frame"></div>
<script type="text/javascript" src="http://v2.uyan.cc/code/uyan.js?uid=2066802"></script>