mieki256's diary



2017/09/21(木) [n年前の日記]

#1 [pi3d][python][raspberrypi] pi3dでキーボード入力をチェックするあたりがなんとかなったかも

pi3dでキーボード入力をチェックすると、「タッ……タタタタ」となったり、同時押しが検出できなかったりした件について。pi3d.InputEvents を使って、少しはマシになるような処理を書いてみたり。

一応、Windows、Ubuntu Linux 、Raspberry Pi Zero W上で、同じように動くことを確認できた。と言っても、Windowsはpygameを、Linux と Raspberry Pi は pi3d.InputEvents を使うように処理を分けてあるけど。

以下は、Raspberry Pi Zero W 上で撮ったスクリーンショット。ホントは動画で見せないと動きが伝わらないけど、デスクトップを動画としてキャプチャする方法が分からない…。でもまあ、とりあえず、画面が出てることぐらいの証拠にはなる…かな…。ちなみにキャプチャには、 _raspi2png を使った。

get_keyboard3_ss_raspi0.png

以下は、Ubuntu Linux 16.04 実機上で動かした際の様子を動画でキャプチャ。キャプチャには、 _SimpleScreenRecorder を使った。



「タッ……タタタタ」な動きになってないこと、及び、斜め移動ができてる=キーの同時押しを検出できてることぐらいは伝わるかなと。

ソース。 :

以下、WASDキーかカーソルキーで、スプライトを動かすだけのスクリプト。ESCで終了。

_get_keyboard3.py
_airplane_01_64x64.png
u"""
pi3d input keyboard with pygame or InputEvents sample.

Sample script to get keyboard input.
Move the sprite up, down, left and right with WASD key or cursor key.

use pygame.key.get_pressed / pi3d.InputEvents.

Press ESC key to exit.

Windows10 x64 + Python 2.7.12 32bit + pi3d 2.21 + pygame 1.9.3

Author : mieki256
License : CC0
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import pi3d
import pygame


class KeyboardStatus(object):
    u"""Keyboard status."""

    # referenc :
    # pi3d/event/Keys.py
    # https://www.pygame.org/docs/ref/key.html
    keys_list = {
        "KEY_ESC": pygame.K_ESCAPE,
        "KEY_A": pygame.K_a, "KEY_B": pygame.K_b, "KEY_C": pygame.K_c,
        "KEY_D": pygame.K_d, "KEY_E": pygame.K_e, "KEY_F": pygame.K_f,
        "KEY_G": pygame.K_g, "KEY_H": pygame.K_h, "KEY_I": pygame.K_i,
        "KEY_J": pygame.K_j, "KEY_K": pygame.K_k, "KEY_L": pygame.K_l,
        "KEY_M": pygame.K_m, "KEY_N": pygame.K_n, "KEY_O": pygame.K_o,
        "KEY_P": pygame.K_p, "KEY_Q": pygame.K_q, "KEY_R": pygame.K_r,
        "KEY_S": pygame.K_s, "KEY_T": pygame.K_t, "KEY_U": pygame.K_u,
        "KEY_V": pygame.K_v, "KEY_W": pygame.K_w, "KEY_X": pygame.K_x,
        "KEY_Y": pygame.K_y, "KEY_Z": pygame.K_z,
        "KEY_0": pygame.K_0, "KEY_1": pygame.K_1, "KEY_2": pygame.K_2,
        "KEY_3": pygame.K_3, "KEY_4": pygame.K_4, "KEY_5": pygame.K_5,
        "KEY_6": pygame.K_6, "KEY_7": pygame.K_7, "KEY_8": pygame.K_8,
        "KEY_9": pygame.K_9,
        "KEY_UP": pygame.K_UP, "KEY_DOWN": pygame.K_DOWN,
        "KEY_LEFT": pygame.K_LEFT, "KEY_RIGHT": pygame.K_RIGHT,
        "KEY_SPACE": pygame.K_SPACE
    }

    class PygameKeyStatus(object):
        u"""Keyboard status with pygame."""

        def __init__(self):
            """Init."""
            pygame.init()

        def update(self):
            """Update."""
            pygame.event.pump()
            self.keys = pygame.key.get_pressed()
            pygame.event.clear()

        def key_pressed(self, key_str):
            """Get key press state.

            @param key_str key kind string
            @return True or False

            """
            return self.keys[KeyboardStatus.keys_list[key_str]]

        def close(self):
            """Close."""
            pygame.quit()

    class Pi3dInputKeyState(object):
        """Keyboard status width pi3d.InputEvents."""

        def __init__(self):
            """Init."""
            self.inputs = pi3d.InputEvents()

        def update(self):
            """Update."""
            self.inputs.do_input_events()

        def key_pressed(self, key_str):
            """Get key press state.

            @param key_str key kind string
            @return True or False

            """
            return (self.inputs.key_state(key_str) != 0)

        def close(self):
            """Close."""
            pass

    def __init__(self):
        """Init."""
        self.keyboard = pi3d.Keyboard()
        if pi3d.USE_PYGAME:
            self.state = KeyboardStatus.PygameKeyStatus()
        else:
            self.state = KeyboardStatus.Pi3dInputKeyState()

    def update(self):
        """Update."""
        self.pikey = self.keyboard.read()
        self.state.update()

    def key_pressed(self, key_str):
        """Key press check.

        @param key_str key kind
        @return True or False

        """
        return self.state.key_pressed(key_str)

    def esckey_pressed(self):
        """ESC key press check.

        @return True or False

        """
        return (self.pikey == 27 or self.key_pressed("KEY_ESC"))

    def close(self):
        u"""Close."""
        self.keyboard.close()
        self.state.close()


display = pi3d.Display.create(w=640, h=480, frames_per_second=60)
shader = pi3d.Shader("uv_flat")
camera = pi3d.Camera(is_3d=False)

x, y, z = 0.0, 0.0, 20.0
tex = pi3d.Texture("airplane_01_64x64.png", mipmap=False)
spr = pi3d.ImageSprite(tex, shader, w=64, h=64, x=x, y=y, z=z)
display.add_sprites(spr)

inputs = KeyboardStatus()

while display.loop_running():
    inputs.update()

    spd = 6.0

    if inputs.key_pressed("KEY_W") or inputs.key_pressed("KEY_UP"):
        spr.translateY(spd)
    if inputs.key_pressed("KEY_S") or inputs.key_pressed("KEY_DOWN"):
        spr.translateY(-spd)

    if inputs.key_pressed("KEY_A") or inputs.key_pressed("KEY_LEFT"):
        spr.translateX(-spd)
    if inputs.key_pressed("KEY_D") or inputs.key_pressed("KEY_RIGHT"):
        spr.translateX(spd)

    if inputs.esckey_pressed():
        inputs.close()
        display.destroy()
        break

少し説明しておくと…。

pi3d を import して pi3d.Display.create() で初期化をすると、pi3d.USE_PYGAME という変数に値が設定される。pygame を使ってたら True、使ってなかったら False。

なので、その変数を見て、pygame を使ってたら pygame でキーボード情報を取得。pygame を使ってなかったら pi3d.InputEvents でキーボード情報を取得するようなクラスを作成した。

上記のソースでは、KeyboardStatusクラスの中で、pygameを利用するクラスと、pi3d.InputEvents を利用するクラスの2つを用意して、pi3d.USE_PYGAME を見てどちらかを選んでる。

問題点。 :

pygameを利用した場合はコレと言って問題はないのだけど。pi3d.InputEvents を利用した場合は少々問題があって。OSの、キーボード入力やマウス入力を、全部奪ってしまうっぽいのだよな…。なので、以下のような怖い状態に。
  • Ctrl + C を押してもスクリプトが止まってくれない。
  • マウスを動かしてもマウスカーソルが動かないから、ウインドウの閉じるボタンを押せない。
更に、pi3.InputEvents を使うと、pi3d.Keyboard、pi3d.Keyboard.read() が働かなくなるような気がする。

であるから、何かしらのキーを押せばスクリプトが終了するような処理を、必ず、絶対、メインループに入れておかないといけない。それをうっかり忘れてスクリプトを動かしたが最後、デスクトップの操作が一切できなくなるので、電源コンセントを引っこ抜いて強制終了、てなことになる。

てな怖さを考えると…。pi3d が pygame を使えない状態にしてしまう Raspberry Pi上では仕方ないとしても、せめて Linux上で動かすときは、pygame を使って動くスクリプトを書いたほうがいいのでは、と思えたりもして。

ちなみに、pygame を使いたい場合は、pi3d.Display.create() に use_pygame=True を渡せばいい。

_pi3d Package - pi3d 2.21 documentation

pi3d は、現状、以下のような処理をしてる模様。
  • Windows上で動かす場合は、何も指定しなくても pygame が有効になる。
  • Raspberry Pi上で動かす場合は、指定しても pygame が無効になる。
  • Linux上で動かす場合は、指定によって pygame の有効/無効が変わる。

以上です。

過去ログ表示

Prev - 2017/09 - Next
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project