ユーザ用ツール

サイト用ツール


vci:script:luatutorial

Luaのチュートリアル (VCIScript)

Luaの基本的なプログラミングのチュートリアルになります。
このチュートリアルはVCIの作成とVCIスクリプトの導入まで終わったユーザー向けのものです。
まずはそちらを終了させてください。

※VCIスクリプトはLuaという言語を使用します。
(Lua - wikipedia)


チュートリアルの準備

こちらのチュートリアルをはじめる前に、
初めてVCIを作成する[開発環境の導入から、アイテム作成・実行まで]を終えてください。
必要な環境構築や基本的な手順について、このページでは説明しません。


チュートリアル一覧

Luaを使ったプログラミングを俯瞰する為の基本的なチュートリアルになります。
Luaの基本を把握した上で VCIスクリプトリファレンス を参考にしていただけると、VCIで様々な事ができるかと思います。


1.Luaのコメントについて

--1行のコメント
 
--[[
    複数行の
    コメント
]]
 
ここはコメントではないのでエラーになります

コメントとはプログラム本体には含まれない文章です。
1行のコメントはハイフンを2つ繋げた後の文字がコメントになります。
複数行のコメントはカッコで囲まれた部分が全てコメントになります。


2.ConsoleにPrintを表示する

main.lua
print("文字はダブルクォーテーションで囲みます")
 
message = "Luaの変数の型は動的に変化するので、型を宣言する必要はありません"
print(message)
 
--文字列の結合は .. で繋ぎます
name = "アリシア・ソリッド"
print("こんにちは"..name.."さん")
 
num = 1234
print("ナンバーは"..num.."です")

実行結果

文字はダブルクォーテーションで囲みます
Luaの変数の型は動的に変化するので、型を宣言する必要はありません
こんにちはアリシア・ソリッドさん
ナンバーは1234です

print() のカッコの中に文字列を入れる事で、Consoleに文字を表示します。
文字列を使う時は文字列の範囲を“”(ダブルクォーテーション)で囲います。 ※1
また、数字が代入されてる変数は自動で文字列に変換されてprintで出力されます。

※1 ““をつける事で、文字列なのか変数なのか区別をつける事ができます。


3.変数と型

main.lua
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公式ドキュメントをご確認ください。(値と型)


4.変数のスコープ

main.lua
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() の中だけです。


5.number型の扱いと結合

main.lua
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() で行います。

main.lua
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

6.テーブル型

main.lua
--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)は #テーブル とする事で知る事ができます。

連想配列

main.lua
people = {name = "babiko", age = 17}
print(people["name"])
print(people.age)

結果

babiko
17

キーと値をセットで保持する事で連想配列のように使う事もできます。
宣言する時は キー = 値 という風に宣言し、コロンで区切って宣言してゆきます。
アクセスする場合は、上記のようにカッコの中にキーを文字列で指定してアクセスするか、配列名.キー名 という風にピリオドで区切ってアクセスするかの二通りのパターンがあります。


7.if文

main.lua
function onGrab(subitem)
    --if文は if(条件式) then と書く
    if subitem == "bell" then
       print("linlinlin")
    else
       print("bellではありません")
    end
end

上記はsubitemがbellだった場合はlinlinlinと音をならし、bellじゃない場合はbellではない事を表示するサンプルです。
変数 == 値 という風に条件を指定して then の後に処理を書きます。
条件式には 関係演算子論理演算子 を使う事ができます。
これらの演算子を使う事である程度の複雑さなら条件として記述できます。
制御構造


8.for文 while文

for文

main.lua
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に加算する値を変更できます。
テーブル型と組み合わせる事で複数の要素をいっきに取り出したり処理できるので、大量の操作をするのに向いています。
for文

while文

main.lua
i = 0
while i < 5 do
   i = i +1
   print(i)
end

実行結果

1
2
3
4
5

while (条件式) do と書き、その後続く処理を書いて end でくくります。
条件を満たすまでの間、while文の中の処理を繰り返します。
while文の中で条件から抜け出す処理を書かないと無限ループするので注意しましょう。
制御構造


9.イベント関数を使う

main.lua
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]にも書かれています。


10.関数を自作する

main.lua
function hello()
    print("hello")
end
 
function onGrab()
    hello()
end

実行結果

hello

関数は自作する事ができます。
作成する場合は function 任意の関数名() で宣言し…関数の処理を書いて end で囲います。
関数を実行する時は イベント関数 の中で 作成した関数名() と書く事で実行できます。
VCIスクリプトでは自作の関数はイベント関数を経由して実行します。


11.関数の引数と戻り値

関数とは、ある入力に対して処理を行い、その結果を返してくれます。

main.lua
function onGrab(target)
    print(ShowPosition(target))
end
 
function ShowPosition(target)
    local pos = vci.assets.GetSubItem(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 に現在地の情報が代入され、結果として現在地を取得できます。

このような方法で関数を設定するメリットは以下の通りになります。

  • 関数の処理内容が分からなくても、引数と戻り値さえ理解すれば色々な結果を得る事ができる。
  • 似たような処理を繰り返し使う場合、関数を呼び出すだけで済んでしまう。(再利用性)
  • 他の人がプログラムを見た時の可読性を上げる事ができる。

12.Luaのライブラリを使おう

main.lua
--日時を表示
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 使えるライブラリには制限があります。


13.使えるライブラリの確認について

VCI TOP使えるライブラリ一覧 よりヘルプのファイルをダウンロード。
(Lua自体のライブラリも確認できます)

VCIのライブラリは VCIスクリプトリファレンス より確認できます。

また、Luaのみのプログラミングをしたい場合であれば codepad で簡易的な確認をする事ができます。
※上記は当然VCI固有の処理はできないので、純粋なLuaのプログラミングに使用します。

vci/script/luatutorial.txt · 最終更新: 2019/06/17 16:36 by h-eguchi

ページ用ツール