コガネブログ

平日更新を目標にUnityやC#、Visual Studioなどのゲーム開発アレコレを書いていきます

【Unity】Lua で定義されたデータを C# で読み込み/書き込みできる「Lua Framework」紹介

概要

2015/2/20 に、Lua に関するアセット「Lua Framework」がリリースされました

Lua Framework を Unity プロジェクトに導入すると、
Lua で定義されたデータを C# に読み込み/書き込みできるようになります

外部で定義したデータを読み込みたい場合、XMLJSON を使用するという選択もありますが、
これらのマークアップ言語と違い、Lua ではデータ設計時にロジックを組むことができます

Lua Framework は「LuaReader」「LuaWriter」の 2 つのモジュールを用意しています
これらのモジュールは下記の型の読み込み/書き込みをサポートしています

  • ビルトインタイプ:bool、int、float、double、string、byte、decimal
  • Lua の関数
  • 列挙型
  • Unity の構造体:Color、Color32、Rect、Vector2、Vector3、Vector4
  • public プロパティを持つカスタムクラス
  • 一次元または二次元の配列
  • List と Dictionary
  • List<Dictionary<string, Vector3[]>> のようなネストされた型

Lua Framework を使用する時は Asset Store から「MoonSharp」を導入しておく必要があります

検証環境

  • Unity 5.6.2f1
  • Lua Framework 1.1
  • MoonSharp 2.0.0.1

LuaReader について

LuaReader を使用して Lua からデータを読み込む時は
下記の名前空間を using する必要があります

using LuaFramework;
using MoonSharp.Interpreter;

そして、Lua を制御するインスタンスを生成して、DoString 関数で Lua のコードを実行します

var lua = new Script();
lua.DoString( luaCode );

例えば Lua のコードを表す文字列から Vector3 の配列情報を読み込みたい場合は
次のような C# のプログラムで実現可能です

using LuaFramework;
using MoonSharp.Interpreter;
using UnityEngine;

public class Example : MonoBehaviour
{
    private void Awake()
    {
        var s = @"
        myVectors = {
            {0, 0, 45},
            {2, 0.5, 0},
            {5, 0, -2.5},
        }";
        var lua = new Script();
        lua.DoString( s );
        var myVectors = lua.Globals.Get( "myVectors" );
        var myVectorArray = LuaReader.Read<Vector3[]>( myVectors );

        foreach ( var myVector in myVectorArray )
        {
            Debug.Log( myVector );
        }
    }
}

f:id:baba_s:20170830174853p:plain

LuaReader.Read は、Vector3 の配列を float に変換しようとするなど
適切ではない型に変換しようとした場合、例外は出さずデフォルト値を返します

var f = LuaReader.Read<float>( myVectors ); // 0

LuaReader について その 2

// 敵情報を管理するクラス
public class Enemy
{
    public string name        { get; set; } // 名前
    public int    health      { get; set; } // 体力
    public float  attackPower { get; set; } // 攻撃力
}

敵情報を管理するこのようなクラスが存在する場合、
Lua に定義する敵情報は次のような形式になります

enemy 
{
    name        = "スライム",
    health      = 50,
    attackPower = 3.5,
}
enemy 
{
    name        = "ゴブリン",
    health      = 125,
    attackPower = 5,
}

そして、この Lua コードから敵情報を読み込む C# のプログラムは次のとおりです

using LuaFramework;
using MoonSharp.Interpreter;
using System;
using System.Collections.Generic;
using UnityEngine;

public class Enemy
{
    public string name        { get; set; }
    public int    health      { get; set; }
    public float  attackPower { get; set; }      
}

public class Example : MonoBehaviour
{
    public TextAsset luaFile;

    private List<Enemy> enemies = new List<Enemy>();

    private void Awake()
    {
        var lua = new Script();
        lua.Globals[ "enemy" ] = ( Action<DynValue> )DefineEnemy;
        lua.DoString( luaFile.text );

        foreach ( var enemy in enemies )
        {
            Debug.LogFormat
            ( 
                "{0}  HP: {1}  ATK: {2}", 
                enemy.name, 
                enemy.health, 
                enemy.attackPower 
            );
        }
    }

    private void DefineEnemy( DynValue luaTable )
    {
        var enemy = LuaReader.Read<Enemy>( luaTable );
        enemies.Add( enemy );
    }
}

f:id:baba_s:20170830175454p:plain

luaFile 変数に Luaスクリプトの参照を設定すると実行できます
Luaスクリプトは TextAsset として読み込むため、拡張子を .txt にする必要があります

f:id:baba_s:20170830174250p:plain

これで外部の Lua コードから敵情報を読み込むことができます
これだけだと、XMLJSON との違いがわからないと思いますが、
Lua では下記のようにデータ設計にロジックを組み込むことができます

health      = 50
attackPower = 3.5

enemy 
{
    name        = "スライム",
    health      = health,
    attackPower = attackPower,
}
enemy 
{
    name        = "メタルスライム",
    health      = health * 2 + 25,
    attackPower = attackPower + 1.5,
}
enemy 
{
    name        = "キングスライム",
    health      = health * 3 + 75,
    attackPower = attackPower + 3,
}

f:id:baba_s:20170830175552p:plain

Lua ではこのようにしてデータ設計のコストを抑えることが可能です

LuaWriter について

string luaCode;
using ( var luaWriter = new LuaWriter() )
{
    luaCode = luaWriter.ToString();
}

LuaWriter を使用することで Lua のコードを生成することができます
LuaWriter を使用する場合は LuaFramework 名前空間の using を追加する必要がありますが
MoonSharp 名前空間の using を追加する必要はありません

using LuaFramework;
using System.Collections.Generic;
using UnityEngine;

public class Example : MonoBehaviour
{
    private void Awake()
    {
        var colors = new Dictionary<string, Color32>
        {
            { "Red"             , new Color32( 255, 0, 0, 255 ) }, 
            { "Green"           , new Color32( 0, 255, 0, 255 ) }, 
            { "TransparentBlue" , new Color32( 0, 0, 255, 128 ) }, 
        };
        
        string luaCode;
        
        using ( var luaWriter = new LuaWriter() )
        {
            luaWriter.Write( "colors = " );
            luaWriter.WriteObject( colors );
            luaCode = luaWriter.ToString();
        }
        
        Debug.Log( luaCode );
    }
}

例えば上記のような C# のプログラムを実行すると
色情報を管理する Lua のコードを表す文字列を生成することができます

colors = {
    Red = {255, 0, 0, 255}, 
    Green = {0, 255, 0, 255}, 
    TransparentBlue = {0, 0, 255, 128}, 
}

あとは File.WriteAllText 関数などを使用すれば
生成された文字列を外部ファイルとして保存することができます

こうして LuaWriter を使用すれば、データを Lua コードとして保存することができます

まとめ

ゲームのマスタデータを Lua ファイルで手軽に管理することができるようになります
興味がある方は購入してみて頂ければと思います