- 1.はじめに
- 2.メソッド一覧
- 3.主要な引数一覧
- 4.C#スクリプトの使い方・注意点
- 5.C#スクリプトでNXマクロ文法を使うには
- 6.LINENotifyの代わりにWebHookで通知しよう
- 7.おわりに
1.はじめに
この記事は Pokémon Past Generation Advent Calendar 2023 の337日目の記事です。SwitchやGCの自動化環境は日々進歩していますが、皆さんが自動化に使用するツールはPokeConかNX Macro Controllerが大半でしょうか。
NXはマクロ文法が単純で、誰でも簡単に扱えるというメリットがありますが、PokeConに比べて自由度が低いというイメージを持たれる方もいるかもしれません。(↓ NXのマクロ文法は夜綱さんの記事で紹介されてます。)
ただし、これはあくまでNXマクロ文法を使用した時の話で、CallCsxコマンドを使って、C#スクリプトを呼び出すことによりグッと自由度があがります。
C#はPythonよりは少しだけ複雑かもしれませんが、PokeConと同様にプログラム言語を使ってスクリプトを書けるようになるため、複雑な処理にも対応しやすく、OCRやPokemonPRNGなどの外部ライブラリを使うこともできます。ダイアログボックスを表示させたり、exeファイルで出力したjsonを参照するなんてこともできます。
C#スクリプトでボタン押下や画像認識など、NXマクロ文法で使用しているコマンドを利用するためには「NxInterface.Nxcommand」をインポートする必要があります。
NxInterface.Nxcommandクラスで定義しているメソッドはNXマクロ文法とは名称や使い方が違うものもありますので、アドカレの場をお借りして、紹介させていただきます。加えて、メソッドに使用する引数や、C#スクリプトを使う際の注意点なども紹介します。
2.メソッド一覧
ボタン系
Press
- Press(Button button, double duration = 0.1, double wait = 0.1)
Press(Direction direction, double duration = 0.1, double wait = 0.1)
Press(Stick stick, int x, int y, double duration = 0.1, double wait = 0.1)
Press(HAT hat, double duration = 0.1, double wait = 0.1) - ボタン押下を行うメソッドです。押下する時間や、押下後の待機時間も指定できます。
PressRepeat
- PressRepeat(Button button, int repeat, double duration = 0.1, double interval = 0.1, double wait = 0.1)
- ボタンの繰り返し押下を行うメソッドです。for文などを使わずスマートに連打したい人向けです。
Hold
- Hold(Button button, double wait = 0.1)
Hold(Direction direction, double wait = 0.1)
Hold(Stick stick, int x, int y, double wait = 0.1)
Hold(HAT hat, double wait = 0.1) - 指定した方向や、ボタンを押し続けるメソッドです。
HoldEnd
- HoldEnd(params Button button)
HoldEnd(Direction direction)
HoldEnd(Stick stick)
HoldEnd(Stick stick, int x, int y)
HoldEnd(HAT hat) - 指定した方向や、ボタンの押下を解除するメソッドです。
画像認識系
IsContainTemplate
- IsContainTemplate(string templatePath, double threshold = 0.8, bool useGray = true)
IsContainTemplate(Image template, double threshold = 0.8, bool useGray = true)
IsContainTemplate(Image capture, string templatePath, double threshold = 0.8, bool useGray = true) - テンプレート画像がキャプチャ内に含まれているか判定するメソッドです。判定が通った場合は()内の処理を実行します。
IsContainTemplateMax
- IsContainTemplateMax(string templatePaths, bool useGray = true)
IsContainTemplateMax(Image templates, bool useGray = true)
IsContainTemplateMax(Image capture, string templatePaths, bool useGray = true)
IsContainTemplateMax(Image capture, Image templates, bool useGray = true) - 複数のテンプレート画像から最も一致度が高いものを判定し、判定が通った場合は()内の処理を実行するメソッドです。
GetCapture
- GetCapture()
- 現在の画面をキャプチャして取得するメソッドです。
ToGrayScale
- ToGrayScale(this Image src)
- 画像をグレースケールに変換するメソッドです。GetCaptureやBitmapで取得した画像をグレースケールにして、画像認識する際に使えます。
通知系
GetLINENotifyToken
- GetLineNotifyToken()
- LINE通知用のトークンを取得するメソッドです。NXのオプションで設定したトークンを参照できるので、中々に便利です。
SendLineNotify
- SendLineNotify(string message, Image image = null)
- LINE通知を送信するメソッドです。GetLineNotifyTokenと合わせて使います。画像も添付可能です。
SendWindowsNotify
- SendWindowsNotify(string text)
- Windows通知を送信するメソッドです。LINENotifyで事足りるので、私は使ったことはありません。
その他
Wait
- Wait(double wait)
- 指定時間待機を行うメソッドです。
SaveCapture
- SaveCapture(int x, int y, int width, int height)
SaveCapture(string filename, int x, int y, int width, int height) - 指定範囲のキャプチャ画像をcsxと同ディレクトリのCapturesフォルダに保存するメソッドです。名前を指定することもできるので、キャプチャした画像を使って、画像認識にするなど、テクニカルなこともできます。
Exit
- Exit()
- プログラムを終了させるメソッドです。NXマクロ文法のStopと同じ使い方ができます。スクリプトではなく、プログラム自体を強引に終了させます。
GetRumble
- GetRumble()
- コントローラーの振動を検知するメソッドです。たぶんSwitch専用ですので、使ったことがありません。
SendKeyboardText
- SendKeyboardText(string text)
- Switchでテキストのキーボード入力を行うメソッドです。非常に便利な機能ですが、使ったことはありません。
SendAmiibo
- SendAmiibo(string filename)
- ファイルパスで指定したAmiiboファイルを読み込むメソッドです。良くわかりません!
ConnectedBluetooth
- ConnectedBluetooth()
- Bluetooth接続するメソッド?のようです。これも使ったことがない…。
3.主要な引数一覧
文字列系
string text
キーボード入力や通知で使うテキストデータを指定します。SendLineNotifyやSendKeyboardTextのようなメソッドで用いられます。
string filename
画像やAmiiboデータのファイル名やファイルパスを指定します。SaveCaptureではキャプチャした画像の保存先のパスとして、SendAmiiboではAmiiboファイルの指定に使います。
string templatePath
テンプレート画像に使用するファイルパスを指定します。画像認識メソッド(IsContainTemplate等)で、キャプチャ画像と比較するテンプレート画像の場所を参照するために使用されます。
string templatePaths
複数のテンプレート画像のファイルパスを格納した配列です。IsContainTemplateMaxで複数のテンプレートから最も一致度の高いものを判定する場合に使います。
画像認識系
Image capture
キャプチャした画面の画像データです。画像認識メソッド(IsContainTemplate等)では、テンプレート画像と比較する対象のキャプチャ画像として使われます。
Image template
画像認識で比較に用いるテンプレート画像です。IsContainTemplateでは、キャプチャ画像に対してテンプレートが含まれているかを判定します。
Image templates
複数のテンプレート画像の配列です。キャプチャ画像と複数のテンプレートを比較し、最も一致度が高いものを判定する際に使います。
double threshold
画像認識の閾値を指定します。値が1.00に近いほど厳密な一致を要求され、デフォルトでは0.80に設定されています。
bool useGray
グレースケールでの画像比較を行うかを指定します。trueの場合、色を無視して比較を行うため、色の違いが影響しにくくなります。
ボタン系
Button button
A、B、X、Yなどの押すボタンを指定します。GCではPLUSがStart、Homeボタンがリセットピン or サーボに当たります。
Direction direction
操作する方向を指定します。スティックや方向ボタンの操作メソッドで、上下左右の向きを指定できます。GCではUPとDOWNが逆になっています。
Stick stick
LEFTかRIGHTで、Switchで操作するスティックを指定します。HoldやPressのメソッドで、左右のスティックを指定する際に用います。
HAT hat
Switchの十字キーに当たるようですが、バグでうまく動作しないようです。UPではなくTOP、DOWNではなくBTMになるので注意。
int repeat
PressRepeatメソッドで、ボタン押下回数を指定する際に使われます。
double interval
PressRepeatメソッドで、ボタン押下間隔を指定する際に使われます
params Button button
複数のボタンを引数として渡すために使われます。HoldEnd(params Button[] button)では、複数ボタンの押下解除が可能です。
時間系
double duration
ボタンやスティックの操作を続ける時間を秒単位で指定します。Press(Button button, double duration)のように押下時間を指定するために使います。
double wait
操作後に待機する時間を秒単位で指定します。
座標系
int x, int y, int width, int height
スティックの座標やキャプチャ範囲を指定します。Press(Stick stick, int x, int y)ではスティックの位置、SaveCapture(int x, int y, int width, int height)ではキャプチャ範囲を指定します。
4.C#スクリプトの使い方・注意点
NX⇔C#スクリプト間で引数を渡すには
NXでVarで宣言した変数をC#スクリプトに値渡ししたり、渡した変数をC#スクリプト内での変更内容をNXに反映することができます。
NXでCallCsx(R“[FilePath]”, [Arg1, Arg2, Arg3...])と記述することで、Argに指定した変数をC#スクリプトに渡せます。C#スクリプトではargsで受け取り、argsで渡すことができます。
注意点としてはNXで変数を受け取る場合、あらかじめマクロ内で宣言しておく必要があるということ、CallCsx(R“[FilePath]”, [Ref:Arg1, Arg2, Arg3...])というように、受け取る変数の頭に「Ref:」と記述する必要があることです。若干、難しいですが私が作成したID調整プログラム等を見れば理解できると思います。
C#スクリプトでログを出力するには
NXマクロ文法でいうPrintに当たるログ出力用のメソッドがないのでは?…と思った方もいるかもしれません。Console.Writeメソッドでフツーに出力できますのでご安心を。
C#スクリプトの修正が反映されない
マクロ側と違って、上書き保存する必要があります。再起動は不要です。
エラーメッセージを確認するには
C#スクリプトにエラーがあった場合はログに「System.NullReferenceException: オブジェクト参照がオブジェクト インスタンスに設定されていません。」と表示されるだけで、エラーの原因が特定できません。
このままではどう修正すればいいのか分からないので、csxのコードをcsファイルにコピペして、Visual Studioでデバッグすることをオススメします。Visual Studioはスクリプトに不備があればエラーが発生している箇所を教えてくれます。(もっといい方法あるかもですが。)
NxInterface.Nxcommandを含む、各ライブラリを参照するのは忘れないようにして下さい。
C#スクリプトを呼び続けると重くなる
NXではCallCsxでC#スクリプトを何度も呼び出すと、プログラムが重くなり、不具合が発生する場合があります。そのため、1ループごとにC#スクリプトを呼び出すような処理には向いておらず、C#スクリプト1発書くか、何度も呼び出さない処理にする必要があります。原因は特定できていませんが、画像認識方式をDirectShowではなくOpenCVにすると重くならないという噂があります。
5.C#スクリプトでNXマクロ文法を使うには
NXマクロ文法では操作記録がめちゃくちゃ便利です。コントローラーで操作したコマンドを自動で書いてくれます。ただし、こちらはNXマクロ文法でしか出力できません。
例えば、NXマクロ文法は
Press(A, 0.10, 0.10)
Press(UP_L, 0.10, 0.10)
のようにA押下や移動を書きます。一方でC#スクリプトでは
Press(Button.A, 0.10, 0.10);
Press(Direction.DOWN, 0.10, 0.10);
のように書きます。ご覧の通り、コピペができない上にゲームキューブでは上下が逆転しています。
そこで、NXマクロ文法のままコピペで使えるようにするために、NX側の記述に合わせた定数定義と、ラッパー関数 Press() を用意します。これにより、操作記録で得られる Press(A, 0.10, 0.10) のようなNXマクロ形式を、そのままC#スクリプト内でも使えるようになり、手動変換の手間がなくなります。
なお、セミコロンは追加が必要ですので、末尾にセミコロンを追加するだけのプログラムを用意するのも手です。
コードを見る
using Button = NxInterface.NxCommand.Button;
// const string で移動を定数定義
const string UP_L = "UP_L";
const string DOWN_L = "DOWN_L";
const string RIGHT_L = "RIGHT_L";
const string LEFT_L = "LEFT_L";
const string UPLEFT_L = "UPLEFT_L";
const string UPRIGHT_L = "UPRIGHT_L";
const string DOWNLEFT_L = "DOWNLEFT_L";
const string DOWNRIGHT_L = "DOWNRIGHT_L";
const string A = "A";
const string B = "B";
const string X = "X";
const string Y = "Y";
const string START = "START";
// NXマクロ文法をそのまま使うためのローカル関数
void Press(string direction, double duration = 0.1, double wait = 0)
{
switch (direction)
{
case "UP_L":
NxInterface.NxCommand.Press(Direction.DOWN, duration, wait);
break;
case "DOWN_L":
NxInterface.NxCommand.Press(Direction.UP, duration, wait);
break;
case "RIGHT_L":
NxInterface.NxCommand.Press(Direction.RIGHT, duration, wait);
break;
case "LEFT_L":
NxInterface.NxCommand.Press(Direction.LEFT, duration, wait);
break;
case "UPLEFT_L":
NxInterface.NxCommand.Press(Direction.DOWN_LEFT, duration, wait);
break;
case "UPRIGHT_L":
NxInterface.NxCommand.Press(Direction.DOWN_RIGHT, duration, wait);
break;
case "DOWNLEFT_L":
NxInterface.NxCommand.Press(Direction.UP_LEFT, duration, wait);
break;
case "DOWNRIGHT_L":
NxInterface.NxCommand.Press(Direction.UP_RIGHT, duration, wait);
break;
case "A":
NxInterface.NxCommand.Press(Button.A, duration, wait);
break;
case "B":
NxInterface.NxCommand.Press(Button.B, duration, wait);
break;
case "X":
NxInterface.NxCommand.Press(Button.X, duration, wait);
break;
case "Y":
NxInterface.NxCommand.Press(Button.Y, duration, wait);
break;
case "START":
NxInterface.NxCommand.Press(Button.PLUS, duration, wait);
break;
default:
Console.WriteLine($"なんぞこれ");
break;
}
}
6.LINENotifyの代わりにWebHookで通知しよう
NXマクロ文法ではLINENotifyコマンドが実装されており、LINE通知をすることができました。が、2025年3月31日を持ってサービスが終了してしまいました。
↓ サービス終了のお知らせ
なので、NXのオプションからLINENotifyTokenを設定しても無意味ですが、C#スクリプトのGetLINENotifyTokenメソッドを使えば、オプションで設定したToken自体は文字列として取得できます。これで何ができるかというと、LINENotifyTokenの代わりにWebHookのURLを取得することで、discordで通知が可能になるのです。

プログラムは以下に置いておきます。
下記のように変数に送りたいメッセージを代入して、メッセージのみ送りたい場合は「Discordに通知.csx」をRefでmessageを与えて呼び出し、画像の場合は「Discordに画像で通知.csx」を呼び出すだけで済みます。
Var message = "検証だよ"
message = "メッセージのみ送信"
CallCsx(R"Discordに通知.csx",Ref:message)
message = "メッセージと画像を送信"
CallCsx(R"Discordに画像で通知.csx", Ref:message)
注意点として、WebHookのURLをオプションで設定した状態で、NXマクロ文法のLINENotifyコマンドを実行すると、プログラムが強制終了するので、既存のプログラムを使う場合は注意しましょう。
ここまで書いておいてなんですが、Callcsxを使わずともNX Macro Controller直下のdllを下記ドライブのものに差し替えるだけでもOKです。LINENotifyまたはLINENotifyWithImageコマンドを使って、WebHookで通知できます。

7.おわりに
PokeConの有識者が多いのに対して、NXでC#スクリプトを使ってプログラムを書く人間がほとんど観測できず、非常に心細いので、同士が増えると泣いて喜びます。
プログラミング言語は難しそうなイメージがあるかもしれませんが、ゲームの自動化を組む程度であればそこまで敷居は高くないですので、一緒に自動化環境を構築しましょう。(私も半年前はC#の知識ゼロでしたし。)