質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

Pygame

Pygameは、ビデオゲームの製作用に設計されたクロスプラットフォームのPythonモジュールセットです。Pythonでコンピューターグラフィックスと音声を扱うためのライブラリが含まれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1604閲覧

キーを押してから図形が動くまでの間に遅延をもたせたい

kappar

総合スコア12

Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

Pygame

Pygameは、ビデオゲームの製作用に設計されたクロスプラットフォームのPythonモジュールセットです。Pythonでコンピューターグラフィックスと音声を扱うためのライブラリが含まれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2020/06/19 02:04

編集2020/06/19 08:14

前提・実現したいこと

pygameを使って、キー押しで図形が動くものを作っています。
キーを押してから図形が動くまでの間に遅延(0.5秒ほど)を設けたいと思っています。

発生している問題・エラーメッセージ

遅延を生じさせる方法がわかりません。
何を使うべきか、ご意見をいただけると幸いです。

エラーメッセージ

該当のソースコード

遅延なしで、キー押しで図形が動くところのコードが以下です。

python

1import pygame 2from pygame.locals import * 3import sys 4import time 5 6start=time.time() 7 8BLACK = (0, 0, 0) 9RED = (255, 0, 0) 10WHITE = (255, 255, 255) 11 12pygame.init() #初期化 13screen = pygame.display.set_mode((640, 500)) #画面サイズ 14myclock = pygame.time.Clock() 15myclock.tick(30) 16pygame.display.flip() 17 18x =320 #circleの初期位置指定 19 20 21while True: 22 time.sleep(0.1) 23 screen.fill(BLACK) 24 pygame.draw.circle(screen, RED, (x, 400), 5) #円 25 pygame.display.update() 26 for event in pygame.event.get(): 27 if event.type==pygame.QUIT: 28 pygame.quit() 29 sys.exit() 30 pressed_key=pygame.key.get_pressed() 31 if (pressed_key[K_LEFT] and x>0): 32 x -= 5 33 if (pressed_key[K_RIGHT] and x<640): 34 x += 5 35 if pressed_key[K_ESCAPE]: 36 pygame.quit() 37 sys.exit() 38 if time.time()-start>120: 39 pygame.quit() 40 sys.exit()

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

遅延を発生させるだけなら pygame.time.delay がありますが、
その間の他の処理(アニメーション描画や入力イベント)が止まってしまう為、
実質、目的の用途には使えません。この場合入力だけが遅延してほしいはずです。

解決策: **優先順位付きキュー (heapq モジュール) **を使いスケジューラーを実装ます。

  • 入力イベントを貯めるキュー(Pythonのリスト)を用意する
  • 入力されたキーと、入力された時の時間 + 遅延時間をキューへ記録 (heappush)

 ※ pygame.time.get_ticks の戻り値の時間で判断する

  • キューにアイテムが有る時(リストが空でない時)

 キューの先頭のアイテムの時間と現在の時間を比較して、
時間が経過していれば、キューからアイテムを取り除き、(heappop)
そのタスクを実行します。

因みに、汎用性を持たせるために優先度付きキューに言及しましたが、
遅延時間が一定(最初に入れられたものが必ず最初に処理される)なら、
優先度~の部分は省けるので、通常のリストを普通に使うだけでも良いです。
(効率的に処理するならリストの代わりに deque についても調べてみて下さい)

queue.PriorityQueue というそのものの実装もあるのですが、
まずは、heapq を使いましょう。heapq モジュールは、データ自体を持たず
list の append, pop の代わりに heappush, heappop を使います。

heapq の使い方を把握した上で、queue.PriorityQueue や
他のスケジューラ関連のソースコードを読むと理解が捗ります。

python

1# 1) while ループの外側で 2delay_inputs = [] 3 4 5# 2) 遅延イベントの処理 while ループ内 6 now = pygame.time.get_ticks() 7 if delay_inputs and delay_inputs[0][0] <= now: 8 _, key_input = heapq.heappop(delay_inputs) 9 if key_input == "left": 10 x -= 5 11 elif key_input == "right": 12 x += 5 13 14# 3) キー入力時 15 pressed_key=pygame.key.get_pressed() 16 if (pressed_key[K_LEFT] and x>0): 17 heapq.heappush(delay_inputs, (now+500, "left")) 18 if (pressed_key[K_RIGHT] and x<640): 19 heapq.heappush(delay_inputs, (now+500, "right")) 20

他の手段: 幾つかありますが、中の実装はどれも同じ(heapq)です
自分で実装するかライブラリに任せるかの違い。

  • pygame.time.set_timer を使う。

→ 繰り返し実行されるので、タイマー解除を忘れずに。
但し、キー入力毎にタイマーを割り当てるのは無駄が多い。

  • pygame.key.key_repeat を使う。

→ 最初のキーを読み飛ばす等の対策が必要。少しトリッキーな方法。

  • asyncio モジュールを使う。call_later

→ pygame/asyncio のループを同時に扱う必要あり。
(他にasyncioのライブラリを使うのでなければ利点なし)

  • threading モジュールを使う。

別スレッド内で sched モジュールを使う。
移動時の変数はスレッド内で書き換えず
pygame.event.post でイベントを送り、必ずメインスレッド側で行う。
そうでない場合はロック等の排他制御が必要です。(コードが複雑になります)
→ キー入力の度に threading.Timer は毎回スレッド生成で無駄が多い

  • pygame zero を導入する

pgzero.clock.schedule(func, delay) で delay ms 秒後に関数実行

※ pygameのみでと言う拘りがなければ、pygame zero 導入が一番簡単です。
が、遅延時間を判定して実行するループが別途必要なので、
この関数だけ借りてくるような事は出来ません。

追記: Pygame Zero 入門

チュートリアルの最後の方に、丁度、0.5秒後に実行するサンプルがあります。


参考資料 (ドキュメントとソースコードへのリンク)
これらの実装は参考になると思います。

投稿2020/06/19 18:57

編集2020/06/20 04:24
teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kappar

2020/06/22 01:51

とても丁寧に教えていただきありがとうございます!! 特に、参考資料でソースコードへのリンクをつけてくださっていたのが非常に助かりました。 先ほど無事にキー押しの遅延が実装できました。本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問