# Arcade Macro
ArcadeZeroにおけるマクロの作り方と使い方のチュートリアルです。
# はじめに
このドキュメントは、ArcadeZero v3.3以降においてマクロを作成して使用する方法の初心者向けガイド・参考資料となっています。もしマクロの作成に興味はなくてもすでに作成されたものを使用したいだけの場合は、ここに書かれているコードについては飛ばして読んでも大丈夫です。ただし、自分独自のマクロを作成したい方のために、このガイドではスクリプト言語であるLuaの基本的な知識を前提に説明します。
自分でマクロに関する問題解決ができるように、このページの内容をすべて読み通すことを強く推奨します。もしあなたがLuaの基礎について初心者である、またはご無沙汰な場合はこちらの公式チュートリアルを参照してください: https://www.lua.org/pil/contents.html
# はじめよう
必要なツール:
- ArcadeZero v3.3以降, またはマクロに対応しているArcadeZeroの派生バージョン
- 既製のマクロを使用する場合:他のソースから取得したマクロのLuaファイル
- マクロを作成する場合:高品質なIDEやテキストエディター (VSCodeがおすすめ)
このドキュメントは3つのパートに分かれています:
- マクロを使用する:概要と基本的な使い方の解説
- マクロを作成する:マクロを作る方法の解説
- リファレンス:使用可能なすべてのクラスとメソッドの詳細
# パート1. マクロを使おう
### 1. マクロとは?
マクロとは、タスク(やりたいこと)を自動化するための、外部の自作可能なスクリプトのことです。それらは本質的にはArcade内で動く小さなプログラムであり、ユーザーのさまざまなアクションや入力に基づいてArcadeに何をすべきかを指示するものです。
マクロは、手作業でやると大変手間と時間がかかるが、その手順を簡単に説明できる作業にとても適しています。
例: ノーツの位置をまとめてずらす、アークノーツを分割する、装飾トレースノーツを生成する、など…
### 2. マクロを導入する方法は?
マクロは一つの`.lua`スクリプトファイルで定義して(他のスクリプトファイルへも今後対応予定)、それらをArcade本体のあるフォルダ内の`Macros`というフォルダーに格納します。
例えば、Arcade本体を`D:\Programs\Arcade\`に保存している場合、自作のLuaスクリプトである`mirror.lua`は、`D:\Programs\Arcade\Macros\mirror.lua`のように格納します。
ArcadeZero内でマクロボタン(パズルピースのアイコン)を表示します。すると、マクロ選択メニューが表示されます。ここに自分で格納したマクロが表示されますが、表示されていない場合は更新ボタン(メニュー右上)を押してください。
### 3. マクロの使い方は?
Arcadeが起動したときやマクロのリストを更新したときに、Arcadeのプログラムは`Macros`フォルダ内にあるすべての有効な`.lua`スクリプトを探します。使用したいマクロの名称をクリックすることで、マクロの実行を始めることができます。もちろんその次に起こることはスクリプトによりますが(それが目的なので!)、分からない場合はスクリプトの作成者にお問い合わせください。
不正なスクリプトだった場合は画面上にエラーメッセージが表示されます。それを見かけたら、そのマクロは使用できないということになります。その際は自身で修正するか、スクリプトの作成者にお問い合わせください。
# パート2. マクロを作成する
もしArcadeのSceneControlドキュメントをご覧になっていたならば、ここでやることはほぼ同じです!
コードの動きの詳細な解説とともにいくつかの例と注意点を見ていきます。
このパートではマクロスクリプトを書く手順とその仕組みに慣れることを目的とします。
マクロでできることの全リストを見たい方は、パート3を参照してください。
## 例1. Hello world!
これは、マクロの基本的な構造がよく分かる究極の例です。実は、この中には実に多くの要素が詰まっているのです!
```lua
-- helloWorld.lua
addMacro("helloWorld", function()
notify("Hello World!")
end)
```
まずこれが何をしているのかを見てみましょう!このファイルがArcade本体を格納しているフォルダの中の`Macros`フォルダに入っていることを確認し、Arcade本体を起動してください。ArcadeZeroが起動したら、1.2と1.3にあるやり方に従って`helloWorld`というマクロを選択してください。すると、画面上側に「Hello World!」と書かれたトースト通知が表示されます。
何が起きたのかを見ていきましょう。
すべてのマクロは`addMacro`という関数によってArcadeに登録されます。好きなだけ`addMacro()`を追加することができて、Arcadeはそれらすべてを登録することができます。
- 第1引数ではマクロの名前を定めており、これがマクロ選択メニューのボタンに表示されます。この例では、`helloWorld`になります。
- 第2引数では関数を定めており、これはマクロが実行されるたびに行うべきことの指示のまとめを渡します。もしかしたら他の関数に、引数として関数を渡すという書き方にあまり馴染みがないかもしれませんが、この通りの書き方をすればいいだけなのでご安心ください。
- その関数の中では、「『Hello World!』とユーザーに通知せよ」というただ一つの指示をしています。
> 注!マクロの名前は唯一無二でなければなりません。もし「helloWorld」というもう一つのマクロを同じスクリプトや別のスクリプトで生成しようとした場合、エラーが投げられて、最初に見つかったその名前のマクロだけが読み込まれます。
探検家の皆さんは、こちらも自分でお試しください:
- `notify`に数値を渡す
- `notify`に2つ以上の引数を渡す
- `notify`の代わりに`log`を使う
- `..`で文字列を結合する (これが何なのかはLuaチュートリアルで調べてみましょう!)
- マクロを削除する (パート3を参照)
## 例2. ノートを生成する
早速、次の作業に入りますが、これはおそらくマクロを扱う上で最も一般的な作業でしょう・・・ノートを生成します。
先ほどの例では譜面プロジェクトを開く必要はありませんでしたが、ここでは譜面ファイルに対して作業を行うので、テスト用の空のプロジェクトを作成してください。
まずは簡単なスクリプトを見てみましょう:
```lua
-- addNote.lua
addMacro("addNote", function()
local tap = Event.tap(1000, 1, 0)
-- Timing 1000、レーン 1、TimingGroup 0 に配置するタップノートを生成
local command = tap.save()
-- commandにそのタップノートを保存する動作そのものを格納
command.commit()
-- commandに格納した動作(タップノートを保存する)を実行する
end)
```
実に無駄なことをしているように感じますが…信じてください、これにもちゃんと目的があるのですよ。
本当は一つのノートを生成するのにわざわざマクロを書くことなんてないと思います。
何のためにそのような手順を踏んでいるのか、少し見てみましょう。とりあえず、今はこれで…
> ご参考までに、上記のコードはこのように短縮できます
> ```lua
> -- addNote.lua
> addMacro("addNote", function()
> tap = Event.tap(1000, 1, 0)
> tap.save().commit()
> end)
> ```
> もしくはさらにこんな感じで
> ```lua
> -- addNote.lua
> addMacro("addNote", function()
> Event.tap(1000, 1, 0).save().commit()
> end)
> ```
> より少ないコードで同じことをしています
それでは、複数のノートを追加してみましょう。同時に、別の種類のノートも生成します。
```lua
-- addNote.lua
addMacro("addNote", function()
local tap = Event.tap(1000, 1, 0)
local command = tap.save()
command.commit()
local hold = Event.hold(1000, 2000, 1, 0)
-- 開始Timing 1000、終了Timing 2000、レーン 1、TimingGroup 0 のロングノート
hold.save().commit()
local arc = Event.arc(
2000, 0, 1, -- 開始Timing 2000、始点x座標 0、始点y座標 1
3000, 1, 1, -- 終了Timing 3000、終点x座標 0、終点y座標 1
false, -- Void(トレースノート化)無効
0, -- 青色
's', -- 移動タイプs
0 -- TimingGroup 0
)
arc.save().commit()
local trace = Event.arc(
3000, 1, 1, -- 開始Timing 3000、始点x座標 1、始点y座標 1
4000, 0, 0, -- 終了Timing 4000、終点x座標 0、終点y座標 0
true, -- Void(トレースノート化)有効
0, -- 青色
'sisi', -- 移動タイプsisi
0 -- TimingGroup 0
)
-- このように多く改行する必要はありませんが、
-- コードを読みやすくするためにも改行することをおすすめします
trace.save().commit()
local arctap = Event.arctap(2500, trace)
-- アークタップは少し奇怪です!これらはトレースノートに依存しています
-- なのでアークタップを生成する前にトレースノートを生成する必要があります
arctap.save().commit()
end)
```
いいですね、これで5つすべての種類のノートを用意できました。それでは早速マクロを実行してみましょう。譜面上に5つのノートが現れたはずです。素晴らしい!(ですよね?)
しかしここで問題があります。今のこのマクロでは、5回分のUndo(元に戻す)を行える操作を実行したことになるので、このマクロによる結果をすべてUndo(元に戻す)にはCTRL+Zを5回押すことになります。もし一度に何百個ものノートに変更を加えるマクロを書いていたとしたら、元に戻す作業は悪夢と化すでしょう。
これを直していきましょう!
```lua
-- addNote.lua
addMacro("addNote", function()
local batchCommand = Command.create()
local tap = Event.tap(1000, 1, 0)
batchCommand.add(tap.save())
local hold = Event.hold(1000, 2000, 1, 0)
batchCommand.add(hold.save())
local arc = Event.arc(
2000, 0, 1,
3000, 1, 1,
false,
0,
's',
0
)
batchCommand.add(arc.save())
local trace = Event.arc(
3000, 1, 1,
4000, 0, 0,
true,
0,
'sisi',
0
)
batchCommand.add(trace.save())
-- このように短縮することもできます
batchCommand.add(
Event.arctap(3500, trace).save()
)
batchCommand.commit()
end)
```
実行すると、一度のUndoで5つすべてのノートが消えたことが分かるはずです!Redo(やり直す、Undoを取り消す)でも同様です。
こちらはご自分でお試しください:
- ノートの追加処理でforループを使用する
- ノート内のパラメータに別の値を渡す。ただしTimingGroupには注意、存在しないTimingGroupを指定するとエラーとなる
- `Command.create()`に文字列を渡す (例. `Command.create("test macro")`)
## 例3. 貴方の努力をボタン一つで全破壊!!
次の例は全く役に立ちません。
このマクロはすべてのノートを消し去り、譜面を無に帰します。(実際のところは、バックアップがあるのでそんなこともないですが、面白半分なので)
ここで必要なのは譜面の中のすべてのノートを取得すること、およびそれらを削除することの2つです。
スクリプトを見てみましょう。
```lua
-- sakuzyo.lua
addMacro("sakuzyoBeam", function()
local allNotes = Event.query(EventSelectionConstraint.create().any())
local batchCommand = Command.create("SELF DESTRUCTION")
for i = 1, #allNotes["tap"], 1 do
batchCommand.add(allNotes["tap"][i].delete())
end
for i = 1, #allNotes["hold"], 1 do
batchCommand.add(allNotes["hold"][i].delete())
end
for i = 1, #allNotes["arc"], 1 do
batchCommand.add(allNotes["arc"][i].delete())
end
for i = 1, #allNotes["arctap"], 1 do
batchCommand.add(allNotes["arctap"][i].delete())
end
for i = 1, #allNotes["timing"], 1 do
batchCommand.add(allNotes["timing"][i].delete())
end
for i = 1, #allNotes["camera"], 1 do
batchCommand.add(allNotes["camera"][i].delete())
end
batchCommand.commit()
end)
```
ここで注目するべきところは以下の4つです。
1. `Event.query`を用いて、譜面の中のノートを検索します
2. `Event.query`に`EventSelectionConstraint`を渡して、どのノートが返されるか制限する必要があります。ここでは`any()`とすることによって、すべてのノートを返しています。
3. クエリは6種類のイベントタイプからなる6つの配列を返します。これらは`[{type}]`としてアクセスできます。
4. ここでは、それらすべてをループし削除コマンドを追加することによってすべてを削除しています。ただし、timingに関しては例外があります。0msに配置されているtimingを削除することはできません!(Arcadeはそれを無視します)
`EventSelectionConstranint`は後ほどまた出てくるので、今のうちになれておくと楽です。
## 例4. 任意のタイミングにノートを作成
例2に戻ります。今度は1000msのところにノートを作成するのではなく、タイミングを指定してノートを作成できるようにしましょう。
```lua
-- addNote.lua
addMacro("addNoteParam", function()
local request = TrackInput.requestTiming() -- ユーザーにtimingの数値を聞く
coroutine.yield() -- 応答を待つ
timing = request.result["timing"]
local batchCommand = Command.create()
local tap = Event.tap(timing, 1, 0)
batchCommand.add(tap.save())
local hold = Event.hold(timing, timing + 1000, 1, 0)
batchCommand.add(hold.save())
local arc = Event.arc(
timing + 1000, 0, 1,
timing + 2000, 1, 1,
false,
0,
's',
0
)
batchCommand.add(arc.save())
local trace = Event.arc(
timing + 2000, 1, 1,
timing + 3000, 0, 0,
true,
0,
'sisi',
0
)
batchCommand.add(trace.save())
-- このように短縮することもできます
batchCommand.add(
Event.arctap(timing + 2500, trace).save()
)
batchCommand.commit()
end)
```
ここで最も重要なスニペットに焦点を当てましょう。
```lua
local request = TrackInput.requestTiming() -- ユーザーにtimingの数値を聞く
coroutine.yield() -- 応答を待つ
local timing = request.result["timing"]
```
このスニペットの目的は、特にユーザーがパターンを作成したい場所の入力を、マクロのユーザーから取得することです。`TrackInput.requestTiming()`は、Arcadeをtiming入力モードに切り替えます。このモードでは、ユーザーはタップノートを作成する方法と同様に、トラックをクリックしてtimingを指定する必要があります。
ユーザーがトラックをクリックするのには少し時間がかかるため、luaコードがすぐに実行されないように `coroutine.yield()`を使用してマクロの実行を一時停止します。ユーザーが要求された情報を入力すると(この場合、パターンを作成するトラックの位置をクリックした後)、Arcadeはマクロを再開します。
`request`変数はArcadeがその情報をマクロに渡す場所です。`coroutine.yield()`の後、その情報が有効であることを確認し、`timing = request.result["timing"]`で取得を続行します。このtiming変数には、ユーザーが指定したtimingが渡されます。
残りは簡単です!パターンを`timing`でオフセットする(パターンを適用するtimingを`timing`の値だけ前後にずらす)だけです。さあ、マクロを試してみてください!
例題:
- `TrackInput.requestPosition(timing)`を試してみる。
これは少しトリッキーで、垂直入力の面を配置する場所を指定するためにtimingパラメータを渡す必要があります。通常は`TrackInput.requestTiming()`を使用して、その結果を `TrackInput.requestPosition(timing)`の引数`timing`に渡します。
- リクエストして待つのを2回繰り返してみてください
### 例4.5. 自爆ボタン!(オーバーフロー)
それでは、「リクエスト&待機」を例3の自爆ボタン(テンペストゲージ)にも適用してみましょう!今回は、ユーザーが間違って譜面を彼らの努力とともに消し去ってしまわないように、確認のメッセージを表示しましょう。
今回使用するのは`DialogInput`です。
```lua
-- sakuzyo.lua
addMacro("sakuzyoBeam", function()
local codeField =
DialogField.create("code")
.setLabel("Confirmation")
.setTooltip("Your confirmation code is 61616") -- 確認コードは61616です
.setHint("INPUT CONFIRMATION CODE") -- 確認コードを入力してください
.textField(FieldConstraint.create().integer())
local request =
DialogInput
.withTitle("INITIATING SELF DESTRUCTION") -- 自己破壊開始
.requestInput({codeField})
coroutine.yield()
local inputtedCode = request.result["code"]
if inputtedCode != "61616" then
notify("Destruction sequence shut down") -- 自己破壊シーケンス停止
return
end
local allNotes = Event.query(EventSelectionConstraint.create().any())
local batchCommand = Command.create("SELF DESTRUCTION")
for i = 1, #allNotes["tap"], 1 do
batchCommand.add(allNotes["tap"][i].delete())
end
for i = 1, #allNotes["hold"], 1 do
batchCommand.add(allNotes["hold"][i].delete())
end
for i = 1, #allNotes["arc"], 1 do
batchCommand.add(allNotes["arc"][i].delete())
end
for i = 1, #allNotes["arctap"], 1 do
batchCommand.add(allNotes["arctap"][i].delete())
end
for i = 1, #allNotes["timing"], 1 do
batchCommand.add(allNotes["timing"][i].delete())
end
for i = 1, #allNotes["camera"], 1 do
batchCommand.add(allNotes["camera"][i].delete())
end
batchCommand.commit()
end)
```
ダイアログはかなり複雑な機能です。複数の入力フィールドを持った一つのダイアログを作成し、それぞれのフィールドに入力された値を読み取ることができます。また、ユーザーが正しいフォーマットでしか入力できないようにしなければなりません。(整数のみ、整数と小数を受け入れるがアルファベットは受け付けない、など)これらの問題を処理するのが`DialogField`です。
```lua
local codeField =
DialogField.create("code")
.setLabel("Confirmation code")
.setTooltip("Your confirmation code is 61616")
.setHint("INPUT CONFIRMATION CODE")
.textField(FieldConstraint.create().integer())
```
このスニペットは以下のようになります:
- 変数`codeField`はダイアログの入力フィールド
- "code"という*識別キー*で作成される
- フィールドの左側に表示される*ラベル*は"Confirmation code"とする
- マウスを乗せると"Your confirmation code is 61616"と書かれた*ツールチップ*が表示される
- 何も入力されていないときは、"INPUT YOUR CONFIRMATION CODE"という*ヒント*[^2451]を表示する
- このフィールドはテキストフィールドで、整数しか受け付けないという制約(入力規則)がある。
[^2451]: 何も入力されていないときに灰色で表示され、何かが入力されると消えるテキスト。
```lua
local request =
DialogInput
.withTitle("INITIATING SELF DESTRUCTION")
.requestInput({codeField})
```
このスニペットは例4と同じように入力用ダイアログを表示します。ダイアログのタイトルは"INITIATING SELF DESTRUCTION"で、1つの入力フィールドを持ちます。(`codeField`のことです)
> メモ:上の例では入力フィールドは1つですが、もちろん複数の入力フィールドを持つこともできます!
> ```lua
> DialogInput.withTitle("Test").requestInput({field1, field2, field2})
> ```
> さらに、テキストボックスだけでなく、ドロップダウンメニューやチェックボックスもあります。詳細はリファレンスを確認してください。
難しそうに聞こえるかもしれませんが、Arcadeでいじってみて、どうなるかを見てみましょう。そのうちコツがつかめるようになりますよ。
```lua
coroutine.yield()
local inputtedCode = request.result["code"]
if inputtedCode != "61616" then
notify("Destruction sequence shut down")
return
end
```
最後に、ユーザーの入力を待機し、入力されたコードを"code"というキーから取得し(もし忘れてしまっていたなら:`DialogField.create("code")`で設定したキーです!)、正しいコードかチェックします。その後はもう大丈夫なはずです。
## 例5. amygdataのような細切れアーク
次の例は実用的なものです。安心しましょう、例3.5よりもとても簡単です。
今からArcadeで普通のアークノートをamygdataにあるような細切れアークに変換するマクロを作りましょう!
```lua
addMacro("amygdata", function()
local request = EventSelectionInput.requestSingleEvent(
EventSelectionConstraint.create().solidArc()
) -- 一つのみアークノートを選択させる
coroutine.yield() -- 応答を待つ
local arc = request.result["arc"][1]
batchCommand = Command.create("conversion to amygdata")
local arcLength = Context.beatLengthAt(arc.timing) / Context.beatlineDensity
-- アークを作成する
for timing = arc.timing, arc.endTiming, arcLength do
endTiming = math.min(timing + arcLength, arc.endTiming)
if (math.abs(endTiming - timing) <= 1) then break end
startXY = arc.positionAt(timing)
endXY = arc.positionAt(endTiming)
batchCommand.add(
Event.arc(
timing,
startXY,
endTiming,
endXY,
false,
arc.color,
arc.type,
arc.timingGroup
).save()
)
end
batchCommand.add(
arc.delete()
)
batchCommand.commit()
end)
```
やはり、もっとも特筆すべきところは、ユーザー入力の部分です。
```lua
local request = EventSelectionInput.requestSingleEvent(
EventSelectionConstraint.create().solidArc()
) -- 一つのみアークノートを選択させる
-- void Arc() を使用した場合、対象はトレースノートに限定される
coroutine.yield() -- 応答を待つ
local arc = request.result["arc"][1]
...
batchCommand.add(
arc.delete()
)
```
この例では、譜面の中から細切れアークにしたいアークノートを選択してもらい、そのデータ(Timingやアークの種類)を取得して、そのデータをもとに細切れアークを作成しています。このままだと元々のアークノートが重なるので、最後にそのアークノートを削除して完成です!
> 元々のアークノートのデータを取得するには `request.result["arc"][1]` とする必要があります。
> `reqest.result`だけでは取得できないことに注意してください。
最後に、`Context` クラスについて説明します。
このクラスは現在選択中のアークノートの色、アークノートのType、BPM等、非常に有用な情報を返してくれます。
このクラスでできることについてはリファレンスを是非ご覧ください。
例題:
- このマクロを改良して複数のアークノートを一度に変換できるようにしてみる (ヒント:`EventSelectionInput.requestEvents(..)`を使うと...?)
- トレースも変換できるようにしてみる (ヒント:`.arc`は`.solidArc()`と`.voidArc()`を組み合わせたものだから...?)
- まだこれはamygdataのような細切れアークではありません!アークノートの始点y座標と終点y座標が同じ場合、アークノートの支柱の列は作られません。これをamygdataのような細切れアークにしてみてください!
## 例6. マクロを作るマクロ、それを消すマクロ、それを…
ArcadeZero v3.3.2から、`addMacro`は他のマクロの中でさえも動作するようになりました!この更新で、マクロは面白い機能の実装を可能にします。
それではマクロを作るマクロ……`stash`[^2601]マクロを作りましょう!このマクロは、ユーザーが選択したものをスタッシュに保存し、それを譜面に貼り付けるマクロを自動的に追加します。
[^2601]: スタッシュ。隠す、しまう。プログラミングでは"退避"の意味で使われることもあります。
このセクションはかなり長く複雑で、これまでの例で触れた全ての知識が必要になります。また、これまでのセクションではコードを一度に全て出していましたが、今回はコードを一緒に順繰りに考えていきます。
(必要に応じてこのセクションの一番下にあるコードの全文もご覧ください)
さっそく始めましょう!まずこのマクロがどのように機能するのか、具体的に考えてみましょう。
1. まず、ユーザーがマクロを選択する
2. 次に、ユーザーはスタッシュに保存するノートを選択し、Enterを押して選択を確定する
3. ダイアログが表示されて、スタッシュの*名前*を尋ねる
4. 指定された名前のマクロが新たに作成される
5. 作成されたマクロが選択されると、ユーザーにタイミングの指定を求める
6. そのマクロのスタッシュが、指定されたタイミングに貼り付けられる
上記のそれぞれのステップは以前の例よりも実装が難しくなっています。一つずつ順に見ていきましょう。
まず、マクロを作成します(ステップ1)。
```lua
addMacro("stash", function()
end)
```
ステップ2も簡単です。ノートの選択をリクエストするだけです。
```lua
...
local eventRequest = EventSelectionInput.requestEvents(
EventSelectionConstraint.create().any(),
"スタッシュに格納するノートを選択してください。ENTERキーで確定します。")
coroutine.yield()
local events = eventRequest.result
...
```
これで、変数`event`にはユーザーが選択したノートが入っています。ステップ2まではこれだけです。
次は、スタッシュの名前を尋ねるダイアログを表示する必要があります。そう、例4.5の自爆ボタンでやりました!
```lua
...
local dialogRequest = DialogInput.withTitle("スタッシュ作成").requestInput({
DialogField
.create("name")
.setLabel("スタッシュの名前")
.setHint("任意の文字列")
.setTooltip("このスタッシュの名前は新しく生成されるマクロの名前となります")
})
coroutine.yield()
local name = dialogRequest.result["name"]
...
```
EX+くらいでしょうか、上々です。今までの例とは少し見た目が変わっていますが、本質的には同じことをやっています。
でも、ここから先は未知の領域です。何が問題なのか考えてみましょう。
- まず、一つのマクロから複数の異なる動作をするマクロを作成する必要があります。
- ノートのリストをどこかに保存する必要があります。そして、それぞれのマクロは正しいリストを取得し貼り付ける必要があります!
ひとつひとつ取り組んでいきましょう。ステップ2で取得した名前でマクロを登録してみます。まあ、とりあえず試してみましょう。
```lua
...
local name = dialogRequest.result["name"]
addMacro(name, function() end)
...
```
マクロを実行して、出てきたダイアログに保存したいスタッシュの名前を入れると……入力した通りの名前のマクロが作成されました!でも少し操作しにくいですね?この問題の解決は後でやることにしますが、`addMacro`がマクロ内で動くことはわかりました。
ここで、それぞれのマクロには異なる動作をしてもらう必要があります。これらのマクロを区別する唯一の方法がマクロの名前です。我々のマクロはこれらの情報を取り出すことはできるのでしょうか。試してみましょう!
```lua
...
local name = dialogRequest.result["name"]
addMacro(name, function()
notify(name)
end)
...
```
マクロを実行すると、ダイアログの入力欄に入力したものが通知として出力されました。すばらしい!`stash`というマクロはこうしてマクロ生成機となりました。これで一つ目の問題が解決しました。
2つ目の問題はやや奇怪で、LuaにおけるTableの挙動を理解している必要があります(もしHash MapやPythonの辞書型の理解がある場合は、Luaにおいてそれらを実現する方法を調べてみてください)。Tableの扱いに自信がない方は、冒頭のリンクにあるLuaの公式チュートリアルを参照してください。
これは一例ですが、作成したスタッシュの名前とノートの選択情報の組み合わせをリスト形式で格納するグローバル変数を作成します。
```lua
storedStashes = {}
addMacro("stash", ...)
```
`storedStashes = {}`を`addMacro("stash", function() ... end)`内に置くとどうなるのか試してみてもいいでしょう。(ネタバレ:このマクロを実行するたびに`storedStashes`が空になる)
とにかく、マクロを作成するたびに、このように新しいノートの選択情報を`storedStashes`に追加していくことができます。
```lua
storedStashes = {}
addMacro("stash", function()
...
local events = eventRequest.result
...
local name = dialogRequest.result["name"]
storedStashes[name] = events
addMacro(name, function()
notify(name)
end)
...
end)
```
では、このマクロがスタッシュのデータを正しく取得できているかどうかを試してみましょう。`stash`に入っているタップノートの数を通知に出力する簡単なコードを記述します。
```lua
addMacro(name, function()
local stash = storedStashes[name]
notify(#stash["tap"])
end)
```
生成されたマクロを試してみると、`name`に格納された名前のスタッシュに保存されたタップノートの数が出力されていることがわかります。実験は成功、ステップ4も完了です!
残りはステップ5と6だけです。少ないように聞こえますか?でもまだまだ考慮すべきことが残っています。
- スタッシュ内のノート内で最小のタイミングが必要です。
- 全てのノートをコピーして、タイミング(と終端タイミング)を変更する必要があります。
- そして、それらを全てバッチコマンドに保存する必要があり……
- 何よりも!スカイノートの取り扱いは……苦痛です。
いくつか方法はあります。一番手っ取り早いのは、少し前のコードをちょっといじることです。このステップを簡単にするために、スタッシュへの保存方法に一手間加えてみましょう。
これを……
```lua
local events = eventRequest.result
...
storedStashes[name] = events
```
こうします
```lua
-- これはもう必要ありません↓
-- local events = eventRequest.result
newStash = {}
newStash.events = eventRequest.resultCombined
newStash.arctaps = eventRequest.result["arctap"]
storedStashes[name] = newStash
```
`resultCombined`は全てのノートとイベントが混ざり合って入っているテーブルです。なぜ混ぜるのかと思うかもしれませんが、実際便利です。
`arctap`は他のノートとは別の方法で処理する必要があるので、他のと分けて格納します。
さあ、完成させましょう!まず、スタッシュを貼り付けるタイミングを取得し、バッチコマンドも作成します。
```lua
addMacro("stash."..name, function()
local stash = storedStashes[name]
local timingRequest = TrackInput.requestTiming(false, "このスタッシュを貼り付ける位置を選択してください")
coroutine.yield()
local timing = timingRequest.result["timing"]
local batchCommand = Command.create("pasting stash "..name)
-- Code to copy notes goes here
-- ここにノートをコピーするコード
batchCommand.commit()
end)
```
あとはノートをコピーするだけです。`event.is`を使ってノートの種類を判別することができます。スカイノートは、それが属するアークを追加するとき一緒にforループで追加します。
```lua
...
local batchCommand = Command.create("pasting stash "..name)
local allEvents = stash.events
local arctaps = stash.arctaps
local origin = allEvents[1].timing -- The minimum timing of all notes
-- リスト内の最小タイミング
-- (リストはタイミング順にソートされています)
local displace = timing - origin -- The amount to shift all notes by
-- ノートを移動させる量
for i = 1, #allEvents, 1 do
local event = allEvents[i].copy()
event.timing = displace + event.timing
if event.is('long') then -- Notes with endTiming also have to have this value updated
event.endTiming = displace + event.endTiming
end
batchCommand.add(event.save())
if event.is('arc') then
local arc = allEvents[i]
-- Look for arctaps belonging to this arc to copy
-- このアークに属しているスカイノートを探してコピーします
for i = 1, #arctaps, 1 do
local arctap = stash.arctaps[i]
if arctap.arc == arc then
local arctapCopy = arctap.copy();
arctapCopy.arc = event
arctapCopy.timing = displace + arctap.timing
batchCommand.add(arctapCopy.save())
end
end
end
end
batchCommand.commit()
...
```
ここで、スカイノートを保存する前にまずトレースノートを保存することが重要です(そうでなければ、スカイノートが配置される場所が無くなります)。
長い長い努力の末、スクリプトのコードがついに機能するようになりました。しかし、ここでマクロの使用感を改善するためにもうワンステップ取り組みましょう。Unityのリッチテキストフォーマットを用いてこのマクロを特徴づけていきましょう!
このマクロの生成を…
```lua
addMacro("stash."..name, ...)
```
から
```lua
addMacro("<color=#2E86AB>stash."..name.."</color>", ...)
```
に変更します。
これはマクロ選択ウィンドウにおけるこのマクロの名前の表示を派手な紺色に変えるもので、簡単にマクロの表示に特徴づけることができます。気軽に好みの色に変えていってください。
しかし、ここでマクロの並び順が変わるという問題が起きたのではないでしょうか。これは、マクロ名に含まれていて画面上には表示されていない記号`<`も、Arcadeのプログラム内部ではマクロ名の一部であるため、その記号も並べ替え基準の対象になっていることが原因です。これを解決するために、`addMacroWithSort`を使用します。
```lua
addMacroWithSort("<color=#2E86AB>stash."..name.."</color>", "stash."..name,...)
```
これで並び順は直りました。これを変更して新しいスタッシュを最後に配置するようにすることもできます。
こちらが最終形のコードです:
```lua
storedStashes = {}
addMacroWithSort("<color=#2E86AB>stash."..name.."</color>", "stash."..name, function()
-- Request for user's selection
local eventRequest = EventSelectionInput.requestEvents(
EventSelectionConstraint.create().any(),
"スタッシュに格納するノートを選択してください。ENTERキーで確定します。")
coroutine.yield()
-- Request for stash's name
local dialogRequest = DialogInput.withTitle("スタッシュ作成").requestInput({
DialogField
.create("name")
.setLabel("スタッシュの名前")
.setHint("任意の文字列")
.setTooltip("このスタッシュの名前は新しく生成されるマクロの名前となります")
})
coroutine.yield()
local name = dialogRequest.result["name"]
newStash = {}
newStash.events = eventRequest.resultCombined
newStash.arctaps = eventRequest.result["arctap"]
storedStashes[name] = newStash
notify(#newStash.events)
addMacro("stash."..name, function()
local stash = storedStashes[name]
local timingRequest = TrackInput.requestTiming(false, "このスタッシュを貼り付ける位置を選択してください")
coroutine.yield()
local timing = timingRequest.result["timing"]
local batchCommand = Command.create("pasting stash "..name)
local allEvents = stash.events
local arctaps = stash.arctaps
local origin = allEvents[1].timing -- The minimum timing of all notes
local displace = timing - origin -- The amount to shift all notes by
for i = 1, #allEvents, 1 do
local event = allEvents[i].copy()
event.timing = displace + event.timing
if event.is('long') then -- Notes with endTiming also have to have this value updated
event.endTiming = displace + event.endTiming
end
batchCommand.add(event.save())
if event.is('arc') then
local arc = allEvents[i]
-- Look for arctaps belonging to this arc to copy
for i = 1, #arctaps, 1 do
local arctap = stash.arctaps[i]
if arctap.arc == arc then
local arctapCopy = arctap.copy();
arctapCopy.arc = event
arctapCopy.timing = displace + arctap.timing
batchCommand.add(arctapCopy.save())
end
end
end
end
batchCommand.commit()
end)
end)
```
例題:
- 全てのスタッシュを削除するマクロを作ってみましょう
- マクロ名にノート数などの情報を追加してみましょう
- リッチテキストは他にも色々な表現ができます!ドキュメントを見て色々試してみてください: https://docs.unity3d.com/2018.3/Documentation/Manual/StyledText.html
- マクロの機能をさらに拡張して、他のBPMにも対応できるようにしてみましょう
実際、マクロをマクロで操作するという発想自体が超強力なので、きっと他にもすごい発想があると思いますよ!(笑)
## 補足説明
- ローカル変数に何かを代入するときは`local`を用いることを忘れないでください。
- Arcade内では、エラーメッセージが読みづらいことがあります。その場合は、エラーログを開いてください。
- マクロを共有する予定がある場合、他者のマクロと名前が被らない様に、独自の文字列をマクロ名の前に付けることをお勧めします。(私の場合、`zero.{category}.{name}`としています)
- `a["b"]`は(luaの機能によって)`a.b`と書くこともできます。例えば、`request.result["arc"]`は`request.result.arc`と書くこともできます。お好みの方法を使いましょう。
# パート3. リファレンス
## 1. グローバル関数とクラス
### 1.1. グローバル関数
関数|説明|返り値
-|-|-
addMacro(string macro, function macroDef)|マクロを登録する|Nil
addMacroWithSort(string macro, string sortKey, function macroDef)|ソートに使用するキーを指定してマクロを登録する|Nil
removeMacro(string macro)|マクロを登録解除する|Nil
log(object content)|contentの内容をログファイルに出力する|Nil
notify(object content)|contentの内容をトースト通知に出力する|Nil
xy(number x, number y)|x、yに指定された値からXY座標を返す|XY
toNumber(string s)|文字列を数値に変換して返す、失敗したら0を返す|number
toBool(string s)|文字列をbool型に変換して返す、失敗したらfalseを返す|bool
### 1.2. Context
静的プロパティ|説明|型
-|-|-
offset|その譜面の現在のAudio Offset(ms)|number
beatlineDensity|Arcadeに設定された現在の小節線密度|number
baseBpm|Arcadeに設定された現在のBase BPM|number
songLength|楽曲の長さ(ms)|number
allArcColors|アークノートの色の文字列リスト("Blue", "Red", "Green"の3つ)|Table (of strings)
currentArcColor|上記のリストにおける現在のデフォルトのアークノートの色の番号|number
allArcTypes|アークノートの移動タイプの文字列リスト("b", "s", ...)|Table (of strings)
currentArcType|現在のデフォルトの移動タイプ|string
currentIsVoidMode|デフォルトでトレースノートを生成するモードならtrue、アークノートを生成するモードならfalse|bool
currentTimingGroup|現在編集中のTimingGroup|number
timingGroupCount|現在の譜面におけるTimingGroupの数|number
language|現在使用されている言語|number
静的メソッド|説明|返り値
-|-|-
beatLengthAt(number timing, number timingGroup = 0)|指定されたtimingGroupにおけるtimingでの1拍の長さ(ms)|number
bpmAt(number timing, number timingGroup = 0)|指定されたtimingGroupにおけるtimingでのBPMの値|number
divisorAt(number timing, number timinggroup = 0)|指定されたtimingGroupにおけるtimingでの小節線間隔|number
### 1.3. Event
静的メソッド|説明|返り値
-|-|-
tap(number timing, number lane, number timingGroup = 0)|タップノートを生成します|LuaTap
hold(number timing, number endTiming, number lane, number timingGroup = 0|ロングノートを生成します|LuaHold
arc(number timing, number startX, number startY, number endTiming, number endX, number endY, bool isVoid=false, number color=0, string type='s', number timingGroup=0)|アークノートを生成します|LuaArc
arc(number timing, XY startXY, number endTiming, XY endXY, bool isVoid=false, number color=0, string type='s', number timingGroup=0)|アークノートを生成します|LuaArc
arctap(number timing, LuaArc arc)|スカイノートを生成します|LuaArcTap
timing(number timing, number bpm, number divisor, number timingGroup=0)|タイミングイベントを生成します|LuaTiming
camera(number timing, number x=0, number y=0, number z=0, number rx=0, number ry=0, number rz=0, string type='reset', number duration=1, number timingGroup=0)|カメライベントを生成します|LuaCamera
createTimingGroup(number bpm, number divisor)|引数のBPMと小節線間隔を0ms時点のタイミングイベントとして使用して、新しくタイミンググループを生成します。返り値は生成されたタイミンググループのIDです|number
query(EventSelectionConstraint constraint)|指定された条件を満たす譜面内の全てのノート/イベントを取得します|Table
getCurrentSelection(EventSelectionConstraint constraint = null)|現在選択されている全てのノートを取得します。条件を指定することで、その条件を満たすもののみを取得することもできます|Table
setSelection(Table notes)|指定されたノートを選択します|nil
### 1.4. XY
プロパティ|説明|型
-|-|-
x|水平方向のx座標(アークノート用の値)|number
y|垂直方向のy座標(アークノート用の値)|number
メソッド|説明|返り値
-|-|-
mirrorX(float axis = 0.5f)|指定されたx座標axisを軸にして左右反転させた座標を返す|XY
mirrorY(float axis = 0.5f)|指定されたy座標axisを軸にして上下反転させた座標を返す|XY
toString()|文字列表現を返す。ログ出力に使用する|string
演算子を用いた処理にも対応
```lua
xy1 = xy(1,2)
xy2 = xy(3,4)
log(xy1 + xy2)
log(xy1 - xy2)
log(xy1 * 3)
log(3 * xy1)
log(xy1 / 2)
```
## 2. 入力メソッド
### 2.1. TrackInput
静的メソッド|説明|返り値
-|-|-
requestTiming(bool showVertical = false, string notification = null)|ユーザーにタイミング値の入力を要求します(タップノートを配置するのと同様)オプションで垂直グリッドとトースト通知を提供します|TrackRequest
requestPosition(int timing, string notification = null)|ユーザーに座標の入力を要求します(アークノートを配置するのと同様)<br>入力時のグリッドは提供されたタイミング値に従って配置されます。 オプションで別のトースト通知を提供します。|TrackRequest
requestLane(string notification = null)|ユーザーにトラックレーンの選択を要求します。オプションで別のトースト通知を提供します。|TrackRequest
### 2.2. EventSelectionInput
静的メソッド|説明|返り値
-|-|-
requestSingleEvent(EventSelectionConstraint constraint)|制約を満たす単一のイベントを選択するようにユーザーに要求します|EventSelectionRequest
requestEvents(EventSelectionConstraint constraint)|制約を満たすイベントを選択するようにユーザーに要求します。イベントは複数選択できます。選択後にEnterキーを押して選択を確定する必要があります。|EventSelectionRequest
### 2.3. DialogInput
静的メソッド|説明|返り値
-|-|-
withTitle(string title)|指定したタイトルでダイアログ入力を作成します|DialogInput
メソッド|説明|返り値
-|-|-
requestInput({DialogField field1, DialogField field2,..})|指定されたフィールドのリストを使用してダイアログを作成します|DialogRequest
## 3. リクエスト結果
### 3.1. TrackRequest
プロパティ|説明|型
-|-|-
result["timing"]|選択されたタイミング|number
result["x"]|選択されたX座標|number
result["y"]|選択されたY座標|number
result["lane"]|選択されたレーン|number
### 3.2. EventSelectionRequest
プロパティ|説明|型
-|-|-
result["tap"]|選択されたタップノートのリスト(タイミング順)|Table (of LuaTap)
result["hold"]|選択されたロングノートのリスト(タイミング順)|Table (of LuaHold)
result["arc"]|選択されたアークノートとトレースノートのリスト(タイミング順)|Table (of LuaArc)
result["arctap"]|選択されたスカイノートのリスト(タイミング順)|Table (of LuaArcTap)
result["timing"]|選択されたタイミングイベントのリスト(タイミング順)|Table (of LuaTiming)
result["camera"]|選択されたカメライベントのリスト(タイミング順)|Table (of LuaCamera)
resultCombined|選択されたイベント全てのリスト(タイミング順)|Table (of LuaChartEvent)
### 3.3. DialogRequest
プロパティ|説明|型
-|-|-
result|フィールドのキーとフィールドに入力された値のテーブル。例えば、`result["key1"]` で`DialogField.create("key1")`により作成したフィールドに入力された値を取得できます|Table
## 4. 入力フィールド
### 4.1. DialogField
プロパティ|説明|型
-|-|-
key|識別用のキー|string
label|フィールドの右側に表示されるラベルテキスト|string
hint|空のテキストボックスのときに表示されるヒントテキスト|string
tooltip|マウスオーバー時に表示されるツールチップのテキスト|string
defaultValue|フィールドのデフォルト値|dynamic
dropdownOptions|重複なしの選択肢(ドロップダウンメニュー用)|Table (of dynamic)
fieldConstraint|フィールドの入力規則(テキストボックス用)|FieldConstraint
静的メソッド|説明|返り値の型
-|-|-
create(string key)|指定されたキーで入力フィールドを作成します|DialogField
メソッド|説明|返り値の型
-|-|-
setLabel(string label)|フィールドのラベルを設定します|DialogField
setTooltip(string tooltip)|フィールドにツールチップを追加します|DialogField
setHint(string hint)|フィールドのヒントを設定します|DialogField
defaultTo(dynamic value)|フィールドのデフォルト値を設定します|DialogField
textField(FieldConstraint constraint)|フィールドを指定された入力規則のテキストボックスに変更します|DialogField
dropdownMenu(dynamic option1, dynamic option2,...)|フィールドを指定された選択肢のドロップダウンメニューに変更します|DialogField
checkbox()|フィールドをチェックボックスに変更します|DialogField
description(string message = nil)|フィールドを表示用テキストに変換します。(入力を受け取るためのものではなく、単に指定されたテキストを表示するためのものです)引数でメッセージを指定しない場合、`label`のテキストが代わりに使用されます|DialogField
## 5. イベント
### 5.0. LuaChartEvent (abstract)
プロパティ|説明|型
-|-|-
timing|イベントのタイミング(ms)|number
timingGroup|イベントの属するタイミンググループID|number
attached|このLuaスクリプト上のイベントが、実際の譜面のイベントと関連付けられているかどうか|bool
メソッド|説明|返り値
-|-|-
copy()|このイベントをコピーします。(返り値のイベントは実際のノートやイベントと関連付けられていない)|LuaChartEvent
save()|このイベントを譜面に作成するコマンドを作成します|LuaChartCommand
delete()|このイベントを譜面から削除するコマンドを作成します|LuaChartCommand
is(string type)|このイベントが指定されたイベント('tap'、'arc'、'floor'、'short'など)かどうかを判定します。|bool
5.1から5.6のクラスは、5.0に示されているすべてのプロパティとメソッドを継承し、呼び出すことができます。
### 5.1. LuaTap (extends LuaChartEvent)
プロパティ|説明|型
-|-|-
lane|レーンの番号|number
### 5.2. LuaHold (extends LuaChartEvent)
プロパティ|説明|型
-|-|-
endTiming|終端のタイミング|number
lane|レーンの番号|number
### 5.3. LuaArc (extends LuaChartEvent)
プロパティ|説明|型
-|-|-
startXY|始点のXY座標|XY
endXY|終点のXY座標|XY
endTiming|終点のタイミング(ms)|number
type|アークノートの形状("b", "s", …)|string
color|アークノートの色|number
isVoid|trueならトレースノート、falseならアークノート|bool
startX|始点のX座標(読み取り専用)|number
startY|始点のY座標(読み取り専用)|number
endX|終点のX座標(読み取り専用)|number
endY|終点のY座標(読み取り専用)|number
メソッド|説明|返り値
-|-|-
positionAt(number timing, bool clamp = true)|指定されたタイミングでのアークノートのXY座標を返します。`clamp`がtrueの場合、タイミングはアークノートの始点から終点までの間に制限されます|XY
xAt(number timing, bool clamp = true)|指定されたタイミングでのアークノートのX座標を計算します。`clamp`がtrueの場合、タイミングはアークノートの始点から終点までの間に制限されます|number
yAt(number timing, bool clamp = true)|指定されたタイミングでのアークノートのY座標を計算します。`clamp`がtrueの場合、タイミングはアークノートの始点から終点までの間に制限されます|number
### 5.4. LuaArcTap (extends LuaChartEvent)
プロパティ|説明|型
-|-|-
arc|スカイノートが属するアークノート|LuaArc
### 5.5. LuaTiming (extends LuaChartEvent)
プロパティ|説明|型
-|-|-
bpm|BPM|number
divisor|小節線の間隔|number
### 5.6. LuaCamera (extends LuaChartEvent)
プロパティ|説明|型
-|-|-
mx|カメラのx移動量|number
my|カメラのy移動量|number
mz|カメラのz移動量|number
rx|カメラのx軸回転量|number
ry|カメラのy軸回転量|number
rz|カメラのz軸回転量|number
duration|カメライベントの継続時間|number
type|カメラの補間タイプ|string
## 6. 譜面編集コマンド
### 6.1. Command
静的メソッド|説明|返り値
-|-|-
create(string name)|指定された名前で空の編集コマンドを作成します|LuaChartCommand
### 6.2. LuaChartComand
メソッド|説明|返り値
-|-|-
add(LuaChartCommand target)|引数に含まれる全てのコマンドを自身のコマンドに追加します|Nil
commit()|自身のコマンドに含まれる全てのコマンドを実行し、譜面に適用します|Nil
## 7. 入力規則・選択規則
### 7.1. FieldConstraint
静的メソッド|説明|返り値
-|-|-
create()|デフォルトのフィールドの入力規則(全ての文字を受け入れ、入力を制限しない)を作成します。|FieldConstraint
メソッド|説明|返り値
-|-|-
any()|全ての文字を受け入れるように設定します|FieldConstraint
float()|小数**のみ**を受け入れるように設定します|FieldConstraint
integer()|整数**のみ**を受け入れるように設定します|FieldConstraint
gEqual(number value)|value以上の数値のみを受け入れるよう設定します|FieldConstraint
lEqual(number value)|value以下の数値のみを受け入れるよう設定します|FieldConstraint
greater(number value)|valueよりも大きい数値のみを受け入れるよう設定します|FieldConstraint
less(number value)|valueよりも小さい数値のみを受け入れるよう設定します|FieldConstraint
custom(function dynamic->bool, string message = "Invalid")|引数の関数を使用した独自の入力規則を設定し、他の制約を無効にします。オプションで入力規則に違反した場合のメッセージを指定できます|FieldConstraint
union(FieldConstraint otherConstraint)|Combines two constraints (similar to an operator OR)<br>指定した規則と自身の規則を"**または**"で組み合わせます。(or演算子と同じように)|FieldConstraint
getConstraintDescription()|自動生成された説明を取得します|string
### 7.2. EventSelectionConstraint
静的メソッド|説明|返り値
-|-|-
create()|デフォルトの選択規則(全てのイベントを受け入れ、入力を制限しない)を作成します。|EventSelectionConstraint
メソッド|説明|返り値
-|-|-
any()|全てのイベント/ノートを受け入れるように設定します|EventSelectionConstraint
tap()|タップノート**のみ**を受け入れるように設定します|EventSelectionConstraint
hold()|ロングノート**のみ**を受け入れるように設定します|EventSelectionConstraint
arc()|アークノートとトレースノート**のみ**を受け入れるように設定します|EventSelectionConstraint
solidArc()|アークノート**のみ**を受け入れるように設定します|EventSelectionConstraint
voidArc()|トレースノート**のみ**を受け入れるように設定します|EventSelectionConstraint
arctap()|スカイノート**のみ**を受け入れるように設定します|EventSelectionConstraint
timing()|タイミングイベント**のみ**を受け入れるように設定します|EventSelectionConstraint
camera()|カメライベント**のみ**を受け入れるように設定します|EventSelectionConstraint
floor()|タップノートとロングノート**のみ**を受け入れるように設定します|EventSelectionConstraint
sky()|アークノートと、トレースノートと、スカイノート**のみ**を受け入れるように設定します|EventSelectionConstraint
short()|タップノートとスカイノート**のみ**を受け入れるように設定します|EventSelectionConstraint
long()|ロングノートと、アークノートと、トレースノート**のみ**を受け入れるように設定します|EventSelectionConstraint
judgeable()|タップノートと、ロングノートと、アークノートと、スカイノート**のみ**を受け入れるように設定します|EventSelectionConstraint
fromTiming(number timing)|指定されたタイミング以降(引数のtimingを含む)のイベント/ノートに制限します|EventSelectionConstraint
toTiming(number timing)|指定されたタイミング以前(引数のtimingを含む)のイベント/ノートに制限します|EventSelectionConstraint
ofTimingGroup(number group)|指定されたタイミンググループ上のイベント/ノートに制限します|EventSelectionConstraint
custom(function dynamic->bool, string message = "Invalid")|引数の関数を使用した独自の選択規則を設定し、他の制約を無効にします。オプションで入力規則に違反した場合のメッセージを指定できます|EventSelectionConstraint
union(EventSelectionConstraint otherConstraint)|指定した規則と自身の規則を"**または**"で組み合わせます。(or演算子と同じように)|EventSelectionConstraint
getConstraintDescription()|自動生成された説明を取得します|string
---
# クレジット
(敬称略)
**原著**
Tempestissiman
**翻訳**
Yut0124
mitu
大団円ちゃん
rassvet_ii
## 編集ログ
> **[Introduction](#Introduction)**:Yut
> **[Getting started](#Getting-started)**:Yut
> **[Part 1. Using macros](#Part-1.-Using-macros)**:Yut
> **[Part 2. Creating macros/Example 1. Hello World](#Example-1-Hello-world)**:Yut
> **[Part 2. Creating macros/Example 2. Creating Notes](#Example-2-Creating-notes)**:Yut
> **[Part 2. Creating macros/Example 3. Self destruct button](#Example-3-Self-destruct-button)**:mitu 終わった 最後のほう結構雑
>
> **[Part 2. Creating macros/Example 4. Create notes, but somewhere else!](#Example-4-Create-notes-but-somewhere-else)**:大団円ちゃん 完了したが最後が微妙
> **[Example 4.5 Self destruction button, but a bit less destructive](#Example-45-Self-destruction-button-but-a-bit-less-destructive)**: Ras II 完了。 // なかったので追加しました
> **[Example 6. Advanced macro creation](#Example-6-Advanced-macro-creation)**:Ras II 作業中/Yut 加勢
> **[Part 2. Creating macros/Example 5. amygdata](#Example-5.-amygdata)**:mitu←終わったけれどもクオリティがやばそうなので査読してくれるとありがたいです
> **[Part 3. Reference/1. Global functions and classes](#1.-Global-functions-and-classes)**:Yut
> **[Part 3. Reference/2. Input methods](#2.-Input-methods)**:大団円ちゃん 完了
> **[Part 3. Reference/3. Request Types](#3.-Request-Types)**: Ras II 完了。
> **[Part 3. Reference/4. DialogField](#4.-DialogField)**: Ras II 完了。雑ぅ
> **[Part 3. Reference/5. Events](#5.-Events)**: Ras II 完了。ちょっと雑かも
> **[Part 3. Reference/6. Command classes](#6.-Command-classes)**: Ras II 完了。査読待ち、用語に関するアドバイス待ち
> **[Part 3. Reference/7. Constraint classes](#7.-Constraint-classes)**: Ras II 完了。査読待ち、用語に関するアドバイス待ち
> ### ほんやくノート
> 用語集とも言います。あちこちで使いそうな言葉をほんやくしたときはここにメモします。
>
> **Field Constraint:** 入力規則
> **Event Selection Constraint:** 選択規則
> **amygdata arc:** (amygdataのような)細切れアーク
>
> **note’s description:** ノート情報? ノート記述子は(個人的にはしっくりくるけど)堅苦しい? でもノート説明はおかしい。 ノート表現?
> ### 工事のおしらせ
> 反映済み:[`64aacb4`](https://github.com/Tempestissiman/ArcadeMacro/commit/64aacb40ce56622c6723d43514122f09417c2fb6)まで 06/12 Ras+Yut
> - [x] [`8bc7943`](https://github.com/Tempestissiman/ArcadeMacro/commit/8bc794399a800c721a4e5c592a11c12228b71587)の内容を~~反映中です~~反映しました
> - [x] リファレンスのテーブルのヘッダーを(静的)プロパティ/メソッド|説明|型/返り値に統一 // 完了
> - [x] [`a706da7`](https://github.com/Tempestissiman/ArcadeMacro/commit/a706da7e83852cfa40edf1593e868ef90c3da301)の内容を反映
> - [x] [`5101ac7`](https://github.com/Tempestissiman/ArcadeMacro/commit/5101ac7437d281a47d6579e7e6cbac600c93b072)コピー・翻訳
> - [x] [`64aacb4`](https://github.com/Tempestissiman/ArcadeMacro/commit/64aacb40ce56622c6723d43514122f09417c2fb6)コピー・翻訳