higedaruma が 2024年10月28日09時40分20秒 に編集
コメント無し
本文の変更
# はじめに **スーパーマリオブラザーズ**を遊ぶための変わった[コントローラ](https://protopedia.net/prototype/3388)を作って展示会等で遊んでもらっていました。 小さいお子さんの場合、普通のコントローラで遊ぶこと自体が初めて子が多い事に気づいきました。 既存のマリオを**誰でも簡単に遊べる**ようにするため、1つのボタンを押すだけで遊べる専用コントローラーを作成しました。 展示会等で細かい説明をしなくても、「勝手に遊べる」簡単さも実装のコンセプトにしています。 ※合計3日ほど展示しましたが、ほぼ説明不要で遊んでもらえてます。 # 完成品の紹介 こちらが展示会に設営した時の写真です。 可愛いアヒル型コントローラーと、大きいボタンが特徴となっています。  ## 実際の動作 @[youtube](https://youtu.be/g0XYTSFk_I0) ### 各種ボタンの動作について 強制的に右ボタンを押す状態にする事で、勝手に移動するようにし、ジャンプだけで遊べるようにしました。 ※ステージによってはこのボタンだけだと厳しいかもしれませんが、今回はそこまで辿り着く方はいませんでした 大人向けに頭のキーロックを回す事で、**Bダッシュ** の状態になるようにしています。 ボタンが押されている状態だと、スタートは無効となるため、スタートボタンが押された場合のみ、他のキーは無視するようにしています。 また、左移動のボタンがないため、全く動けなくなる場合もあることから、すべてのボタンを同時に押すとゲームをリセットする機能も入れています。  展示会において、こちらの説明資料があれば問題は起こりませんでした。 # 構成 装置の構成は下図の通りです  ==なぜモノラルジャックを使うのか? ボタンをモノラルジャックにすることで、どんな方でもご自身が利用できる**専用のボタン**に変えて使って遊んでもらえると考えたからです。 参考:[意思伝達装置用スイッチ](https://www.rehab.go.jp/ri/kaihatsu/itoh/com-sw.html)== ## アヒルの構成 頭に、キーロック、胴に3つのモノラルジャックをつけています。  可哀想ですが、頭は、12mm、胴は8mmのドリルで穴を開けています。  アヒルの下に60mm程度の穴を開けています。 3D専用の土台を3プリンタで出力し、空いた穴の蓋と基板の固定(はめる感じ)を兼ねるようにしています。  頭と胴からの各種配線はこのような感じ。 少し小さい大きいアヒルを使っています。 ボタンを増やす、配線が窮屈な場合は、もう少し大型のアヒルを使うも良さどうです。  お尻からは任天堂Switchと接続するためのUSBケーブルを出しています。 穴を開けず切れ込みを入れて、ケーブル通しています。 ## ボタンの構成 モノラルプラグ対応であればどのようなボタンでも利用可能ですが、叩き心地のある大きめなボタンを用意  ボタン自体は発光対応ですが、今回は光らせてません。  ボタンは、モノラルケーブルと繋ぐだけのシンプルなモノです。 筐体は、3Dプリンタで出力し、上蓋、胴、下蓋と3つを組み合わせるだけのシンプルなものです。 # 部品表 ### アヒルコントローラー | 名前 | 数量 | 備考 | |:---|---:|:--| | ゴムアヒル (10.2 mm x 115mm x 130mm) | 1個 | https://ja.aliexpress.com/item/1005005849020308.html| | Raspberry Pi Pico | 1個 |(共立電子) https://eleshop.jp/shop/g/gL25313/| | φ3.5mm モノラルジャック パネル型 | 3個 | (共立電子) https://eleshop.jp/shop/g/gB84131/| | キースイッチ| 1個 | (共立電子) https://eleshop.jp/shop/g/gO8MS3Z/ | | QIケーブル2S-2S *※半分に切って使用* | 2本 | (共立電子) https://eleshop.jp/shop/g/gAAC411/| | ヘッダーピン | 8本 | (共立電子) https://eleshop.jp/shop/g/gN1K311/| |30mm x 70mm ユニバーサル基板 |1枚|(共立電子)https://eleshop.jp/shop/g/gGBS125/ | | ファストン端子 単極用 #110/メス|2個|(共立電子)https://eleshop.jp/shop/g/gN1D114/ | | microUSBケーブル | 1本 | (共立電子)https://eleshop.jp/shop/g/gH9E31E/| | アヒル筐体 | 1個 | [3Dプリンタ出力](https://github.com/tanaka3/OneButtonMario/blob/main/STL/%E3%82%A2%E3%83%92%E3%83%AB%E7%AD%90%E4%BD%93.stl) | ※筐体は、[Github](https://github.com/tanaka3/OneButtonMario)にてモデルを公開しています。 ### ボタン (3個分) | 名前 | 数量 | 備考 | |:---|---:|:--| |60mmラウンドプッシュボタンスイッチ |3個|https://ja.aliexpress.com/item/1005001456931168.html |
| ファストン端子 単極用 #205/メス |6個|((共立電子)https://eleshop.jp/shop/g/gN1D116 |
| ファストン端子 単極用 #205/メス |6個|(共立電子)https://eleshop.jp/shop/g/gN1D116 |
| 3.5φ片端モノラルプラグ付きケーブル| 3本 | (共立電子)https://eleshop.jp/shop/g/g66131S/| | ボタン(上蓋) | 3個 | [3Dプリンタ出力 ](https://github.com/tanaka3/OneButtonMario/blob/main/STL/%E3%83%9C%E3%82%BF%E3%83%B3%EF%BC%88%E4%B8%8A%E8%93%8B%EF%BC%89.stl)| | ボタン(胴) | 3個 | [3Dプリンタ出力](https://github.com/tanaka3/OneButtonMario/blob/main/STL/%E3%83%9C%E3%82%BF%E3%83%B3%EF%BC%88%E4%B8%8B%E8%93%8B%EF%BC%89.stl) | | ボタン(下蓋) | 3個 | [3Dプリンタ出力](https://github.com/tanaka3/OneButtonMario/blob/main/STL/%E3%83%9C%E3%82%BF%E3%83%B3%EF%BC%88%E8%83%B4%EF%BC%89.stl) | ※筐体は、[Github](https://github.com/tanaka3/OneButtonMario)にてモデルを公開しています。 # 接続図  # ソースコード ## 環境 * [Arduino IDE v2.3.3](https://www.arduino.cc/en/software/) ## ボード定義 * [Arduino-Pico v4.1.1](https://github.com/earlephilhower/arduino-pico) ==ビルドを行うには、**USB Stack**は、``Adafruit TinyUSB``を選択してください。 == ## 使用ライブラリ * [switch_tinyusb_custom](https://github.com/tanaka3/switch_tinyusb_custom) ※touchgadgetさん作成の[switch_tinyusb](https://github.com/touchgadget/switch_tinyusb)のカスタマイズ版 [Github](https://github.com/tanaka3/OneButtonMario/tree/main/OneButtonMario) ```cpp:onebuttonmario.ino #include "switch_tinyusb_custom.h" #define SW_SATRT_GPIO 19 #define SW_LEFT_GPIO 18 #define SW_B_GPIO 17 #define SW_A_GPIO 16 Adafruit_USBD_HID G_usb_hid; NSGamepad Gamepad(&G_usb_hid); HID_NSGamepadReport_Data_t beforeData; bool resetFlg = false; void setup() { Serial.begin(115200); Gamepad.begin(); // wait until device mounted while( !USBDevice.mounted() ) delay(1); pinMode(SW_SATRT_GPIO, INPUT_PULLUP); pinMode(SW_LEFT_GPIO, INPUT_PULLUP); pinMode(SW_B_GPIO, INPUT_PULLUP); pinMode(SW_A_GPIO, INPUT_PULLUP); pinMode(25, OUTPUT); digitalWrite(25, HIGH); } void loop() { Gamepad.reset(); // 他のキーが押下されている場合、スタートが無効となるため // スタートが押されている場合は、他のボタンを無視する if(digitalRead(SW_SATRT_GPIO) == LOW){ // スタート押下状態で、他のボタンが押されている場合は // ゲームをリセットする if(digitalRead(SW_A_GPIO) == LOW && digitalRead(SW_STOP_GPIO) == LOW ){ if(resetFlg){ return; } //リセットフラグを有効し、複数回の実行を防ぐ resetFlg = true; resetControll(); } else{ resetFlg = false; Gamepad.press(NSButton_Plus); } } else{ resetFlg = false; //キーロックが有効の場合は、Bダッシュ状態とする if(digitalRead(SW_B_GPIO) == LOW){ Gamepad.press(NSButton_B); } if(digitalRead(SW_A_GPIO) == LOW){ Gamepad.press(NSButton_A); } bool up = false; bool down = false; // 強制的に移動させる bool right = true; // 右と左が同時に押されている場合は、無効の判断になる(なので止まる) bool left = stopButton.read() == LOW; Gamepad.dPad(up, down, left, right); } // 前回と入力が同じ場合は、ボタン操作を送信しない if(!Gamepad.compareTo(beforeData)){ Gamepad.SendReport(); beforeData = Gamepad.getReportData(); } } /** * @brief ファミコンのリセット操作 * ZL+ZR押してメニューのリセットを選ぶ操作 */ void resetControll(){ Gamepad.reset(); Gamepad.press(NSButton_LeftThrottle); Gamepad.press(NSButton_RightThrottle); Gamepad.SendReport(); delay(100); for(int i=0; i<3; i++){ Gamepad.reset(); Gamepad.dPad(true, false, false, false); Gamepad.SendReport(); delay(150); Gamepad.reset(); Gamepad.SendReport(); delay(150); } Gamepad.reset(); Gamepad.press(NSButton_A); Gamepad.SendReport(); } ``` # 最後に 展示会に置いておくだけで、みんなが勝手に遊んでくれる事を目標に、2回ほど展示しましたが、 説明の手間もなく、子供から大人まで、好き勝手に楽しんでくれていたように思います。 簡単だけど制約があるコントローラーは、同じゲームの新しい楽しみ方を教えてくれました。 そして、30年近く前の「スーパーマリオブラザーズ」のゲームデザインがいかに優れているかも気づかせてくれます。 一部ではありますが、遊んでくださった方々に感謝を 