Luaの基本的なプログラミングのチュートリアルになります。
このチュートリアルはVCIの作成とVCIスクリプトの導入まで終わったユーザー向けのものです。終わっていない方は、まずはそちらを終了させてください。
※VCIスクリプトの記述にはLuaというスクリプト言語を使用します。
こちらのチュートリアルをはじめる前に、 [ガイド]初めてVCIを作成する の[開発環境の導入から、アイテム作成・実行まで]を終えてください。
必要な環境構築や基本的な手順について、このページでは説明しません。
Luaを使ったプログラミングを俯瞰する為の基本的なチュートリアルになります。
Luaの基本を把握した上で VCIスクリプトリファレンス を参考にしていただけると、VCIで様々な事ができるかと思います。
--1行のコメント --[[ 複数行の コメント ]] ここはコメントではないのでエラーになります
コメントとはプログラム本体には含まれない文章です。
1行のコメントはハイフンを2つ繋げた後の文字がコメントになります。
複数行のコメントはカッコで囲まれた部分が全てコメントになります。
print("文字はダブルクォーテーションで囲みます") message = "Luaの変数の型は動的に変化するので、型を宣言する必要はありません" print(message) --文字列の結合は .. で繋ぎます name = "アリシア・ソリッド" print("こんにちは"..name.."さん") num = 1234 print("ナンバーは"..num.."です")
実行結果
文字はダブルクォーテーションで囲みます Luaの変数の型は動的に変化するので、型を宣言する必要はありません こんにちはアリシア・ソリッドさん ナンバーは1234です
print() のカッコの中に文字列を入れる事で、Consoleに文字を表示します。
文字列を使う時は文字列の範囲を“”(ダブルクォーテーション)で囲います。 ※1
また、数字が代入されてる変数は自動で文字列に変換されてprintで出力されます。
※1 ““をつける事で、文字列なのか変数なのか区別をつける事ができます。
⇒ コンソール
name = "アリシア・ソリッド" forever = true age = 17 object = nil --type()は変数の型を判定して結果をString型で返してくれます print(type(name)) print(type(forever)) print(type(age)) print(type(object))
実行結果
string boolean number nil
Luaで使える主な基本的な型は数値、文字列、真偽値、nil、テーブル(配列)、関数 等になります。
変数の型は代入したデータによって動的に決まります。
なので、変数宣言時に型を宣言する必要はなく、変数のみ宣言し代入演算子で直接データを代入できます。
全ての型を知りたい場合はLua公式ドキュメントをご確認ください。
Lua 5.2 リファレンスマニュアル - 2.1 値と型
GranCount = 0 function onGrab() GranCount = GranCount + 1 print("Grab : "..GranCount) --つかんでる回数が3の倍数か判定 local num = GranCount % 3 if num == 0 then print("3の倍数") end end function onUngrab() --アクセスできる print(GranCount) --アクセスできない print(num) end
実行結果
Grab : 1 Grab : 2 Grab : 3 3の倍数
Luaでは local
をつけずに宣言された変数はどこからでも呼べます。
(local
が無ければグローバル変数として扱う)
上記のサンプルの場合 GranCount
はどこからでも呼べます。
local
を付けた場合は local
を宣言した関数の中でしかアクセスできません。
上記のサンプルの場合 num
にアクセスできるのは onGrab()
の中だけです。
GrabCount = 0 function onGrab() GrabCount = GrabCount + 1 --型変換することなくprintで表示できます。 print(GrabCount) --文字列とnumber型の結合 print("Grab : "..GrabCount) --整数が代入されている場合、number型 print("GrabCountは"..type(GrabCount).."型です") --小数点の計算をしても型はnumber型 local num = GrabCount * 3.14159265 print(num) print("numは"..type(num).."型です") --文字列で宣言 local char = "1234" print("charは"..type(char).."型です") --文字列からnumber型への型変換 local conversion = tonumber(char) print("conversionは"..type(conversion).."型です") end
実行結果
1 Grab : 1 GrabCountはnumber型です 3.14159265 numはnumber型です charはstring型です conversionはnumber型です
Luaでは現状、int型とfloat型で区別はなく数値はnumber型として扱います。
(正確に言うと整数値がなく全て浮動小数点として扱っています)
また、print()
でnumber型を表示する場合は型変換する事なくそのまま表示できます。
文字列とnumber型の結合も型変換を行わずに可能です。結合には ..
を使用します。
文字列からnumber型への変換は tonumber()
で行います。
a = 2 b = 5 num = a + b --足し算 print("足し算"..num) num = a - b --引き算 print("引き算"..num) num = a * b --掛け算 print("掛け算"..num) num = a / b --割り算 print("割り算"..num) num = a % b --余りの計算 print("余りの計算"..num) num = a ^ b --べき乗 print("べき乗"..num)
実行結果
足し算7 引き算-3 掛け算10 割り算0.4 余りの計算2 べき乗32
--table型は ={} で宣言します table = { 3, 6, 9, 12, 15 } function onGrab() --for文を使って宣言 local t = {} for i = 1, 5 do t[i] = i end --まとめてテーブルを表示 print(t[1]..t[2]..t[3]..t[4]..t[5]) --for文で表示 -- #table でテーブルの要素数(length)が返ってきます for i = 1, #table do print("table "..i.." の値は "..table[i]) end end
実行結果
12345 table 1 の値は 3 table 2 の値は 6 table 3 の値は 9 table 4 の値は 12 table 5 の値は 15
Luaにおける配列はテーブル型になります。テーブル型は複数のデータをまとめて扱う場合に便利です。
テーブルを扱う際には、まとめてデータを操作したりする必要があるのでfor文を使用します。
テーブル型を宣言する時は c = {1, 2, 3, 4, 5}
と{}括弧で囲い宣言します。
アクセスする時は c[1]
という風に[]の中にアクセスしたいテーブルの番号を入れます。
テーブルの要素数(length)は #テーブル
とする事で知る事ができます。
※現在テーブルで扱える型は数値、文字列、真偽値、nilのみになります。
people = {name = "babiko", age = 17} print(people["name"]) print(people.age)
結果
babiko
17
キーと値をセットで保持する事で連想配列のように使う事もできます。
宣言する時は キー = 値
という風に宣言し、コロンで区切って宣言してゆきます。
アクセスする場合は、上記のようにカッコの中にキーを文字列で指定してアクセスするか、配列名.キー名 という風にピリオドで区切ってアクセスするかの二通りのパターンがあります。
function onGrab(subitem) --if文は if(条件式) then と書く if subitem == "bell" then print("linlinlin") else print("bellではありません") end end
上記はsubitemがbellだった場合はlinlinlinと音をならし、bellじゃない場合はbellではない事を表示するサンプルです。
変数 == 値
という風に条件を指定して then
の後に処理を書きます。
条件式には 関係演算子 や 論理演算子 を使う事ができます。
これらの演算子を使う事である程度の複雑さなら条件として記述できます。
Lua 5.2 リファレンスマニュアル
- 3.3.4 制御構造
- 3.4.3 関係演算子
- 3.4.4 論理演算子
num = {2, 4, 6, 8, 10} for i = 1, 5 do print(num[i]) end
実行結果
2 4 6 8 10
for iの初期値, 繰り返す回数 do
と定義すると for ~ end
で囲った処理を指定した回数繰り返します。
iは指定しなければfor文を繰り返す毎に1加算されます
for iの初期値, 繰り返す回数, iに加算する値 do
と書くとiに加算する値を変更できます。
テーブル型と組み合わせる事で複数の要素をいっきに取り出したり処理できるので、大量の操作をするのに向いています。
Lua 5.2 リファレンスマニュアル - 3.3.5 for文
i = 0 while i < 5 do i = i +1 print(i) end
実行結果
1 2 3 4 5
while (条件式) do
と書き、その後続く処理を書いて end
でくくります。
条件を満たすまでの間、while文の中の処理を繰り返します。
while文の中で条件から抜け出す処理を書かないと無限ループするので注意しましょう。
Lua 5.2 リファレンスマニュアル - 3.3.4 制御構造
function onGrab(target) print(target.."をつかみました") end function onUngrab(target) print(target.."を離しました") end function onUse(use) print(use.."をつかんだ状態で使用されました") end function onTriggerEnter(item, hit) print(item.."と"..hit.."が重なりました") end function onTriggerExit(item, hit) print(item.."と"..hit.."が重なった状態から離れました") end function onCollisionEnter(item, hit) print(item.."と"..hit.."が衝突しました") end function onCollisionExit(item, hit) print(item.."と"..hit.."が接触した状態から離れました") end
VCIをつかんだ時、離した時、使った時、触れた時、離れた時等…
VCIを使ってる状態を条件にして実行する関数を イベント関数 といいます。
また、イベント関数には引数を設定できます。
引数とは、関数が情報を受け取る仕組みです。
イベント関数の場合は SubItemのgameobject名が引数に渡される という決まりがあります。
イベント関数でSubitemの名前が受け取れると何がいいのか?といいますと… function onGrab(target)
の target
の文字列を見る事で、どのSubitemをつかんだのか?を知る事ができます。
つかんだアイテム名を知る事ができるので、そのアイテムに対して処理が施せるわけです。
(引数…例えば、所持金に対して、買えるジュースの本数を計算関数があるとします。この場合、関数を実行するのに所持金を知る必要があります。この所持金が引数にあたります。)
また、イベント関数の一覧は[EmbeddedScriptWorkspace]フォルダ内の[template.lua]にも書かれています。
function hello() print("hello") end function onGrab() hello() end
実行結果
hello
関数は自作する事ができます。
作成する場合は function 任意の関数名()
で宣言し…関数の処理を書いて end
で囲います。
関数を実行する時は イベント関数 の中で 作成した関数名()
と書く事で実行できます。
VCIスクリプトでは自作の関数はイベント関数を経由して実行します。
関数とは、ある入力に対して処理を行い、その結果を返してくれます。
function onGrab(target) print(ShowPosition(target)) end function ShowPosition(target) local pos = vci.assets.GetTransform(target).GetPosition() local posc = tostring(pos) local message = target.."の現在位置は"..posc.."です" return message end
実行結果
Subitemの現在位置は(0.0, 0.5, 0.1)です
関数を定義する際に引数と戻り値を設定する事ができます。
引数とは、関数が情報を受け取る仕組みなのに対して、戻り値とは、関数の計算結果を返す仕組みです。
引数は function 関数名(引数)
で定義され、戻り値は return 戻り値
で定義されます。
上記のサンプルでは ShowPosition()
関数は引数に target
を使用し、戻値は message
になります。
target
に引数としてSubitemの名前を渡してあげれば、message
に現在地の情報が代入され、結果として現在地を取得できます。
このような方法で関数を設定するメリットは以下の通りになります。
--日時を表示 print(os.date()) --フォーマットを指定して日時を表示 print(os.date("%Y年 %m月 %d日")) --ランダムな値 print(math.random()) --範囲を指定したランダムな値 print(math.random(1, 100)) --円周率 print(math.pi) --sin関数 print(math.sin(vci.me.FrameCount))
実行結果
2019年2月27日 14:20 2019年 02月 27日 0.152287599235907 25 3.14159265358979 0.97997642695433
ライブラリとは…様々な機能(関数)がつまったプログラム群の事です。
VCIではVCIに関するライブラリに加えて、Lua自体の標準ライブラリを使用する事ができます。※1
これらの機能を組み合わせて使いこなす事で、様々な処理を実現する事が可能です。
例えば、アナログ時計など作る場合は os.date()
によって得られる値を使って針の角度を変更すればよいわけです。
ランダム関数をつかえばおみくじなども作れます。
Luaのライブラリは Lua 5.2 リファレンスマニュアル に書かれています。
VCIで使用可能なライブラリはVCIスクリプトリファレンスの他、[EmbeddedScriptWorkspace]フォルダ内の[types.lua]からも定義されてる関数を確認する事ができます。
※1 使えるライブラリには制限があります。
旧VCIスクリプトリファレンス の リファレンス(自動出力) よりvcireferencedoc.zip
のファイルをダウンロード。
(Lua自体のライブラリも確認できます)
現在のVCIのライブラリは 新VCIスクリプトリファレンス より確認できます。
また、Luaのみのプログラミングをしたい場合であれば codepad で簡易的な確認をする事ができます。
※上記は当然VCI固有の処理はできないので、純粋なLuaのプログラミングに使用します。