Luaチュートリアル

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

sample.lua

1--1行のコメント
2
3--[[
4  複数行の
5  コメント
6]]

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

2.コンソールに文字列を表示する

sample.lua

1print("文字はダブルクォーテーション等で囲みます")
2
3local message = "Luaの変数の型は動的に変化するので、型を宣言する必要はありません"
4print(message)
5
6-- 文字列の結合は .. で繋ぎます
7print("ABC" .. "XYZ")
8
9-- printは「,」で区切って複数の値を表示できます
10print("ちなみに文字と数字も繋げられます", "ABC" .. 123)
譜面プレビューで「2」を押したときに表示されるConsoleの出力結果を文字で載せていきます。
出力結果
文字はダブルクォーテーション等で囲みます
Luaの変数の型は動的に変化するので、型を宣言する必要はありません
ABCXYZ
ちなみに文字と数字も繋げられます ABC123
print() のカッコの中に文字列を入れる事で、Consoleに文字を表示します。
また、=演算子はイコールという意味ではなく、右辺を左辺に代入するという意味になります。
数字が代入されている変数は自動で文字列に変換されてprintで出力されます。

3.Luaの文法:変数と値

ここからLuaスクリプトの文法を見ていきましょう。まずは変数と値です。
C言語などでは「変数は値を入れる箱のようなもの」というように例えられます。
Luaでもそれは変わらないのですが、変数の型は代入したデータによって動的に決まります。

3.1 値の種類

数値

数値

1x = 10
2x = 5.5
3x = 0xff -- 16進数
Luaでは、整数と実数(小数点値)は特に区別されません。

文字列

文字列

1x = "文字列"
2x = '文字列'
3x = [[文字列]]
ダブルクォート(")または、シングルクォート(')の場合は「\」で始まるエスケープシーケンス(\t、\nなど)が有効です。[[]]で囲った場合は、\文字や、さらに改行などもそのまま出力されます。

関数

関数

1x = function()
2  print("this is a function")
3end
Luaでは、関数も値としてやりとりすることができます。

テーブル

テーブル

1x = {a = 3, b = 5}
各種の構造を持ったデータを取り扱う場合に中心となるのがテーブルです。後で詳細に解説します。

ブール値(真偽値)

ブール値

1x = true
2x = false
ブール値は、true(真)と、false(偽)の2つのどちらかをとります。

3.2 変数とnil

変数にとって、nilは特別な値です。nilは変数が「空」であることを表します。
変数にnilを代入することはできますが、それはその変数を破棄するのと同じ意味になります。
また、変数の値を取得するとき、その変数が定義されていなければ、nilという値を返します。

未定義の変数

1-- 未定義のhogeという変数を参照してみる
2print(hoge)
出力結果
nil

3.3 グローバル変数とローカル変数

変数には、グローバル変数とローカル変数が存在します。Luaではデフォルトでグローバル変数になります。変数を設定するときに、変数名の前に「local」を付けると、ローカル変数になります。
ローカル変数はどこからでも参照できるわけではありません。local を付けた場合は local を宣言した関数の中や後述のif文やdo~end、for文、while文などでブロックを作成した場合もそのブロック内の変数定義した場所以降で参照することができます。
変数値を参照する場合、まずローカル変数から名前が検索され、なければグローバル関数から検索されます。
以下の例をみてみましょう。

グローバル変数とローカル変数

1-- グローバル変数
2abc = "global"
3
4do
5  -- ローカル変数 (do~endブロックの中だけで有効)
6  local abc = "local"
7  print("abc=", abc)
8end
9
10print("abc=", abc)
11
出力結果
abc=  local
abc= global
do~endブロックの中では、ローカル変数abcによって、グローバル変数abcが覆い隠されていることが分かります。

4.Luaの文法:演算子

表1にLuaで使用できる各種の演算子を示します。

表1. Luaの演算子

演算子演算使用例
+加算c = a + b
-減算c = a - b
*積算c = a * b
/除算c = a / b
%剰余 (割り算の余り)c = a % b
^累乗c = a ^ b
..文字列連結c = a..b
and論理積c = a and b
or論理和c = a or b
not否定c = not a
<値が小さいc = a < b
<=値が同じか小さいc = a <= b
>値が大きいc = a > b
>=値が同じか大きいc = a >= b
==値が等しいc = a == b
~=値が異なるc = a ~= b
#テーブルの配列部のサイズを求めるc = #t

5.Luaの文法:制御構造

5.1 分岐

分岐を行うif文を見てみましょう。ブレース(波括弧)の代わりにthen~endを使う点を除けば、C言語とそれほど変わりません。

ifによる分岐

1age = 22
2text = "20 歳未満"
3
4if age >= 20 then
5  text = "20 歳以上"
6end
7
8print(text)
出力結果
20 歳以上
条件式が偽の場合の処理を指定するために、elseを使うこともできます。

if~elseによる分岐

1if age >= 20 then
2  text = "20 歳以上"
3else
4  text = "20 歳未満"
5end

さらに条件分岐を行うためにelseifを使うこともできます。

if~elseif~elseによる分岐

1if age >= 20 then
2  text = "20 歳以上"
3elseif age >= 15 then
4  text = "20 歳未満"
5else
6  text = "15 歳未満"
7end

5.2 繰り返し

繰り返しを表現する制御構造を見ていきましょう。まずはfor文です。
1から10までを加算してその結果を表示してみましょう。

for文による繰り返し

1sum = 0
2for i = 1, 10 do
3  sum = sum + i
4end
5print("total : " .. sum)
6
出力結果
total : 55
iが変化しながら、doとendに挟まれた間の部分(ブロック)が繰り返し実行されます。Luaで次のように書いたとき、
1for i = a, b, c do
2end
C言語で次のように書いたのと同じことになります。
1for(int i = a; i <= b; i += c){
2}
Luaではcは省略可能で、その場合は1という値を指定したのと同じになります。
繰り返しの構造としては、for文のほかにwhile文を使用できます。(repeat文はここでは省略します)
while文の中で条件から抜け出す処理を書かないと無限ループするので注意しましょう。

while文による繰り返し

1i = 0
2while i < 5 do
3  i = i + 1
4  print(i)
5end
出力結果
1
2
3
4
5
for文、while文では処理の本体から「break」文を呼ぶことで、抜け出すことができます。一方、C言語のcontinueに相当するものは用意されていません。

メモ:break文および関数を抜け出すためのreturn文は、ブロックの最後でしか実行できないため、必要な場合は「do break end」のように、ブロックを作成して実行してください。

6.Luaの文法:テーブル(配列として)

さて、今度はLuaの特徴の1つであるテーブルを使ってみましょう。
テーブルは、キーと値のペアからなる連想配列、つまり辞書のようなデータ構造ですが、キーが数値である場合には配列としても機能します。
たとえば、表2のようなデータを表示できます。ここでは配列としてのテーブルを取り上げます。

表2. 配列としてのテーブルデータの例

キー要素
1ザクザク
2クランチ
3チョコ
まずはテーブルの作成です。
t = {}
これで内容が空のテーブルが作成され、グローバル変数tに入れられます。ブレース(波括弧)の「開く」、「閉じる」の組み合わせがテーブルの表現になります。
このテーブルに表2のデータを追加するには次のようにします。
t[1] = "ザクザク"
t[2] = "クランチ"
t[3] = "チョコ"
このテーブルは3つの要素を持った配列として機能します。Luaの配列で注意することは"添え字が常に1から開始する"ということです。(0やマイナス値をキー(添え字)として値をセットできますが、Luaの配列は全て添え字が1から始まる事を前提としているので十分な注意が必要です。)

同じ内容のテーブルを他の方法で作ることもできます。
t = {"ザクザク", "クランチ", "チョコ"}
では、このテーブルを使ったプログラムを作ってみましょう。
この例では、配列の3つの要素を連結して出力します。

配列としてのテーブル

1t = {"ザクザク", "クランチ", "チョコ"}
2print(t[1]..t[2]..t[3])
出力結果
ザクザククランチチョコ
また、ipairs関数を使って配列の持つすべての要素を巡回する方法もあります。
これによって、iには配列のインデックス値が、vには値が入ります。

配列としてのテーブルの巡回

1t = {"ザクザク", "クランチ", "チョコ"}
2for i, v in ipairs(t) do
3  print(i .. " : " .. v)
4end
出力結果
1 : ザクザク
2 : クランチ
3 : チョコ
配列としてのテーブルを巡回する方法として、もう1つの書き方が可能です。上記のコードのforブロックを次のように書き換えれば同じ出力結果が得られます。 なお、「#t」というのは、テーブルの配列としてのサイズを取得する方法です。この例では、テーブルtのキーとして、1から最大インデックス値までを順番に指定することで配列を巡回します。
for i = 1, #t do
  print(i .. " : " .. t[i])
end

7.Luaの文法:テーブル(連想配列として)

今度はテーブルの連想配列としての側面を見ていきましょう。連想配列というのは、辞書のように、キーと値の組を多数格納し、キーによって検索できるようなデータ構造のことです。

表3. 連想配列としてのテーブルデータの例

キー
nameLua
countryBrazil
表3のデータを表現するには、次のようにします。

連想配列としてのテーブル

1t = {}
2t["name"] = "Lua"
3t["country"] = "Brazil"
4
5print("name is " .. t.name .. ", country is " .. t.country )
出力結果
name is Lua, country is Brazil
配列の場合と似ていますが、キーとして数値ではなく、文字列が指定されています。
同じ内容のテーブルを作成する別の方法としてキーがアルファベットで始まる名前であれば、以下の方法が使えます。
t = { name = "Lua", country = "Brazil"}
次のように作成することもできます。
t = {} 
t.name = "Lua"
t.country = "Brazil"

連想配列を巡回する方法についても見ていきましょう。配列の場合と非常に似ていますが、ipairs関数ではなく、pairs関数を使います。

連想配列としてのテーブルの巡回

1t = { name = "Lua", country = "Brazil"}
2for k, v in pairs(t) do
3  print(k .. " : " .. v)
4end
出力結果
name : Lua 
country : Brazil
連想配列としてテーブルを巡回する場合は、各要素が出力される順序が変化する可能性があります。もし巡回する順序を一定にしたい場合は、テーブルを配列として使用する必要があります。

8.Luaの文法:関数定義と関数呼び出し

8.1 基本的な関数定義

Luaでは、関数定義の文法は次のようになります。

function 関数名(引数1, 引数2, ...)
  -- ここに処理内容
end
まずは、グローバル関数を定義してみます。次のコードは、aという名前の関数を定義し、それを実行する例です。

グローバル関数の定義と呼び出し

1-- Hello, Worldと出力する関数
2function a()
3  print("Hello, World")
4end
5
6-- 関数aを実行する
7a()
出力結果
Hello, World
次に、引数を持つ関数を定義してみます。

引数を持つ関数

1-- textの内容をn回printする関数
2function printTimes(n, text)
3  for i = 1, n do
4    print(text)
5  end
6end
7
8-- 引数を指定して関数を実行する
9printTimes(3, "Calling")
出力結果
Calling
Calling
Calling

関数の返り値

C言語の関数と同様に、Luaの関数はreturn文によって呼び出し側に値を返すことができます。

関数の戻り値(1個の場合)

1function foo()
2  return 100
3end
4
5local a = foo()
6
7print(a)
出力結果
100
さらに、Luaではreturn文で複数の値を返すことができます。

関数の戻り値(複数の場合)

1function foo()
2  return 100,200,300
3end
4
5local a,b,c = foo()
6
7print(a)
8print(b)
9print(c)
出力結果
100
200
300

8.2 さまざまな関数定義

Luaでは、関数を定義するための書き方がいくつか存在します。たとえば、次の2つの書き方は同じ意味になります。

-- 1つ目の書き方
function f()
  -- 処理
end

-- 2つ目の書き方
f = function()
  -- 処理
end
後者の書き方は、まず関数を名前の無い関数(無名関数)として作成し、それを変数にセットしていることになります。前者では、最初から名前の付いた関数を作成しているように見えますが、処理の内容は同一です。
さらに、テーブルをクラス風に使うための記法が存在します。1つ目と2つ目の書き方は同じになります。
a = {}

-- 1つ目の書き方
function a:b()
  -- 処理
end

-- 2つ目の書き方
function a.b(self)
  -- 処理
end
selfとは、C++のthisに相当するもので、「自分自身」を意味します。
a:b()のように関数を呼び出すと、selfにはaの値が代入されます。クラス風に記述する例を見てみましょう。

クラス風の関数定義

1-- テーブル Penを定義 (クラス風味)
2Pen = {
3  name = "This is a Pen!"
4}
5
6-- 「話す」メンバ関数を定義
7function Pen:talk()
8  print(self.name)
9end
10
11-- Penに話してもらう
12Pen:talk()
出力結果
This is a Pen!
関数呼び出しの「.」(ドット)と「:」(コロン)は、間違えやすいので注意が必要です。通常は、クラス(風味)のメンバ関数呼び出しであれば「:」を使い、そうでなければ「.」を使うという使い分けになります。
ダンカグライクのLuaAPIもクラスの変数名:関数名で呼び出すことができます。

ダンカグライクのLuaAPIの関数呼び出し例

1function onloaded()
2  SCREENMAN:SystemMessage("ダンカグライク")
3end
出力結果
ダンカグライク

9.ダンカグライクのイベント関数

sample.lua

1function onloaded()
2  -- Luaが読み込まれた後に実行される処理
3  SCREENMAN:SystemMessage("onloaded")
4end
5
6function start()
7  -- 開始を押して曲が始まる1フレームのみ実行される処理
8  SCREENMAN:SystemMessage("start")
9end
10
11function update()
12  -- 楽曲再生中に毎フレーム実行される処理
13  local currentBeat = GAMESTATE:GetSongBeat()
14  SCREENMAN:SystemMessage(currentBeat)
15end
16
17function ondestroy()
18  -- ゲーム画面終了時に実行される処理
19  print("lua destroy")
20end

onloaded、start、update、ondestroy等、
ゲーム側から特定のタイミングで実行される関数を「イベント関数」といいます。
また、LuaAPI ver1.1で新たに追加されたonHitNote関数等はゲーム側から引数に値が渡されてきます。

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

sample.lua

1-- 日時を表示
2print(os.date())
3-- フォーマットを指定して日時を表示
4print(os.date("%Y年 %m月 %d日"))
5-- ランダムな値
6print(math.random())
7-- 範囲を指定したランダムな値
8print(math.random(1, 100))
9-- 円周率
10print(math.pi)
11-- sin関数
12print(math.sin(math.pi/2))
13-- 引数の値の型を文字列で取得
14print(type(1))
15

出力結果
Fri Jun  2 00:57:26 2023
2023年 06月 02日
0.001251220703125
57
3.14159265358979
1.0
number
ライブラリとは様々な機能(関数)をまとめたプログラム群の事です。
予めLua自体の標準ライブラリが用意されており、使用することができます。
Luaのライブラリは Lua 5.4 リファレンスマニュアル に書かれています。
また、今回のチュートリアルに記載がないことも記載されておりますので、必要な場合はご確認ください。

11.Luaの基礎演習

チュートリアルの内容は以上となりますが、アウトプット学習として「Luaの基礎演習」を用意してみました。合わせてご利用ください。