🎮

Pyxelで入力を簡単に検知したい

2023/12/01に公開

この記事の内容

Pythonでレトロゲーム制作ができるゲームエンジン、Pyxelで、入力検知用のクラスを作り、キー入力を簡単に管理・検出できるようにしてみたいと思います。

サンプルプログラムではどうなっているか

Pyxelはサンプルプログラムが充実していて、コードの基本的な実例として参考になります[1]。まずは、サンプルプログラムではどのように入力を検知しているかをみてみましょう。

入力の検知はpyxel.btnpyxel.btnrを使う

キー入力とプレイヤーの移動については、サンプルプログラムの09_shooter.pyがすごくわかりやすいです。以下に抜粋してみます。

09_shooter.pyからの抜粋
if pyxel.btn(pyxel.KEY_LEFT) or pyxel.btn(pyxel.GAMEPAD1_BUTTON_DPAD_LEFT):
    self.x -= PLAYER_SPEED
if pyxel.btn(pyxel.KEY_RIGHT) or pyxel.btn(pyxel.GAMEPAD1_BUTTON_DPAD_RIGHT):
    self.x += PLAYER_SPEED
if pyxel.btn(pyxel.KEY_UP) or pyxel.btn(pyxel.GAMEPAD1_BUTTON_DPAD_UP):
    self.y -= PLAYER_SPEED
if pyxel.btn(pyxel.KEY_DOWN) or pyxel.btn(pyxel.GAMEPAD1_BUTTON_DPAD_DOWN):
    self.y += PLAYER_SPEED

「右」であれば、pyxel.KEY_LEFT(キーボードの右)か、pyxel.GAMEPAD1_BUTTON_DPAD_LEFT(ゲームパッドの右)のいずれかを検知すれば、PLAYER_SPEEDの値がxに代入される仕組みになっていますね。

ボタンが押された場合はpyxel.btn、離された場合はpyxel.btnrです。分かりやすい!

でも…毎回if文を書くのは嫌だ

さて、自分のゲームを作る段階に移ったとします。

キーボードの矢印キーとゲームパッドの入力に加えて、PCゲームで一般的な「WASD」にも対応したい場合はどうでしょう。途中でやっぱり「WASD」から「ESDF」に変更したくなったら…?キーボードの矢印キーはプレイヤー2に割り当て直したくなるかもしれません。また、複数のファイルのいたるところで入力を検知するコードを書いているかもしれません。

仕様を変更するたびに、毎回全てのif文を書き換える…のは、ちょっと大変そうですね。

入力検知のためのクラスを作ってみる

そこで、入力検知用の簡易的なクラスInputDetectorを作ってみます。Godot Engineの入力周りの関数の使用感を参考にしてみました。

このクラスの役割・働きは以下のとおりです。

  1. 同じ役割の入力(例えば、上方向の入力→pyxel.KEY_UPpyxel.KEY_Wpyxel.GAMEPAD1_BUTTON_DPAD_UP)を1つの配列に詰め込みます。
  2. 1.で定義した配列を引数としてis_pressed()is_released()に渡すと、boolを返すようにします。

コードは以下のとおりです。

input_detector.py
import pyxel

class InputDetector():
  # 上方向の入力
  UP = [
    pyxel.KEY_UP,
    pyxel.GAMEPAD1_BUTTON_DPAD_UP,
    pyxel.KEY_W,
  ]

  # 下方向の入力
  DOWN = [
    pyxel.KEY_DOWN,
    pyxel.GAMEPAD1_BUTTON_DPAD_DOWN,
    pyxel.KEY_S,
  ]

  # 左方向の入力
  LEFT = [
    pyxel.KEY_LEFT,
    pyxel.GAMEPAD1_BUTTON_DPAD_LEFT,
    pyxel.KEY_A,
  ]

  # 右方向の入力
  RIGHT = [
    pyxel.KEY_RIGHT,
    pyxel.GAMEPAD1_BUTTON_DPAD_RIGHT,
    pyxel.KEY_D,
  ]

  # 上で定義した配列を代入し、その中に該当する入力があればTrueを返す
  def is_pressed(key:list[int]) -> bool:
    for k in key:
      if pyxel.btn(k):
        return True
    return False

  #こちらはキーを離した場合のための関数
  def is_released(key:list[int]) -> bool:
    for k in key:
      if pyxel.btnr(k):
        return True
    return False

実際に使ってみる

これをメインのクラスからimportして、呼び出してみます。

main.py
import pyxel
from input_detector import InputDetector as Input

## __init__ などは省略

def update(self):
  if Input.is_pressed(Input.UP):
    print("pressed UP")
  if Input.is_pressed(Input.DOWN):
    print("pressed DOWN")
  if Input.is_released(Input.LEFT):
    print("released LEFT")
  if Input.is_released(Input.RIGHT):
    print("released RIGHT")

キー入力に応じてコンソールに方向が出力されました。

キーの種類が増えたり、変更が必要になった場合にも、input_detector.py内の配列を書き換えたり追加したりすればOKです。ちょっとだけ便利になりました。

脚注
  1. 初学者にも分かりやすく書かれたコードで、Pythonに入門したての自分にはすごく有難いです。 ↩︎

Discussion