ポケモンにおける孵化厳選のコード第2弾です。基本的には第1弾のコードが完成されているので、そちらを使うと良いでしょう。
マイコンを使ったポケモン剣盾の自動孵化を最適化したコードを作ってみました。 孵化厳選はレイドや化石ポケモンの自動化とは違い、何千、何万という繰り返しを行うからこそ、少しでも効率的に回したくコンマ単位でかなりこだわったコードに仕上げまし[…]
しかし、第1弾のコードでは少し不満のある箇所があったかと思います。
- 一部のポケモンで、タマゴが孵化しきれていないことがある
- 孵化サイクルの短いポケモンでも走る距離が長くなってしまう
今回はこの2点にフォーカスを当てて、ピンポイントで解決するコードを作成しました。
孵化歩数の少ないポケモンで「色違いを狙う」といったケースで活用していけるプログラムになっています。
この記事をご覧になる前に
マイコンをまだ導入していない方は、以下の記事を参考に導入してみてください。
マイコンと呼ばれるものをご存知でしょうか? Switchに接続するだけで様々な作業を "自動" で行ってくれるというものです。 導入すれば作業が楽になるだけでなく、寝てる間に色々稼ぐこともできちゃう便利なアイテムなわけですね! […]
※2021年2月11日追記:当ブログで使用するライブラリが「NintendoSwitchControlLibrary」へと変わりました。旧ライブラリのコードも残しておきますが、基本的には新しいライブラリをダウンロードして新しいコードを使ってください。
A library for microcontrollers that uses Arduino to automate…
ダウンロードして解凍したら、『Arduino』フォルダの中にある『libraries』フォルダの中にコピーすればOKです。(展開を終えたら展開元のzipファイルは削除してしまって構いません。)
ソースコード
実際に書いたコードはこちらになります。
- 旧ライブラリ(NintendoSwitchControll)を使用している方はこちらをクリック
-
/** * 育て屋から卵を回収→孵化→ボックスに預けるを繰り返すスケッチ * ボックスに空きがある限り、ポケモンを孵化し続ける * * 初期条件は以下の通り * 1.ハシノマはらっぱにいること * 2.自転車に乗っていること * 3.手持ちが1体のみのこと * 4.Xボタンを押したときに「タウンマップ」が左上、「ポケモン」がその右にあること * 5.ボックスが空のこと * 6.オフライン状態であること * 7.無線のコントローラーが接続されていないこと * 8.「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと */ // ライブラリを読み込むためのコード #include <auto_command_util.h> // 孵化サイクルを設定する const int EGG_CYCLE = 25; // 孵化するまでに自転車で走り回る時間 const int TIME_TO_HATCHING_SEC = EGG_CYCLE * 32/10 + 5; // 空飛ぶタクシーでハシノマはらっぱに移動する関数 void moveToInitialPlayerPosition(){ pushButton(Button::A, 2000); pushButton(Button::A, 450, 2); delay(2200); // 天候によって読み込み時間がやや異なる(最も重かった砂嵐でも1900で安定していたが、柱の本数や服装などの環境による差異がある可能性も考慮して少し余裕を持たせた) } // 初期位置から育て屋さんに移動しタマゴを受け取る関数 void getEggFromBreeder(){ // 初期位置(ハシノマはらっぱ)から育て屋さんのところまで移動 pushButton(Button::PLUS, 600); tiltJoystick(0, 0, 100, 0, 2000); tiltJoystick(30, -100, 0, 0, 800); pushButton(Button::PLUS, 450); // 育て屋さんから卵をもらう pushButton(Button::A, 450, 3); delay(750); pushButton(Button::B, 450, 10); delay(50); } // 初期位置(ハシノマはらっぱ)からぐるぐる走り回る関数 void runAround(int run_time_sec){ // delayの秒数がintの最大値を越えないように30秒ごとに実行する for(int i=0; i<run_time_sec/30; i++){ tiltJoystick(100, 100, -100, -100, 30000); } tiltJoystick(100, 100, -100, -100, (run_time_sec%30)*1000); } // タマゴが孵化するのを待つ関数 void waitEggHatching(){ pushButton(Button::B, 450, 38); // 余裕があるように思えるが、色違いのエフェクトを考慮するとこれ以上は厳しい } // 孵化した手持ちのポケモンをボックスに預ける関数 // box_line : 何列目にポケモンを預けるか void sendHatchedPokemonToBox(int box_line){ // ボックスを開く pushButton(Button::X, 500); pushHatButton(Hat::RIGHT, 25); pushButton(Button::A, 1250); pushButton(Button::R, 1500); // 手持ちの孵化したポケモンを範囲選択 pushHatButton(Hat::LEFT, 25); pushHatButton(Hat::DOWN, 25); pushButton(Button::Y, 25); pushButton(Button::Y, 25); pushButton(Button::A, 25); pushHatButtonContinuous(Hat::DOWN, 600); pushButton(Button::A, 25); // ボックスに移動させる pushHatButton(Hat::RIGHT, 100, box_line+1); pushHatButton(Hat::UP, 25); pushButton(Button::A, 25); // ボックスがいっぱいになったら、次のボックスに移動させる if(box_line==5){ pushHatButton(Hat::UP, 25); pushHatButton(Hat::RIGHT, 25); } // ボックスを閉じる pushButton(Button::B, 25); // ボックスが空でなかった場合でも、ボックスを閉じてループを実行し続けさせるのに必要な記述 pushButton(Button::B, 1500); pushButton(Button::B, 1250); // メニュー画面のカーソルをタウンマップに戻す pushHatButton(Hat::LEFT, 25); } // 実際にループ内で呼び出す関数 void receiveAndHatchEggs(int box_line){ // 手持ちが1体の状態から、卵受け取り→孵化を繰り返していく for(int egg_num=0; egg_num<5; egg_num++){ moveToInitialPlayerPosition(); getEggFromBreeder(); pushButton(Button::X, 500); moveToInitialPlayerPosition(); // 野生ポケモンとのエンカウントを避けるため初期位置から少し移動する tiltJoystick(100, 0, 0, 0, 500); runAround(TIME_TO_HATCHING_SEC); waitEggHatching(); // 手持ちがいっぱいになったときの処理 if(egg_num==4){ // ボックスに預ける処理を呼び出す sendHatchedPokemonToBox(box_line); // 手持ちがいっぱいでない場合は、メニューを開いてからループに戻る } else { pushButton(Button::X, 500); } } } // マイコンのセット時に1度だけ行われる処理 void setup(){ // Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく pushButton(Button::B, 500, 5); // マイコンを認識したら、メニューの左上にカーソルを持っていく pushButton(Button::X, 600); pushHatButtonContinuous(Hat::LEFT_UP, 750); // 初回は処理が少しだけ重い?ので、moveToInitialPlayerPosition を呼び出さずに余裕をもたせる形にした pushButton(Button::A, 2200); pushButton(Button::A, 450, 2); delay(2200); // 初めのタマゴが出現するまで走り回る tiltJoystick(100, 0, 0, 0, 500); runAround(25); // メニューを開く動作をループに含めてしまうと、毎回メニューを閉じないといけなくなってしまうため、ループから外すことにした pushButton(Button::X, 500); } // ここに記述した内容がループされ続ける void loop(){ for(int box_line=0; box_line<6; box_line++){ receiveAndHatchEggs(box_line); } }
/**
* 育て屋から卵を回収→孵化→ボックスに預けるを繰り返すスケッチ
* ボックスに空きがある限り、ポケモンを孵化し続ける
*
* 初期条件は以下の通り
* 1.ハシノマはらっぱにいること
* 2.自転車に乗っていること
* 3.手持ちが1体のみのこと
* 4.Xボタンを押したときに「タウンマップ」が左上、「ポケモン」がその右にあること
* 5.ボックスが空のこと
* 6.オフライン状態であること
* 7.無線のコントローラーが接続されていないこと
* 8.「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと
* 9.ちょいらくモードが「しない」であること
* 10.まるいおまもりを所持していること
*
* コード25行目の以下の箇所に孵化するポケモンの孵化サイクルを入れること
* const int EGG_CYCLE = 25;
*/
// ライブラリを読み込むためのコード
#include <NintendoSwitchControlLibrary.h>
// 孵化サイクルを設定する
const int EGG_CYCLE = 25;
// 孵化するまでに自転車で走り回る時間
const int TIME_TO_HATCHING_SEC = EGG_CYCLE * 32 / 10 + 5;
// 空飛ぶタクシーでハシノマはらっぱに移動する関数
void moveToInitialPlayerPosition() {
pushButton(Button::A, 2000);
pushButton(Button::A, 450, 2);
delay(2200); // 天候によって読み込み時間がやや異なる(最も重かった砂嵐でも1900で安定していたが、柱の本数や服装などの環境による差異がある可能性も考慮して少し余裕を持たせた)
}
// 初期位置から育て屋さんに移動しタマゴを受け取る関数
void getEggFromBreeder() {
// 初期位置(ハシノマはらっぱ)から育て屋さんのところまで移動
pushButton(Button::PLUS, 600);
tiltRightStick(Stick::MAX, Stick::NEUTRAL, 2000);
tiltLeftStick(166, Stick::MIN, 800);
pushButton(Button::PLUS, 450);
// 育て屋さんから卵をもらう
pushButton(Button::A, 450, 3);
delay(750);
pushButton(Button::B, 450, 10);
delay(50);
}
// 初期位置(ハシノマはらっぱ)からぐるぐる走り回る関数
void runAround(int run_time_sec) {
// delayの秒数がintの最大値を越えないように30秒ごとに実行する
for (int i = 0; i < run_time_sec / 30; i++) {
tiltLeftAndRightStick(Stick::MAX, Stick::MAX, Stick::MIN, Stick::MIN, 30000);
}
tiltLeftAndRightStick(Stick::MAX, Stick::MAX, Stick::MIN, Stick::MIN, (run_time_sec % 30) * 1000);
}
// タマゴが孵化するのを待つ関数
void waitEggHatching() {
pushButton(Button::B, 450, 38); // 余裕があるように思えるが、色違いのエフェクトを考慮するとこれ以上は厳しい
}
// 孵化した手持ちのポケモンをボックスに預ける関数
// box_line : 何列目にポケモンを預けるか
void sendHatchedPokemonToBox(int box_line) {
// ボックスを開く
pushButton(Button::X, 500);
pushHat(Hat::RIGHT, 25);
pushButton(Button::A, 1250);
pushButton(Button::R, 1500);
// 手持ちの孵化したポケモンを範囲選択
pushHat(Hat::LEFT, 25);
pushHat(Hat::DOWN, 25);
pushButton(Button::Y, 25);
pushButton(Button::Y, 25);
pushButton(Button::A, 25);
holdHat(Hat::DOWN, 600);
pushButton(Button::A, 25);
// ボックスに移動させる
pushHat(Hat::RIGHT, 100, box_line + 1);
pushHat(Hat::UP, 25);
pushButton(Button::A, 25);
// ボックスがいっぱいになったら、次のボックスに移動させる
if (box_line == 5) {
pushHat(Hat::UP, 25);
pushHat(Hat::RIGHT, 25);
}
// ボックスを閉じる
pushButton(Button::B, 25); // ボックスが空でなかった場合でも、ボックスを閉じてループを実行し続けさせるのに必要な記述
pushButton(Button::B, 1500);
pushButton(Button::B, 1250);
// メニュー画面のカーソルをタウンマップに戻す
pushHat(Hat::LEFT, 25);
}
// 実際にループ内で呼び出す関数
void receiveAndHatchEggs(int box_line) {
// 手持ちが1体の状態から、卵受け取り→孵化を繰り返していく
for (int egg_num = 0; egg_num < 5; egg_num++) {
moveToInitialPlayerPosition();
getEggFromBreeder();
pushButton(Button::X, 500);
moveToInitialPlayerPosition();
// 野生ポケモンとのエンカウントを避けるため初期位置から少し移動する
tiltLeftStick(Stick::MAX, Stick::NEUTRAL, 500);
runAround(TIME_TO_HATCHING_SEC);
waitEggHatching();
// 手持ちがいっぱいになったときの処理
if (egg_num == 4) {
// ボックスに預ける処理を呼び出す
sendHatchedPokemonToBox(box_line);
// 手持ちがいっぱいでない場合は、メニューを開いてからループに戻る
} else {
pushButton(Button::X, 500);
}
}
}
// マイコンのセット時に1度だけ行われる処理
void setup() {
// Switchがマイコンを認識するまでは信号を受け付けないため、適当な処理をさせておく
pushButton(Button::B, 500, 5);
// マイコンを認識したら、メニューの左上にカーソルを持っていく
pushButton(Button::X, 600);
holdHat(Hat::UP_LEFT, 750);
// 空飛ぶを使うことで、位置情報をリセットする
moveToInitialPlayerPosition();
// 初めのタマゴが出現するまで走り回る
tiltLeftStick(Stick::MAX, Stick::NEUTRAL, 500);
runAround(25);
// メニューを開く動作をループに含めてしまうと、毎回メニューを閉じないといけなくなってしまうため、ループから外すことにした
pushButton(Button::X, 500);
}
// ここに記述した内容がループされ続ける
void loop() {
for (int box_line = 0; box_line < 6; box_line++) {
receiveAndHatchEggs(box_line);
}
}
コードの使い方
コードを使うにあたって確認して欲しいことが2点ほどあります。
設定の確認
マイコンを繋げる前に、以下の状態になっていることを確認してください。
2022年5月12日追記:必要な設定を一部追加しました。
- ハシノマはらっぱにいること
- 自転車に乗っていること
- 手持ちが1体のみのこと
- Xボタンを押したときに「タウンマップ」が左上、「ポケモン」がその右にあること
- ボックスが空のこと
- オフライン状態であること(機内モード推奨)
- 無線のコントローラー(プロコンなど)が接続されていないこと
- 「設定」から「話の速さ」を「速い」に、「手持ち/ボックス」を「自動で送る」に、「ニックネーム登録」を「しない」にしておくこと
- ちょいらくモードが「しない」であること
- まるいおまもりを所持していること
孵化サイクルを指定する
コードの25行目に注目してください。
const int EGG_CYCLE = 25;
となっている箇所が見つけられましたか?
実は、この『25』の部分に『孵化サイクル』と呼ばれる値を入れることにより、最適な歩数でループを回していくことが可能になります。
例えば、孵化サイクル『15』のポケモンの場合は以下のように編集します。
const int EGG_CYCLE = 15;
ちなみに、孵化サイクルというのはポケモンごとに決められている「タマゴが孵化するまでの歩数」の目安のことです。コイキングはすぐに孵化するのに対し、ドラメシヤはなかなか孵化しなかったりしますよね?
まさにそれは『孵化サイクル』の差によるものなのです!
そんな孵化サイクルですが、種族値などと同様に隠れパラメーターなので、ゲーム内で調べるのは難しいです。
ポケモンの情報をまとめているサイトがあるので、そちらでチェックしていきましょう!
孵化サイクルの調べ方
孵化サイクルは、以下のサイトで一覧を確認することができます。
孵化させるポケモンが明確な場合には、ポケ徹さんの個別ページでも確認できるので、そちらも合わせて活用してみてください。
ポケモン・ポケットモンスターの攻略サイト(21年運営)。スカーレット・バイオレット・ポケモンSV(DLC碧の仮面・藍の円…
コードの書き換えが面倒な方へ
今回のコードを活用するためには、各ポケモンの孵化サイクルを調べて、そのたびにコードを上書きしていく必要があります。
ですが、毎回のようにマイコンをPCにつなげ、コードを書き換えていくのは面倒ですよね…
そんな方は、以下のページにて、自動孵化の汎用的なコードを紹介しているのでぜひ確認してみてください。孵化サイクル25のポケモンはやや怪しいものの、ほぼ全てのポケモンを効率よく孵化させることのできるコードとなっています。
マイコンを使ったポケモン剣盾の自動孵化を最適化したコードを作ってみました。 孵化厳選はレイドや化石ポケモンの自動化とは違い、何千、何万という繰り返しを行うからこそ、少しでも効率的に回したくコンマ単位でかなりこだわったコードに仕上げまし[…]
上の記事のコードは対戦用のポケモン、今回の記事のコードは色違い厳選のように、用途に応じて使い分けていくのもいいかもしれません!
最後に
何度もテストしたコードなので、動作に関しては問題ないと思います。
ですが、万一ループから抜けてしまうようなことがありましたら、@lefmarnaまでお知らせください。