Skip to content

Luaスキンの記述方法

excln edited this page Sep 18, 2018 · 3 revisions

概要

beatoraja 0.6 からスキンを Lua で記述することができます。この記事では大まかな仕様やおすすめの記述方法を説明します。

Lua スキンのメリット

CSV や JSON と異なり一般的なスクリプト言語なので、条件分岐、繰り返し、算術演算などを簡単に書いたり、類似する計算をまとめたりすることができます。これにより、スキンオプションによるパーツの変化などを全パターン書き下す必要がなくなり、データの記述と修正が楽になります。

現在(0.6.3)のところ、Lua スクリプトの実行タイミングはおもにスキン読み込み時です。そのため、表示する内容を実行中のスクリプト処理によって動的に変化させるようなことはできません。(後述のように一部実行中にスクリプトを動作させることでカスタマイズできる箇所もありますが、その影響範囲は限られています。)

仕様

スキンフォルダ内にある拡張子 .luaskin のファイルが1個のスキンと見なされ、Lua スクリプトとして実行されます。実行結果(Lua としての戻り値)は JSON スキン と同じ構造を持つテーブルとして解釈されます。

例えば、次のスクリプトは最小限の Lua スキンの例です。(プレイスキンとして必要な情報が抜けているため、実際に使おうとするとエラーが出るでしょうが。)

-- example.luaskin
return {
    type = 0,        -- skin type: 7keys
    name = "Skin Name",
    w = 1280,
    h = 720,
    playstart = 1000,
    scene = 3600000,
    input = 500,
    close = 1500,
    fadeout = 1000,
    property = {},
    filepath = {},
    offset = {}
}

デフォルトスキンに含まれる例

デフォルトスキンのうち、現在(0.6.3)24key SP プレイスキン(/skin/default/play24.luaskin)のみ Lua で記述されています。

他のデフォルトスキンはすべて JSON 形式なので、JSON スキンの仕様がわからない場合は参考にしてください。特に、何を書いていいか全くわからない場合はシンプルな 決定画面リザルト画面 をおすすめします。

スキンデータの仕様・JSON と Lua テーブルの対応関係

スキンデータの構造については、 JsonSkin クラス を参照してください。 JsonSkin クラスや、内部にある Property などのクラスに対応したデータを与えると、自動でデシリアライズされます。

各クラスの意味はこの記事では説明しきれませんが、LR2 スキン(CSV)との簡単な対応だけ説明しておきます。例えば、LR2 スキンでの画像表示

//SRC定義,(NULL),gr,x,y,w,h,div_x,div_y,cycle,timer,op1,op2,op3,,,,,,,
#SRC_IMAGE,0,0,432,408,32,13,1,1,0,0,0,0,0,,,,,,,
//DST定義,(NULL),time,x,y,w,h,acc,a,r,g,b,blend,filter,angle,center,loop,timer,op1,op2,op3
#DST_IMAGE,0,1600,555,435,32,13,0,0,255,255,255,2,0,0,0,2000,0,202,0,0
#DST_IMAGE,0,2000,555,435,32,13,0,255,255,255,255,2,0,,,,,,,

は、Lua では次のようになります。

return {
    type = 0,
    -- ...
    image = {
        -- ...
        { id = "example", src = 0, x = 432, y = 408, w = 32, h = 13 },
        -- ...
    },
    -- ...
    destination = {
        -- ...
        { id = "example", loop = 2000, blend = 2, op = {202}, dst = {
          { time = 1600, x = 555, y = 435, w = 32, h = 13, a = 0, r = 255, g = 255, b = 255 },
          { time = 2000, a = 255 }
        } },
        -- ...
    }
    -- ...
}

#SRC_ 系の命令は、その種類に応じたフィールド内(今回は IMAGE なので image フィールド)に、対応する #DST_ 系命令は種類にかかわらず destination フィールド内に書きます。また、これらに同じ id を与えることで SRC と DST の対応関係を表します。(id には文字列だけでなく数値を指定することもできます。)

これ以上の仕様については、デフォルトスキンや SkinProperty などを参考にしてください。

最後に、JSON と Lua テーブルの対応は以下のようになっています。

  • 真理値、数値、文字列はそのまま
  • JSON の配列 ⇔ Lua の配列(数字が添え字のテーブル)
  • JSON のオブジェクト ⇔ Lua のテーブル

Lua では配列とテーブルの区別が曖昧ですが、配列を書くべき場所かテーブルを書くべき場所かは決まっているので問題ありません。参考までに、前述の SRC/DST 定義の Lua に対応する JSON は次のようになります。作成済みの JSON スキンを Lua に変換する場合はほぼ機械的な変換で事足りるかと思います。

{
    "type": 0,
    
    "image": [
        
        { "id": "example", "src": 0, "x": 432, "y": 408, "w": 32, "h": 13 },
        
    ],
    
    "destination": [
        
        { "id": "example", "loop": 2000, "blend": 2, "op": [202], "dst": [
            { "time": 1600, "x": 555, "y": 435, "w": 32, "h": 13, "a": 0, "r": 255, "g": 255, "b": 255 },
            { "time": 2000, "a": 255 }
        ]},
        
    ],
    
}

スキン設定へのアクセス

スキン設定(カスタムオプション、カスタムファイル、カスタムオフセット)にはグローバル変数の skin_config でアクセスできます。変数の中身については SkinLuaAccessor を参照してください。

ただし、Lua スキンのスクリプトは読み込み時に「ヘッダ読み込み」と「本体読み込み」の2回実行され、前者では skin_config 変数が nil となることに注意してください。「ヘッダ読み込み」はスキン名などの基本的な情報と、どのようなスキンオプションが存在するかのデータを取得するための手順です。「本体読み込み」は、ユーザーが設定したスキンオプションに基づいてスキンの実体を取得するための手順です。「ヘッダ読み込み」ではスキン設定にアクセスできない代わりに destination などの実際に画面に表示するデータの部分が必要ないので、それらの部分は空白にして構いません。

おすすめの記述方法

最初に示した例のように .luaskin にデータをべた書きしてしまうと Lua のメリットが活かせません。また、テキストエディタの構文ハイライトを利用するために、大部分のデータは .lua ファイルに記述したいところです。スキン設定に柔軟に対応するために、以下のテンプレートを元に記述することをおすすめします。

-- play7.luaskin
local t = require("play7main")
if skin_config then
    return t.main()
else
    return t.header
end
-- play7main.lua
local header = {
    type = 0,
    name = "Example (7key)",
    w = 1280,
    h = 720,
    playstart = 1000,
    scene = 3600000,
    input = 500,
    close = 1500,
    fadeout = 1000,
    property = {
        -- カスタムオプション
        -- {name = "Judge Detail", item = {
        --     {name = "Off", op = 910},
        --     {name = "EARLY/LATE", op = 911},
        --     {name = "+-ms", op = 912}
        -- }}
    },
    filepath = {
        -- カスタムファイル
        -- {name = "Background", path = "background/*.png"}
    },
    offset = {
        -- カスタムオフセット
    }
}

local function main()
    -- ヘッダ情報をスキン本体にコピーします
    local skin = {}
    for k, v in pairs(header) do
        skin[k] = v
    end
    -- 以下でスキン本体のデータを定義します
    skin.source = {
        -- {id = 1, path = "background/*.png"},
    }
    skin.font = {
        -- {id = 0, path = "VL-Gothic-Regular.ttf"}
    }
    skin.image = {
        -- {id = "background", src = 1, x = 0, y = 0, w = 1280, h = 720},
    }
    skin.imageset = {
    }
    skin.value = {
        -- {id = 400, src = 5, x = 0, y = 0, w = 240, h = 24, divx = 10, digit = 4, ref = 91},
    }
    skin.text = {
        -- {id = 1000, font = 0, size = 24, align = 0, ref = 12}
    }
    skin.slider = {
        -- {id = 1050, src = 0, x = 0, y = 289, w = 14, h = 20, angle = 2, range = 520,type = 6}
    }
    skin.hiddenCover = {
    }
    skin.graph = {
    }
    skin.note = {
    }
    skin.gauge = {
    }
    skin.judge = {
    }
    skin.bga = {
        id = "bga"
    }
    skin.destination = {
        -- {id = "background", dst = { {x = 0, y = 0, w = 1280, h = 720} }},
    }
    return skin
end

return {
    header = header,
    main = main
}

play7.luaskinif skin_config then の部分で「本体読み込み」か「ヘッダ読み込み」かを判別しています。play7main.lua では、ヘッダ(header)と本体部分のデータを作成する関数(main)を返しています。main をわざわざ関数にした理由は、「ヘッダ読み込み」時に skin_config が使えなくてエラーになるのを防ぐとともに、スキン設定画面で余分な処理を行わず高速化するためです。(スキン設定画面ではすべてのスキンのヘッダのみ読み込むため)

また、異なるスキンの共通部分をくくりだす(例:SPとDPの部品の共通化など)には、適宜ファイルを分けて require で読み込むと良いでしょう。

その他

利用上の注意

Lua からはファイル入出力その他の OS 機能が利用可能なため、怪しい入手先のスキンを使うのは危険です。信頼できるスキンのみ、自己責任で使いましょう。

スキン作成側も、危険な処理を書かないのはもちろんのこと、スクリプトに間違いがあるとアプリ全体が落ちてしまうので十分にデバッグしましょう。

デバッグ方法

TODO

スキン実行中に使える Lua

数値系の SRC で参照値に文字列を与えると、実行時に文字列を Lua スクリプトとして実行してくれます。この中でスコアなどの情報を変数で参照することができます。使える変数とその意味については SkinLuaAccessor を参照してください。

スコアなどは実行時に変化していく情報のため、読み込み時には当然使えません。

また、JSON スキンでもこのタイプの Lua SRC 値を使うことができます。

Lua 関連の情報

Clone this wiki locally