※本記事は、ポケモン剣盾の本編ストーリーを自動化するプログラムについてモチベを挙げるためにひとまず公開した解説した記事です。ポケモン剣盾の操作をArduino Leonardoで自動化しております。「Arduinoって何?」って方は00回目の記事を、Arduinoの環境構築(ライブラリ含む)は01回目の記事をご覧ください。
作り途中でモンハンで忙しくなってモチベが下がったので、ひとまず公開します。完成を優先したいので解説は気が向いたときに追記します。デバッグ等はできていません。動作報告、改善案などいただけますと執筆者のやる気が回復します。
2021/10/23 色違いザシアンザマゼンタの配布に合わせ、調整しました。言語によってテキスト送りの時間に差があったため、全言語に対応すべく入力回数や猶予時間を増やしました。
2021/10/24 ろっこく 様より、 言語ごとに入力回数を変更できる改良版を提供いただきましたので、こちらにて公開させていただきます(ENG, SPA, ITA 以外であれば動作が速くなります)。
2021/10/25 こちゃてす 様より、Ver2.1をArduino Uno R3(ATmega16U2)用に変換したプログラムを提供いただきましたので、こちらに公開させていただきます。(私は16U2を使用していないため、こちらではサポートできません。ご了承ください。)以下でストーリー開始~通信できるまで進行~ふしぎなおくりもの受け取りまでの自動化を公開しています。
原理、おおまかな流れ
動画を見ればだいたい流れが分かるかと思います。
作成したスケッチ
2021/07/31 ふしぎなおくりもの受け取り自動化にあわせて、一部操作を改良したv.1.1を公開します。 時間に余裕のある箇所は短縮し、余裕のない箇所は時間やボタン入力の頻度などを調整しました。また、2番道路の3人目のトレーナー戦の前に傷薬での回復を行い、メッソンが瀕死になる可能性を減らしました。
2021/10/23 色違いザシアンザマゼンタの配布に合わせ、調整しました。主に、言語によってテキスト送りの時間に差があったため、全言語に対応すべく入力回数や猶予時間を増やしました。全体的に動作はv1.xよりも長いため、効率化の場合は各言語に合わせて調整してください。
2021/10/26 2番道路にて最初の短パン小僧付近の動きが少し不安定だったので、動きを変更したVer3.0(2.0より改良)を公開します。短パン小僧付近で右、上、右と3段階で動いていたところを右上1段階に変更しています。その他、スリープ関数の変更をしました。
Ver3.0はVer2.0をベースに作成しております。上記 ろっこく 様のVer2.1の機能(言語ごとの調整)を使用する場合は、「sleepNow()」「goToRoute2()」のみ編集してください。
「ゲーム開始~推薦状:通信できるまで」のスケッチ最新版はこちらv3.0。
2021/10/24 ろっこく 様より、 言語ごとに入力回数を変更できる改良版を提供いただきましたので、こちらにて公開させていただきます(ENG, SPA, ITA 以外であれば動作が速くなります)v2.1
2021/10/25 こちゃてす 様より、Ver2.1をArduino Uno R3(ATmega16U2)用に変換したプログラムを提供いただきましたので、こちらに公開させていただきます。v2.1for16U2
なお、私は16U2を使用していないため、こちらではサポートできません。ご了承ください。 こちゃてす 様よりお問い合わせ等の対応をしていただけるとのことですが、ご迷惑のないようにお願いいたします。
言語、主人公の容姿や名前を決定後にマイコンを挿してスタート。
99%失敗しないことを目指して作っており、ランダム要素を考慮して余裕をもった操作をしているため、無駄な動作が多いかと思います。
本スケッチを実際に使用した動画はこちら↓。 無編集仮up版(v.1.0)
以下は初期のものです(v1.0)。最新版は上からファイルをDLしてください。
* ポケモン剣盾メインストーリー自動進行01
* 主人公名入力後~推薦状もらうまで
*
* 言語、外観、名前を決定し終えたところからスタート
* メッソンを選択し、推薦状をもらうまでを自動化
* 推薦状の後は、通信交換が可能
*
*/
#include <auto_command_util.h>
#include <avr/sleep.h>
// Switchスリープ用関数
void sleepNow()
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
}
// 主人公設定直後~動けるまで
void roseOpening(){
// 主人公設定、「はい」を選んだ直後からスタート、動けるまで約3分B連打
pushButton(Button::B, 400, 366);
}
// オープニング終了後~ポケモンもらえるまで
void startMove(){
// かばん取りに行く
tiltJoystick(0, 100, 0, 0, 700);
delay(200);
tiltJoystick(100, 0, 0, 0, 3500);
pushButton(Button::A, 200);
tiltJoystick(0, -100, 0, 0, 200);
pushButton(Button::A, 400, 34);
}
// 設定変更
void settingChange(){
// メニュー「設定」を変更,話速い
pushButton(Button::X, 900);
pushHatButtonContinuous(Hat::RIGHT, 1000);
pushButton(Button::A, 1000);
pushHatButton(Hat::RIGHT, 300);
// 日本語、その他言語共通の設定にするため下から順に変更(ひらがな漢字選択はしない)
pushHatButton(Hat::UP, 300);
// ムービースキップ、オートセーブOFF、ジャイロOFF、ニックネームOFF、ボックス送りオート、勝ち抜き、戦闘アニメOFF
pushHatButton(Hat::LEFT, 300);
pushHatButton(Hat::UP, 300, 3);
pushHatButton(Hat::RIGHT, 300);
pushHatButton(Hat::UP, 300, 3);
pushHatButton(Hat::RIGHT, 300);
pushHatButton(Hat::UP, 300);
pushHatButton(Hat::RIGHT, 300);
pushHatButton(Hat::UP, 300);
pushHatButton(Hat::RIGHT, 300);
pushHatButton(Hat::UP, 300);
pushHatButton(Hat::RIGHT, 300);
pushHatButton(Hat::UP, 300);
pushHatButton(Hat::RIGHT, 300);
// 決定、メニュー閉じる
pushButton(Button::A, 500, 7);
pushButton(Button::B, 500, 4);
}
// ポケモンもらえるところまで
void giveMePokemon(){
// 家を出る~ホップ家右塀に衝突
tiltJoystick(-100, 30, 0, 0, 4800);
tiltJoystick(0, 100, 0, 0, 24500);
pushButton(Button::B, 400, 56);
tiltJoystick(100, 0, 0, 0, 17000);
// ホップ家の中へ
tiltJoystick(-100, 0, 0, 0, 950);
tiltJoystick(0, -100, 0, 0, 1800);
pushButton(Button::B, 400, 48);
// 家を出る~ダンデに会い、ポケモンもらえるまで
tiltJoystick(100, 30, 0, 0, 1500);
tiltJoystick(0, 100, 0, 0, 300);
delay(2000);
tiltJoystick(0, 100, 0, 0, 300);
tiltJoystick(-100, 0, 0, 0, 5000);
tiltJoystick(0, -100, 0, 0, 5000);
pushButton(Button::B, 400, 14);
tiltJoystick(-10, -100, 0, 0, 18000);
pushButton(Button::B, 400, 194);
}
// メッソンを選ぶ
void chooseSobble(){
// メッソンに衝突
tiltJoystick(0, -100, 0, 0, 700);
tiltJoystick(-100, 0, 0, 0, 400);
// メッソン選択~バトル、ウールーへはたく×4、約2:20
pushButton(Button::A, 100, 700);
// ヒバニー出るまでB連打、急所等も考慮して多めに
pushButton(Button::B, 100, 90);
// たたかう>水鉄砲、その後約50s
pushButton(Button::A, 500);
pushHatButton(Hat::DOWN, 300, 2);
pushButton(Button::A, 100, 270);
}
void wooluuRescue(){
// 塀の外へ、ウールー助けに
tiltJoystick(-80, 100, 0, 0, 2000);
pushButton(Button::A, 500, 36);
tiltJoystick(-30, 100, 0, 0, 2000);
tiltJoystick(-30, -100, 0, 0, 200);
tiltJoystick(-30, 100, 0, 0, 2000);
// 左スティックを左(少し下)に固定、野生戦開始
SwitchController().setStickTiltRatio(-100, 30, 0, 0);
pushButton(Button::B, 500, 56);
// 逃げる×3
pushHatButton(Hat::UP, 300);
pushButton(Button::A, 500);
pushButton(Button::B, 500, 50);
pushHatButton(Hat::UP, 300);
pushButton(Button::A, 500);
pushButton(Button::B, 500, 48);
pushHatButton(Hat::UP, 300);
pushButton(Button::A, 500);
pushButton(Button::B, 500, 16);
// 左スティックを上に固定、ザシザマ戦開始(30s)
SwitchController().setStickTiltRatio(0, -100, 0, 0);
pushButton(Button::A, 100, 150);
// 左スティック固定解除、ニュートラル、引き続きA連打(2min)、家の前へ
SwitchController().setStickTiltRatio(0, 0, 0, 0);
pushButton(Button::A, 100, 600);
}
void changeMovePosition(){
// メッソンの技の1番上を水鉄砲に変更
pushButton(Button::X, 1000);
pushHatButtonContinuous(Hat::LEFT, 1500);
pushButton(Button::A, 1500);
pushButton(Button::A, 500);
pushButton(Button::A, 2000);
pushHatButton(Hat::RIGHT, 400, 2);
pushButton(Button::A, 400, 2);
pushHatButton(Hat::DOWN, 400, 2);
pushButton(Button::A, 400);
pushButton(Button::B, 500, 8);
}
void talkWithMom(){
// 自宅、ママに話しかけ
tiltJoystick(-80, -100, 0, 0, 4800);
delay(1200);
tiltJoystick(100, -60, 0, 0, 1500);
pushButton(Button::B, 500, 28);
tiltJoystick(-100, 30, 0, 0, 2000);
tiltJoystick(0, 100, 0, 0, 7500);
}
void goToRoute1(){
tiltJoystick(100, -30, 0, 0, 6000);
tiltJoystick(0, -100, 0, 0, 10000);
pushButton(Button::B, 500, 13);
tiltJoystick(0, -100, 0, 0, 3000);
// 左スティックを右に倒し、野生戦開始
// 野生との戦闘になったらボールを投げる
for(int i=0; i<5; i++){
SwitchController().setStickTiltRatio(100, 0, 0, 0);
pushButton(Button::B, 100, 38);
SwitchController().setStickTiltRatio(0, 0, 0, 0);
pushButton(Button::X, 500);
pushButton(Button::A, 500);
pushButton(Button::B, 100, 15);
}
pushButton(Button::B, 500, 8);
// 左スティックを上に倒す
tiltJoystick(0, -100, 0, 0, 8000);
// 左スティックを左に倒し、捕獲
for(int i=0; i<15; i++){
SwitchController().setStickTiltRatio(-100, 0, 0, 0);
pushButton(Button::B, 100, 38);
SwitchController().setStickTiltRatio(0, 0, 0, 0);
pushButton(Button::X, 500);
pushButton(Button::A, 500);
pushButton(Button::B, 100, 15);
}
pushButton(Button::B, 500, 2);
// プラッシータウン駅に衝突~研究所へ
tiltJoystick(0, -100, 0, 0, 8000);
tiltJoystick(0, 100, 0, 0, 800);
tiltJoystick(100, 0, 0, 0, 8500);
pushButton(Button::A, 400, 160);
// 研究所を出る
tiltJoystick(0, 100, 0, 0, 3000);
pushButton(Button::B, 400, 40);
}
void BrassyWalk(){
// ポケセンへ
tiltJoystick(-100, 30, 0, 0, 4500);
tiltJoystick(0, -100, 0, 0, 5000);
pushButton(Button::B, 400, 37);
pushHatButton(Hat::DOWN, 400);
pushButton(Button::A, 400, 15);
tiltJoystick(0, 100, 0, 0, 1200);
delay(1800);
tiltJoystick(-100, 100, 0, 0, 1700);
// 2番道路へ、捕獲チュートリアルスキップ
tiltJoystick(0, -100, 0, 0, 4000);
pushButton(Button::A, 400, 20);
tiltJoystick(100, -100, 0, 0, 5500);
tiltJoystick(0, 100, 0, 0, 800);
tiltJoystick(100, 0, 0, 0, 9000);
}
void goToRoute2(){
// ボールをもらった後、博士の家まで
// 左スティックを右に固定、野生戦開始
SwitchController().setStickTiltRatio(100, 0, 0, 0);
// 野生との戦闘になったら逃げる
for(int i=0; i<14; i++){
pushHatButton(Hat::UP, 500);
pushButton(Button::A, 500);
pushButton(Button::B, 500, 4);
}
// 左スティックを上に固定、野生は倒す
SwitchController().setStickTiltRatio(0, -100, 0, 0);
pushButton(Button::A, 100, 150);
// 左スティックを右に固定、短パン小僧、野生を撃破,壁に衝突
SwitchController().setStickTiltRatio(100, 0, 0, 0);
for(int i=0; i<45; i++){
pushButton(Button::A, 100, 5);
pushButton(Button::B, 100, 5);
}
// アイテム(ボール3個)に衝突
tiltJoystick(-100, -100, 0, 0, 3000);
// バッグを開き、傷薬をメッソンに使う
pushButton(Button::X, 500);
pushHatButtonContinuous(Hat::LEFT_UP, 1500);
pushHatButton(Hat::RIGHT, 400, 2);
pushButton(Button::A, 2000);
pushButton(Button::A, 500, 3);
pushButton(Button::B, 500, 9);
// 左スティックを左に固定、アイテムを取り、壁に衝突
SwitchController().setStickTiltRatio(-100, 0, 0, 0);
pushButton(Button::A, 100, 30);
// 左スティックを右上に固定、ミニスカートを撃破,壁に衝突
SwitchController().setStickTiltRatio(100, -100, 0, 0);
pushButton(Button::A, 100, 420);
tiltJoystick(-100, 100, 0, 0, 1000);
// 左スティックを上に固定、短パン小僧撃破、そのまま博士の家へ
SwitchController().setStickTiltRatio(0, -100, 0, 0);
pushButton(Button::A, 100, 460);
// スティックを戻し、引き続き会話
SwitchController().setStickTiltRatio(0, 0, 0, 0);
pushButton(Button::A, 100, 250);
// ホップと対戦へ
tiltJoystick(100, 30, 0, 0, 1700);
tiltJoystick(0, 100, 0, 0, 5000);
pushButton(Button::A, 500, 10);
tiltJoystick(-100, 0, 0, 0, 650);
tiltJoystick(0, -100, 0, 0, 200);
// 戦闘開始~推薦状、DMバンド、約4min
pushButton(Button::A, 100, 1220);
tiltJoystick(100, 60, 0, 0, 2500);
delay(8000);
}
void setup(){
pushButton(Button::B, 500, 13); // 最初の数回の入力はswitchが認識しない場合があるので、無駄打ちをしておく
roseOpening();
startMove();
settingChange();
giveMePokemon();
chooseSobble();
wooluuRescue();
changeMovePosition();
talkWithMom();
goToRoute1();
BrassyWalk();
goToRoute2();
sleepNow();
}
void loop(){
}
最後に
デバッグしてほしい+続きを作るモチベが上がらない(上げたい)のでひとまずうp。
いずれ気の向いたときに真面目に書きます。
その他にもプログラムの不備、改善点などありましたらコメントやお問い合わせからお願いいたします。
Arduino Arduino Leonardo (ピンソケット・ピンヘッダ実装済) 【A000057】 | ||||
|
0 件のコメント:
コメントを投稿