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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

1093閲覧

開発中のゲームのpause機能が不安定

ddd8

総合スコア19

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/07/10 13:41

編集2020/07/11 17:43

c++で本(ゲームプログラミングC++)を参考にPongゲームを作っています。

プログラムに一時停止のpause機能を実装したのですが、その挙動が不安定です。

キーボードPを押すとmIsPoseのフラグを立つようにし、trueの時はGameの更新処理を行わないようにしました。

しかし、ゲームを実行してPを押すと停止するのですがしない時もあり不安定です。

pause処理を安定させたいのですが、原因とよい解決方法が思いつかずにいます。
何か良い方法があれば教えていただきたいです。

以下、コードです。(省略部分あり)

// 省略 void Game::RunLoop() { while (mIsRunning) { ProcessInput(); if (!mIsPose) UpdateGame(); GenerateOutput(); } } void Game::ProcessInput() { SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { // If we get an SDL_QUIT event, end loop case SDL_QUIT: mIsRunning = false; break; } } // Get state of keyboard const Uint8* state = SDL_GetKeyboardState(NULL); // If escape is pressed, also end loop if (state[SDL_SCANCODE_ESCAPE]) { mIsRunning = false; } if (state[SDL_SCANCODE_P]) { mIsPose = !mIsPose; } // Update paddle direction based on W/S keys mPaddleDir = 0; if (state[SDL_SCANCODE_W]) { mPaddleDir -= 1; } if (state[SDL_SCANCODE_S]) { mPaddleDir += 1; } // Update paddle direction based on W/S keys mPaddleDir2 = 0; if (state[SDL_SCANCODE_I]) { mPaddleDir2 -= 1; } if (state[SDL_SCANCODE_K]) { mPaddleDir2 += 1; } } void Game::UpdateGame() { // Wait until 16ms has elapsed since last frame while (!SDL_TICKS_PASSED(SDL_GetTicks(), mTicksCount + 16)) ; // Delta time is the difference in ticks from last frame // (converted to seconds) float deltaTime = (SDL_GetTicks() - mTicksCount) / 1000.0f; // Clamp maximum delta time value if (deltaTime > 0.05f) { deltaTime = 0.05f; } // 省略 void Game::GenerateOutput() { // Set draw color to right blue SDL_SetRenderDrawColor( mRenderer, 0, // R 0, // G 0, // B 255 // A ); // Clear back buffer SDL_RenderClear(mRenderer); // Draw walls SDL_SetRenderDrawColor(mRenderer, 255, 255, 255, 255); // Draw top wall SDL_Rect wall{ 0, // Top left x 0, // Top left y windowW, // Width thickness // Height }; SDL_RenderFillRect(mRenderer, &wall); // Draw bottom wall wall.y = windowH - thickness; SDL_RenderFillRect(mRenderer, &wall); // Draw right wall //wall.x = windowW - thickness; //wall.y = 0; //wall.w = thickness; //wall.h = windowW; //SDL_RenderFillRect(mRenderer, &wall); // Draw paddle SDL_Rect paddle{ static_cast<int>(mPaddlePos.x), static_cast<int>(mPaddlePos.y - paddleH/2), thickness, static_cast<int>(paddleH) }; SDL_RenderFillRect(mRenderer, &paddle); SDL_Rect paddle2{ static_cast<int>(mPaddlePos2.x), static_cast<int>(mPaddlePos2.y - paddleH / 2), thickness, static_cast<int>(paddleH) }; SDL_RenderFillRect(mRenderer, &paddle2); // Draw ball for (auto& b : mBalls) { SDL_Rect ball{ static_cast<int>(b.pos.x - thickness/2), static_cast<int>(b.pos.y - thickness/2), thickness, thickness }; SDL_RenderFillRect(mRenderer, &ball); } // Swap front buffer and back buffer SDL_RenderPresent(mRenderer); } void Game::Shutdown() { SDL_DestroyRenderer(mRenderer); SDL_DestroyWindow(mWindow); SDL_Quit(); }

解決できました

ありがとうございます。皆様のアドバイスにより解決できました。

Daregadaさんのアドバイスに倣い、
トグル動作を一旦辞め、処理を分けてみたところ安定しました。

そこで、前フレームのキー状態を保存し、トグル処理実行の条件に前フレームのチェックを
加えたコードにしてみたところ安定して動作することが確認できました。

以下解決したコード(thkanaさんのコードを参考にしました。)

c++

1 if (!mPrevPState && state[SDL_SCANCODE_P]) 2 { 3 mIsPose = !mIsPose; 4 } 5 mPrevPState = state[SDL_SCANCODE_P];

ベストアンサーは御三方ともほぼ同じ趣旨の内容と思いますので、最も早く回答して頂いたDaregadaさんに致しました。

皆様、ありがとうございました。

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

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

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

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

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

guest

回答3

0

キーが「押されている」ことを検出していると、キーが押されている間はずっと、何度でも、検出されてトグルを繰り返すことになります。
キーが「押された」ことを知りたいのなら、そういうAPIがあるのならそれを使えばいいですが、「直前までは押されていなかったが、今は押されている」というようなロジックを組む必要があるでしょう。
例えば、

C++

1static Uint8 prevPState=0; 2if ( !prevPState && state[SDL_SCANCODE_P]){ 3//キーが「押された」処理 4} 5prevPState=state[SDL_SCANCODE_P];

とか。

組み込み屋視点だとスイッチのチャタリング(過渡的に接点がくっついたりはなれたりする現象)も気にするところですが、PCではその辺の対処はされた後のキーボード状態が得られるものと考えてもよい...のかな?

投稿2020/07/10 23:57

thkana

総合スコア7639

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

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

0

とりあえず、トグル動作をやめて、mIsPose = true;にするキー(現在のPのまま)と、mIsPose = false;にするキー(何か適当なキーを割り当てる)に処理を分けてみてください。

これでポーズ(およびポーズ解除)が安定するなら、Pキーを押している間にProcessInputが何度も呼ばれて、そのたびにmIsPoseの値が反転しているのが不安定な原因です。

投稿2020/07/10 17:39

Daregada

総合スコア11990

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

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

0

ベストアンサー

キーが押しっぱなしの場合、毎フレームON/OFFが切り替わっていませんか?
フレーム間隔が短ければ、キーを離すタイミングは相当シビアになります。
不安定な原因がそうであれば、
前フレームのキー状態を保存しておいて、前フレームは押されていないが、
現在のフレームでは押されている場合のみポーズフラグを切り替えるとうまくいくと思います。

投稿2020/07/10 14:29

ameagari_hare

総合スコア39

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問