2023-11-07に更新

Godot でゲームのコントローラーを使おうぜ(^~^)?

読了目安:15分

親記事から来た

📖 Godot って何だぜ(^~^)?

Git Hub

📖 src-game-controller

はじめに

202310__photo__27-2220--Gamepad.jpg

ramen-tabero-futsu2.png
「 👆 ゲームパッドが届いたので Godot はゲームパッドを使えるか 調べようぜ?」

ohkina-hiyoko-futsu2.png
「 こういうコントローラーは どうやって使うの?」

ramen-tabero-futsu2.png
「 ハードウェアと ハードウェアは結局 ピンが束になったバスで つながってるだけで
そこを電気信号が通るだけだぜ。
現代だと USB規格 を使うだろうから、
USB端子を USBポートに差し込めば
OS に何か刺さった、という 自動認識まではしてくれるんじゃないかな」

kifuwarabe-futsu.png
「 やってくれだぜ」

202310__photo__27-2232--Gamepad-o2o0.jpg

ramen-tabero-futsu2.png
「 👆 じゃあ USB ケーブルを指すぜ。無線のもあるな」

ramen-tabero-futsu2.png
「 USB メモリータイプの端子挿したら PCから音が出て 反応して セットアップが自動的に始まって
セットアップが終わったぜ」

ohkina-hiyoko-futsu2.png
「 電池は?」

ramen-tabero-futsu2.png
「 ケーブル挿して1、2時間でチャージが終わるそうだぜ。電池は取り出せなさそう」

kifuwarabe-futsu.png
「 じゃあ ケーブル挿せだぜ」

Godot の説明書読もうぜ?

ramen-tabero-futsu2.png
「 👇 説明書読むか~」

📖 Controllers, gamepads, and joysticks

E 0:00:00:0571   director.gd:24 @ _process(): The InputMap action "move_back" doesn't exist. Did you mean "ui_text_backspace"?
  <C++ エラー>      Condition "!InputMap::get_singleton()->has_action(p_action)" is true. Returning: 0.0
  <C++ ソース>      core/input/input.cpp:346 @ get_action_raw_strength()
  <スタックトレース>     director.gd:24 @ _process()

ramen-tabero-futsu2.png
「 👆 いや もう エラー出たが」

202310__godot__27-2316--InputMap.png

ramen-tabero-futsu2.png
「 👆 インプットマップが空なのと 何か関係あるかだぜ?」

202310__godot__27-2316--InputMap-o2o0.png

ramen-tabero-futsu2.png
「 👆 あっ、何か出た!」

ohkina-hiyoko-futsu2.png
「 ui_left というのが使えるんじゃないの?」

func _process(_delta):

    var velocity = Input.get_vector(
            &"ui_left",     # 左の方
            &"ui_right",    # 右の方
            &"ui_up",       # 上の方
            &"ui_down")     # 下の方

    $"GuiArtist/CanvasLayer/→値".text = str(velocity.x)
    $"GuiArtist/CanvasLayer/↓値".text = str(velocity.y)

ramen-tabero-futsu2.png
「 👆 よし、取れたぜ。 -101 のいずれかになる感じだぜ」

Godot の説明書じゃ分かんね

ramen-tabero-futsu2.png
「 たいてい、公式の記事を読め、と言うところなんだが、 Godot は金も人手も足りてないのか ホームページもドキュメントも ぐちゃぐちゃなんで……」

📖 Input examples

func _input(event):
    print(event.as_text())

ramen-tabero-futsu2.png
「 👆 自力で解析するか」

Output:

Joypad Button 0 (Bottom Action, Sony Cross, Xbox A, Nintendo B)
Joypad Button 1 (Right Action, Sony Circle, Xbox B, Nintendo A)

ramen-tabero-futsu2.png
「 👆 この入力はどうやって 利用できるのか」

ohkina-hiyoko-futsu2.png
「 その文字列を利用すればいいんじゃない?」

ramen-tabero-futsu2.png
「 この文字列が仕様なのか Godot をアップデートしたら あっさり変わるのか分からん」

📖 Input

func _input(event):
    for action in InputMap.get_actions():
        if InputMap.event_is_action(event, action):
            print("action: " + action)

Output:

Joypad Button 0 (Bottom Action, Sony Cross, Xbox A, Nintendo B)

ramen-tabero-futsu2.png
「 👆 確かにこの文字列が出力されるが……」

ramen-tabero-futsu2.png
「 じゃあ この長ったらしい文字列が ボタンのIdになってるわけかだぜ、変なの」

Joypad Button 0 (Bottom Action, Sony Cross, Xbox A, Nintendo B)
Joypad Button 0 (Bottom Action, Sony Cross, Xbox A, Nintendo B)

ramen-tabero-futsu2.png
「 👆 1ボタンと 連射1ボタンが 同じ文字列 返ってくるぜ」

kifuwarabe-futsu.png
「 連射ボタンだからじゃないか? 押しっぱなしにしてみろだぜ?」

ramen-tabero-futsu2.png
「 確かに 1ボタンは 押しっぱなしにしても反応しないが、
連射1ボタンは 押しっぱなしにしてると 何度も反応するぜ、いわゆるキー・リピート」

kifuwarabe-futsu.png
「 連射ボタンだからな」

ramen-tabero-futsu2.png
「 嬉しくね~」

ramen-tabero-futsu2.png
「 せっかく 4つ ボタンが付いてるのに そのうちの半分は キーリピートするだけ……」

ohkina-hiyoko-futsu2.png
「 時代よ 時代! シューティング全盛期!」

セレクトボタンと ランボタン

Joypad Button 4 (Back, Sony Select, Xbox Back, Nintendo -)
Joypad Button 6 (Start, Xbox Menu, Nintendo +)
Unknown

ramen-tabero-futsu2.png
「 👆 セレクト・ボタンが ボタン4、
ラン・ボタンが ボタン6 だぜ。
模倣品のゲームパッドの真ん中上の方にある 本来付いてない何か分からんボタンを押すと Unknown で、パソコン画面上に 各種設定が出てきたぜ」

PC-Engine のゲームパッドのボタン配置

                                                  &"Unknown"
      &"ui_up"                                                                         &"Joypad Button 1 (Right Action, Sony Circle, Xbox B, Nintendo A)"連射  &"Joypad Button 0 (Bottom Action, Sony Cross, Xbox A, Nintendo B)"連射
&"ui_left"       &"ui_right"                                                   
      &"ui_down"                                                                        &"Joypad Button 1 (Right Action, Sony Circle, Xbox B, Nintendo A)"    &"Joypad Button 0 (Bottom Action, Sony Cross, Xbox A, Nintendo B)"

                  &"Joypad Button 4 (Back, Sony Select, Xbox Back, Nintendo -)"      &"Joypad Button 6 (Start, Xbox Menu, Nintendo +)"

kifuwarabe-futsu.png
「 👆 つまり こうだ」

ramen-tabero-futsu2.png
「 美しくないが その文字列に従って コーディングしてみるか、美しくないが」

# 入力1つ1つに分解されて呼び出されるようだ
func _unhandled_input(event):

    # 文字列だけだと、押したのか放したのか分からない
    var event_as_text = event.as_text()
    print("入力: " + event_as_text)

    var description = "判定: "
    # 初期状態は、ボタンを離しているということにする
    var presentation = "."

    # ボタンの状態(何もしていないときはこの関数自体が呼び出されない)

    if event.is_pressed():
        description += "pressed "
        presentation = "■"

    if event.is_released():
        description += "released "
        presentation = "."

    # 操作したボタン
    var button_number = -1

    if event_as_text == &"Joypad Button 0 (Bottom Action, Sony Cross, Xbox A, Nintendo B)":
        description += "Joypad Button 0"
        button_number = 0

    elif event_as_text == &"Joypad Button 1 (Right Action, Sony Circle, Xbox B, Nintendo A)":
        description += "Joypad Button 1"
        button_number = 1

    elif event_as_text == &"Joypad Button 4 (Back, Sony Select, Xbox Back, Nintendo -)":
        description += "Joypad Button 4"
        button_number = 4

    elif event_as_text == &"Joypad Button 6 (Start, Xbox Menu, Nintendo +)":
        description += "Joypad Button 6"
        button_number = 6

    print(description)

    # "Joypad Button 0 (Bottom Action, Sony Cross, Xbox A, Nintendo B)"
    if button_number == 0:
        $"GuiArtist/CanvasLayer/I値".text = presentation

    # "Joypad Button 1 (Right Action, Sony Circle, Xbox B, Nintendo A)"
    elif button_number == 1:
        $"GuiArtist/CanvasLayer/II値".text = presentation

    # "Joypad Button 4 (Back, Sony Select, Xbox Back, Nintendo -)"
    elif button_number == 4:
        $"GuiArtist/CanvasLayer/Select値".text = presentation

    # "Joypad Button 6 (Start, Xbox Menu, Nintendo +)"
    elif button_number == 6:
        $"GuiArtist/CanvasLayer/Run値".text = presentation


    var is_lever = false

    for action in InputMap.get_actions():
        if InputMap.event_is_action(event, action):
            print("action: " + action)

            # 十字キーを想定
            if action == &"ui_left" or action == &"ui_right" or action == &"ui_up" or action == &"ui_down":
                is_lever = true

#           if action == &"JOY_AXIS_INVALID":
#               print("JOY_AXIS_INVALID")
#           elif action == &"JOY_AXIS_LEFT_X":
#               print("JOY_AXIS_LEFT_X")
#           elif action == &"JOY_AXIS_LEFT_Y":
#               print("JOY_AXIS_LEFT_Y")
#           elif action == &"JOY_AXIS_MAX":
#               print("JOY_AXIS_MAX")
#           elif action == &"JOY_AXIS_RIGHT_X":
#               print("JOY_AXIS_RIGHT_X")
#           elif action == &"JOY_AXIS_RIGHT_Y":
#               print("JOY_AXIS_RIGHT_Y")
#           elif action == &"JOY_AXIS_SDL_MAX":
#               print("JOY_AXIS_SDL_MAX")
#           elif action == &"JOY_AXIS_TRIGGER_LEFT":
#               print("JOY_AXIS_TRIGGER_LEFT")
#           elif action == &"JOY_AXIS_TRIGGER_RIGHT":
#               print("JOY_AXIS_TRIGGER_RIGHT")
#           elif action == &"JOY_BUTTON_A":
#               print("JOY_BUTTON_A")
#           elif action == &"JOY_BUTTON_B":
#               print("JOY_BUTTON_B")
#           elif action == &"JOY_BUTTON_BACK":
#               print("JOY_BUTTON_BACK")
#           elif action == &"JOY_BUTTON_DPAD_DOWN":
#               print("JOY_BUTTON_DPAD_DOWN")
#           elif action == &"JOY_BUTTON_DPAD_LEFT":
#               print("JOY_BUTTON_DPAD_LEFT")
#           elif action == &"JOY_BUTTON_DPAD_RIGHT":
#               print("JOY_BUTTON_DPAD_RIGHT")
#           elif action == &"JOY_BUTTON_DPAD_UP":
#               print("JOY_BUTTON_DPAD_UP")
#           elif action == &"JOY_BUTTON_GUIDE":
#               print("JOY_BUTTON_GUIDE")
#           elif action == &"JOY_BUTTON_INVALID":
#               print("JOY_BUTTON_INVALID")
#           elif action == &"JOY_BUTTON_LEFT_SHOULDER":
#               print("JOY_BUTTON_LEFT_SHOULDER")
#           elif action == &"JOY_BUTTON_LEFT_STICK":
#               print("JOY_BUTTON_LEFT_STICK")
#           elif action == &"JOY_BUTTON_MAX":
#               print("JOY_BUTTON_MAX")
#           elif action == &"JOY_BUTTON_MISC1":
#               print("JOY_BUTTON_MISC1")
#           elif action == &"JOY_BUTTON_PADDLE1":
#               print("JOY_BUTTON_PADDLE1")
#           elif action == &"JOY_BUTTON_PADDLE2":
#               print("JOY_BUTTON_PADDLE2")
#           elif action == &"JOY_BUTTON_PADDLE3":
#               print("JOY_BUTTON_PADDLE3")
#           elif action == &"JOY_BUTTON_PADDLE4":
#               print("JOY_BUTTON_PADDLE4")
#           elif action == &"JOY_BUTTON_RIGHT_SHOULDER":
#               print("JOY_BUTTON_RIGHT_SHOULDER")
#           elif action == &"JOY_BUTTON_RIGHT_STICK":
#               print("JOY_BUTTON_RIGHT_STICK")
#           elif action == &"JOY_BUTTON_SDL_MAX":
#               print("JOY_BUTTON_SDL_MAX")
#           elif action == &"JOY_BUTTON_START":
#               print("JOY_BUTTON_START")
#           elif action == &"JOY_BUTTON_TOUCHPAD":
#               print("JOY_BUTTON_TOUCHPAD")
#           elif action == &"JOY_BUTTON_X":
#               print("JOY_BUTTON_X")
#           elif action == &"JOY_BUTTON_Y":
#               print("JOY_BUTTON_Y")

            # 以上

    if is_lever:
        var velocity = Input.get_vector(
                &"ui_left",     # 左の方
                &"ui_right",    # 右の方
                &"ui_up",       # 上の方
                &"ui_down")     # 下の方

        $"GuiArtist/CanvasLayer/→値".text = str(velocity.x)
        $"GuiArtist/CanvasLayer/↓値".text = str(velocity.y)

ramen-tabero-futsu2.png
「 👆 よく分からん。またあとで書き直そうぜ?」

仮想キーを作らな

ramen-tabero-futsu2.png
「 ゲームパッドと キーボード、両方の操作を プログラムするの めんどくさいぜ。
仮想キーを作らな」

&"VK_Ok"
&"VK_SystemMenu"
&"VK_FastForward"

ramen-tabero-futsu2.png
「 👆 こんな感じで」

kifuwarabe-futsu.png
「 キーボードが Push Any Key じゃなくなったが……」

ramen-tabero-futsu2.png
「 1つ1つ 仮想の Ok ボタン当てはめていくの めんどくさいんで エンターキー使えだぜ」

ohkina-hiyoko-futsu2.png
「 劣化よ、劣化!」

メガドライブ風ゲームパッド

202310__photo__28-1256--GamePadBox-o2o0.jpg

kifuwarabe-futsu.png
「 👆 まだ箱があるぜ」

202310__photo__28-1256--GamePadOpen-o2o0.jpg

ramen-tabero-futsu2.png
「 これもUSBが入ってるな。 同じ 8 Bit Do というメーカーのようだぜ、知らんけど」

8BitDo のコントローラーは粗悪品かも知らん。コントローラーが反応しなくなった

ramen-tabero-futsu2.png
「 終わった……」

kifuwarabe-futsu.png
「 電池か?」

ramen-tabero-futsu2.png
「 最後に挿したUSB端子のせいで おかしくなったとか 画面右下で言いわけがポップアップされたぜ」

ohkina-hiyoko-futsu2.png
「 2時間 充電してみましょう。
それで動かなかったら 床に叩きつけて 割りましょう」

8BitDo のPC-Engine風のゲームパッドは、実用的な話を言えば、必ずドライバーの更新の手順を踏む必要がある

ramen-tabero-futsu2.png
「 捨てるか ドライバーを再インストールするか 考え中」

📖 https://support.8bitdo.com/

ramen-tabero-futsu2.png
「 👆 サポートサイトはここにあるが、悪意のあるサイトか、そうでないか分からない。
わたしが人柱になるんで、あとは頼む」

ramen-tabero-futsu2.png
「 PC-Engine風のゲームパッド用のドライバーをダウンロードすると説明書が入っているのでそれを読む」

202310__godot__28-2330--8BitDo-HomeButton.png

ramen-tabero-futsu2.png
「 👆 8BitDo のゲームパッドには 上図のような柄のボタンが付いていて、 ホームボタン(Home Button) と呼ぶそうだぜ」

ramen-tabero-futsu2.png
「 ゲームパッドのUSB接続を抜き、ホームボタンを3秒押すと、赤いランプも青いランプも消えた状態になる。
これが 電源オフの状態だぜ」

ramen-tabero-futsu2.png
「 セレクトボタンを押したまま、ホームボタンを押す」

ramen-tabero-futsu2.png
「 すると 青いランプと 黄色いランプが点滅する」

ramen-tabero-futsu2.png
「 無線ではなく、USBケーブルを使って ゲームパッドとPCを接続する」

ramen-tabero-futsu2.png
「 すると ゲームパッド側は USB フラッシュ・ドライブ になっているらしく、
そのファイル・エクスプローラーが開く」

ramen-tabero-futsu2.png
「 8BitDo_PCE_Gamepad_Fw_V4.02.dat ファイルを、 USB フラッシュ・ドライブへ
コピー貼り付けする」

ramen-tabero-futsu2.png
「 コピーが終わったら USBケーブルを抜く」

ramen-tabero-futsu2.png
「 まだ 青いランプと 黄色いランプが点滅しているから、
そのランプが消えるよう、ホームボタンを 3秒間 押し続ける」

ramen-tabero-futsu2.png
「 ランプが消えたら更新完了」

ramen-tabero-futsu2.png
「 あとは 工場から出荷されて自宅に届いたつもりになって 普通にゲームパッドを使えば 使える」

kifuwarabe-futsu.png
「 だったら 使用前に ドライバーの更新をすることを 必須にしてほしい」

8BitDO のメガドライブ風のゲームパッドも、実用的な話を言えば、ドライバーを再インストールする必要がある

ramen-tabero-futsu2.png
「 8BitDO のメガドライブ風のゲームパッドも、実用的な話を言えば、ドライバーを再インストールする必要がある」

ohkina-hiyoko-futsu2.png
「 何の案内も無いのに 探した者だけが見つけることができるところに 手順だけあるの、海外製品のサポートよね~」

ramen-tabero-futsu2.png
「 👇 とりあえず 自分の持ってる製品に合ったドライバーを入手しろだぜ。ゲームパッドのどこかに型番が刻印されているだろう」

📂 M30_24G_Mini_GamepadV208

ramen-tabero-futsu2.png
「 パターンがいくつかあるようなので、わたしのケースで説明する」

ramen-tabero-futsu2.png
「 ゲームパッドとPCが接続されていない状態にする。USBケーブルを抜くとか」

ramen-tabero-futsu2.png
「 ゲームパッドのど真ん中にあるスタートボタンを、体感で10秒ぐらい長押しする。
すべてのランプが消灯する」

ramen-tabero-futsu2.png
「 L、Rボタンの両方を押しっぱなしにして、スタートボタンを押す。
これで 黄色いランプと、青いランプが点灯し続ける。これは アップグレード・モード と呼ぶそうだぜ」

ramen-tabero-futsu2.png
「 USBケーブルを使って、ゲームパッドとPCを接続する」

ramen-tabero-futsu2.png
「 すると ゲームパッド側は USB フラッシュ・ドライブ になっているらしく、
そのファイル・エクスプローラーが開く」

ramen-tabero-futsu2.png
「 CopyFwToUDisk.exe ファイルをダブルクリックする」

ramen-tabero-futsu2.png
「 Open ボタンをクリックして、*.dat ファイルが添付されてるから、それを選ぶ」

ramen-tabero-futsu2.png
「 Update ボタンをクリックする。黒い画面が出る。それが勝手に閉じられるまで待つ」

ramen-tabero-futsu2.png
「 また、ゲームパッドとPCを接続しているUSBケーブルを抜く」

ramen-tabero-futsu2.png
「 スタートボタンを 3秒間 押し続ける。これでコントローラーの電源がオフになる」

ramen-tabero-futsu2.png
「 あとは 工場から出荷されて自宅に届いたつもりになって 普通にゲームパッドを使えば 使える」

kifuwarabe-futsu.png
「 だったら 使用前に ドライバーの更新をすることを 必須にしてほしい」

📅 2023-10-29 sun ⏰ 13:16

XBox風コントローラー

202310__photo__29-1312--XBoxController-o2o0.jpg

ramen-tabero-futsu2.png
「 👆 次は XBox風のコントローラーだぜ。ぷちぷちにくるまれてただけで、説明書もないぜ。
メーカー名も刻印されてないぜ」

kifuwarabe-futsu.png
「 じゃあ USB端子を挿そうぜ?」

ramen-tabero-futsu2.png
「 USB端子を挿しただけで認識したぜ。もう すぐに使える状態のようだぜ」

8BitDo のコントローラーは粗悪品かも知らん

ramen-tabero-futsu2.png
「 8BitDo のメガドライブ風のゲームパッドが反応しなくなった。
もう ドライバーの再インストールなんてしないぜ クソだろ このゲームパッド」

ramen-tabero-futsu2.png
「 Amazon のレビューに ☆1 付けたった」

PS風コントローラーは粗悪品だった

202310__photo__29-1646--PSControllerPacked-o2o0.jpg

ramen-tabero-futsu2.png
「 👆 新品が ぷちぷちに くるまれて送られてくるんだな。こんなんでいいんだな」

202310__photo__29-1647--PSController-o2o0.jpg

ramen-tabero-futsu2.png
「 👆 USB端子を挿してみるか」

ramen-tabero-futsu2.png
「 左側の十字キーの上ボタンと、右ボタンが反応しないぜ」

kifuwarabe-futsu.png
「 もっと調べてみろだぜ。他のボタンも反応しないかもしれないぜ?」

ramen-tabero-futsu2.png
「 嬉しくないな……」

ramen-tabero-futsu2.png
「 □、×、○ボタンも利かねーっ!」

PS風コントローラーうまくいかね

202311__photo__07--RegularPSController-o2o0.jpg

ramen-tabero-futsu2.png
「 👇 PCでうまくいかね。BGM消えたり、レバーが入りっぱなしだったり分かんね。もう止めよかな」

📖 PS4 ユーザーズガイド

kifuwarabe-futsu.png
「 他にも 買ったコントローラー まだ来ないのか」

ramen-tabero-futsu2.png
「 即売会への時間も そろそろ無くなってきたし ゲームパッドの調査は打切りとする」

親記事へ戻る

📖 Godot って何だぜ(^~^)?

.

ツイッターでシェア
みんなに共有、忘れないようにメモ

むずでょ

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント