Unity3D集成Lua

16k 词

|

分类

<a href="/categories/#lua之基础" title="lua之基础">lua之基础</a> 

|

关于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">&#34;num&#34;</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">&#34;str&#34;</span><span class="p">]</span> <span class="p">=</span> <span class="s">&#34;string&#34;</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">&#34;tab&#34;</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">&#34;str&#34;</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">&#34;LuaCode.lua&#34;</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">&#34;Controller.lua&#34;</span><span class="p">);</span>

    <span class="nf">CallLuaFunc</span><span class="p">(</span><span class="s">&#34;Controller.Start&#34;</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">&#34;Controller.Update&#34;</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">&#34;https://www.music.com/music.ogg&#34;</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">&#34;Rigidbody&#34;</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>