Unity3D集成Lua

| 分类 lua之基础  | 标签 lua  C#  Unity  LuaInterface  Luanet  CLR  MacOS  ToLua  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();

        // 创建Lua整形变量
        lua["num"] = 34;

        // 创建Lua字符串变量
        lua["str"] = "string";

        // 创建表 tab = []
        lua.NewTable("tab");

        Debug.Log((string)lua["str"]);
    }
}

结果在运行的时候出现报错

查阅一些资料,发现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;

    void Start()
    {
        // 定义Lua加载器,加载Lua文件
        new LuaResLoader();

        // 初始化Lua虚拟机
        lua = new LuaState();

        // 开启Lua虚拟机
        lua.Start();

        // 向虚拟机注册wrap类
        LuaBinder.Bind(lua);

        // 打开Lua文件
        lua.DoFile("LuaCode.lua");
    }
}

运行效果如下

使用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")

    -- 设置力
    force = 5
end


function this.Update()
    -- 获取键盘输入
    local h = Input.GetAxis("Horizontal")
    local y = Input.GetAxis("Vertical")

    -- 在对应方向上对刚体施加力
    rigid : AddForce(Vector3(h, 0, v) * force)
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;

    void Start()
    {
        // 定义Lua加载器,加载Lua文件
        new LuaResLoader();

        // 初始化Lua虚拟机
        lua = new LuaState();

        // 开启Lua虚拟机
        lua.Start();

        // 向虚拟机注册wrap类
        LuaBinder.Bind(lua);

        // 打开Lua文件
        lua.DoFile("Controller.lua");

        CallLuaFunc("Controller.Start");
    }

    void Update()
    {
        CallLuaFunc("Controller.Update");
    }

    // 调用函数
    void CallLuaFunc(string func_name)
    {
        // 获取Lua 方法
        LuaFunction luaFunc = lua.GetFunction(func_name);

        // 执行Lua 方法
        luaFunc.Call();
    }
}

测试的时候,每次启动程序就直接崩溃,单步调试发现,将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")

    -- 下载音乐
    local url = UnityEngine.WWW("https://www.music.com/music.ogg")

    -- 使用协程下载
    coroutine.www(url)

    -- 播放
    audio.clip = url : GetAudioClip()
    audio : Play()
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)
    
    -- 添加音乐组件
    Sphere : AddComponent(typeof(AudioSource))
    -- 启动协程调用Music.PlaySound() 方法
    coroutine.start(Music.PlaySound)

    -- 添加刚体
    Sphere : AddComponent(typeof(Rigidbody))
    rigid = Sphere : GetComponent("Rigidbody")

    -- 设置力
    force = 5
end


function this.Update()
    -- 获取键盘输入
    local h = Input.GetAxis("Horizontal")
    local y = Input.GetAxis("Vertical")

    -- 在对应方向上对刚体施加力
    rigid : AddForce(Vector3(h, 0, v) * force)
end

参考资料




如果本篇文章对您有所帮助,您可以通过微信(左)或支付宝(右)对作者进行打赏!


上一篇     下一篇