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

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

新規登録して質問してみよう
ただいま回答率
85.37%
Pygame

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

Python

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

Q&A

1回答

271閲覧

pythonでのアケコンの入力フレームとスト6内のフレームのずれ

4rsenal

総合スコア0

Pygame

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

Python

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

0グッド

0クリップ

投稿2024/07/15 04:29

実現したいこと

スト6のコンボ練習用にどの行動が何フレーム遅いかなどを調べるプログラムの作成をしたい。

発生している問題・分からないこと

発生している問題は!
イメージ説明
このようにゲーム内のフレームとプログラム内のフレームに誤差が発生することです。
原因か修正方法があれば知りたいです。

該当のソースコード

python

1import pygame 2import time 3 4# Pygameの初期化 5pygame.init() 6pygame.joystick.init() 7 8# ジョイスティックの初期化 9joystick = pygame.joystick.Joystick(0) 10joystick.init() 11 12print(f"コントローラー名: {joystick.get_name()}") 13 14# 前回の入力状態を保存する変数 15previous_button_states = [0] * joystick.get_numbuttons() 16previous_axis_states = [0.0] * joystick.get_numaxes() 17button_press_start_frame = [-1] * joystick.get_numbuttons() 18button_press_start_time = [-1] * joystick.get_numbuttons() 19axis_move_start_frame = -1 20axis_move_start_time = -1 21current_frame = 0 22current_direction = "中立" 23frame_time_ns = 1_000_000_000 / 60 # 1フレームは1/60秒 24 25# Pygameの時計 26clock = pygame.time.Clock() 27 28# 方向の記号を取得する関数 29def get_direction(x, y): 30 if y < -0.5: 31 if x < -0.5: 32 return "↖" 33 elif x > 0.5: 34 return "↗" 35 else: 36 return "↑" 37 elif y > 0.5: 38 if x < -0.5: 39 return "↙" 40 elif x > 0.5: 41 return "↘" 42 else: 43 return "↓" 44 else: 45 if x < -0.5: 46 return "←" 47 elif x > 0.5: 48 return "→" 49 else: 50 return "中立" 51 52# ボタンと軸の状態をチェックする関数 53def check_joystick_input(): 54 global previous_button_states, previous_axis_states, button_press_start_frame, button_press_start_time 55 global axis_move_start_frame, axis_move_start_time, current_frame, current_direction 56 pygame.event.pump() # 入力状態を更新 57 58 # ボタンの状態を取得 59 for i in range(joystick.get_numbuttons()): 60 button_state = joystick.get_button(i) 61 if button_state != previous_button_states[i]: 62 if button_state: 63 button_press_start_frame[i] = current_frame # ボタンが押された瞬間のフレームを記録 64 button_press_start_time[i] = time.perf_counter_ns() # ボタンが押された瞬間の時間を記録 65 print(f"ボタン {i} が押されました") 66 else: 67 press_duration_ns = time.perf_counter_ns() - button_press_start_time[i] # 押されていた時間(ナノ秒)を計算 68 press_duration_seconds = press_duration_ns / 1_000_000_000 # 秒に変換 69 press_duration_frames = round(press_duration_seconds / (1 / 60)) # 秒から1/60秒のフレーム数に変換 70 button_press_start_frame[i] = -1 71 button_press_start_time[i] = -1 72 print(f"ボタン {i} が離されました - 押されていた時間: {press_duration_frames}F ({press_duration_seconds:.5f}秒)") 73 previous_button_states[i] = button_state 74 75 # 軸の状態を取得 76 x_axis = joystick.get_axis(0) 77 y_axis = joystick.get_axis(1) 78 direction = get_direction(x_axis, y_axis) 79 80 if direction != current_direction: 81 if current_direction != "中立": 82 duration_ns = time.perf_counter_ns() - axis_move_start_time 83 duration_seconds = duration_ns / 1_000_000_000 # 秒に変換 84 duration_frames = round(duration_seconds / (1 / 60)) # 秒から1/60秒のフレーム数に変換 85 print(f"{current_direction} {duration_frames}F ({duration_seconds:.5f}秒)") 86 current_direction = direction 87 axis_move_start_frame = current_frame 88 axis_move_start_time = time.perf_counter_ns() 89 90 previous_axis_states[0] = x_axis 91 previous_axis_states[1] = y_axis 92 93# メインループ 94running = True 95start_time_ns = time.perf_counter_ns() 96while running: 97 for event in pygame.event.get(): 98 if event.type == pygame.QUIT: 99 running = False 100 101 check_joystick_input() 102 current_frame = int((time.perf_counter_ns() - start_time_ns) / frame_time_ns) # フレーム数をリアルタイムに計算 103 104 clock.tick(60) # 毎秒60フレームに設定 105 106pygame.quit() 107

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

chatgptでのコードの変更をためしたがうまくいかなかった。

補足

特になし

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

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

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

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

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

guest

回答1

0

おそらく以下のコードが4rsenalさんの想定通り動いていないためと思います。

python

1clock.tick(60) # 毎秒60フレームに設定

公式のドキュメントに記載されているように2点の懸念点があります。

Clock.tick()はそれほど精度が高いわけではありません。

https://www.pygame.org/docs/ref/time.html?highlight=clock#pygame.time.Clock.tick

Note that this function uses SDL_Delay function which is not accurate on every platform, but does not use much CPU. Use tick_busy_loop if you want an accurate timer, and don't mind chewing CPU.

回避策として公式ドキュメントではClock.tick_busy_loop()を使うことをお勧めしていますね。
CPUの使用率が跳ねあがるので、ゲーム側に影響が出てしまうかもしれませんが、やってみる価値はあると思います。

Clock.tick()は「指定されたFPSよりも高くならないようにする」という指定でしかありません。

By calling Clock.tick(40) once per frame, the program will never run at more than 40 frames per second.

これも公式ドキュメントに書いてある通り、60fpsを指定しても「60fpsを上回らないようにする」だけで、55fpsや50fpsになってしまう可能性もあります。

例えば97行目から102行目までの処理がたまたま16msecかかる場合があると Clock.tick()で60fpsを指定しても、実質数フレーム遅れてしまうことになります。
もしそうだった場合には、コードを高速化してなるべく短い時間で処理が終わるようにする必要があります。場合によってはPythonよりも高速に動作するプログラミング言語を採用しないといけなくなってしまいます。

投稿2024/07/20 18:51

toge_

総合スコア226

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問