Pygame の Event はメインスレッド以外では取得できない?
あああ、スレッド使って取得すれば長い描画や音声処理の間でも 60fps で入力を取得できると期待してたのに! してたのにぃ!!
というわけでテスト用に作った残骸を晒しておきます。
(Python 2.5 + Pygame 1.8)
from __future__ import division import threading import Queue import pygame from pygame.locals import * FULLSCREEN = False # True にするとフルスクリーン表示 MAIN_FPS = 1 # 秒間描画枚数 EVENT_FPS = 60 # イベント取得間隔 WIDTH, HEIGHT = 640, 480 # 表示する画面のサイズ LINEWIDTH = 3 # 線の太さ BG_COLOR = 127, 127, 127 # 背景色 class PygameEvent(threading.Thread): def __init__(self, **kwds): threading.Thread.__init__(self, **kwds) self.queue = Queue.Queue() self.starttime = pygame.time.get_ticks() self.running = True print 'start' self.start() def run(self): clock = pygame.time.Clock() count = 0 while self.running: count += 1 print count, if pygame.event.get_grab(): now = pygame.time.get_ticks() for event in pygame.event.get(): pygame.display.set_caption( '%d %s' % (now, event)) self.queue.put_nowait((now, event)) clock.tick(EVENT_FPS) def get(self): eventlist = [] try: while True: eventlist.append(self.queue.get_nowait()) except Queue.Empty: pass return eventlist def main(): screen = pygame.display.set_mode( (WIDTH, HEIGHT), (pygame.FULLSCREEN | pygame.HWSURFACE | pygame.DOUBLEBUF) if FULLSCREEN else 0) font = pygame.font.Font(None, 16) clock = pygame.time.Clock() ## pygameevent = PygameEvent() while True: screen.fill(BG_COLOR) for event in pygame.event.get(): time = pygame.time.get_ticks() ## for time, event in pygameevent.get(): if event.type == QUIT: return elif event.type == KEYDOWN and event.key == K_ESCAPE: return elif event.type == MOUSEMOTION: color = [x * 255 for x in event.buttons] x, y = event.pos xr, yr = event.rel pygame.draw.line(screen, color, (x - xr, y - yr), (x, y), LINEWIDTH) screen.blit( font.render('%.3f' % (time / 1000), True, color), event.pos) else: print event pygame.display.flip() clock.tick(MAIN_FPS) if __name__=='__main__': pygame.init() try: main() finally: pygame.quit() # 好きに流用してください。
1 fps 間隔で描画するマウスの動線に取得した時間が付記される、というスクリプト。マウスボタンをカチカチさせながら動かしてみてください。(現状 PygameEvent クラス使わない動作になっていますので取得する時間も 1 fps 間隔)
このスクリプト(というか MOUSEMOTION イベント)フルスクリーンで動かした場合とウィンドウで動かした場合とで動作が違うのでそこらへんも興味深いです。
2009-02-18 Pygame ドキュメントにありました
Pygame handles all it's event messaging through an event queue. The routines in this module help you manage that event queue. The input queue is heavily dependent on the pygame display module. If the display has not been initialized and a video mode not set, the event queue will not really work.
pygame.event — Pygame v1.9.5.dev0 documentation
ディスプレイを管轄しているスレッドでないとイベントは受けられないっぽい。
pygame.mouse 使った実装も試してみたけどやはりダメ*1。「pygame.mouse — Pygame v1.9.5.dev0 documentation」の方の記述でも When the display mode is set, the event queue will start receiving mouse events.
でイベントに依存してるみたいだし。
あきらめてなるたけ処理を細切れにするようにするしかないか。
まあ元々古いタイプの2Dゲームをメインターゲットにしたモジュールだから垂直帰線区間割込み単位で処理が完結するのが前提なんだろうし。無いものねだりかも。
*1:メインスレッドで最後に pygame.event.get なりした時に値がまとめて変わる。これはこれで(pygame.event での状態とずれがなくなるわけだから)便利ではあるけど