🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

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

Q&A

解決済

2回答

1354閲覧

二重for文の突然動作がものすごく重たくなる原因とは? 計算量について

退会済みユーザー

退会済みユーザー

総合スコア0

C++

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

0グッド

1クリップ

投稿2021/01/30 01:34

編集2021/01/30 02:29

提示コードですがPlayer::Update()関数のコメント部の内部のコードのスペースボタンを押して弾を発してGameクラスのGame::Update()関数部のコメント部の内部のコードに移動すると動作が極端に重たくなります。Game::Update();関数部のコメント部内部のコードはなぜ重たくなるのでしょうか?

質問内容「 Game::Update();関数部のコメント部内部のコードをコメントアウトすると正常に動作しますがこのコードの何が悪いのか知りたです。

質問内容「 スペック内容を除いて 動作が極端に重くなる原因として考えてられるものが何か知りたい。 」

PCスペック的にも物凄く重くなるとはどうしても考えにくいです。

OS: Windows10
CPU: i78 3390
メモリ 8GB

cpp

1 2// 計算 3void Player::Update() 4{ 5 // キー入力 6 mSpeed = SPEED; 7 if (mInput->KeyDownHold(GLFW_KEY_LEFT) == true) 8 { 9 mVector.x = -1.0f; 10 mVector.y = 0.0f; 11 mKeyCode = Key_Code::Left; 12 } 13 else if (mInput->KeyDownHold(GLFW_KEY_RIGHT) == true) 14 { 15 mVector.x = 1.0f; 16 mVector.y = 0.0f; 17 mKeyCode = Key_Code::Right; 18 19 } 20 else if (mInput->KeyDownHold(GLFW_KEY_UP) == true) 21 { 22 mVector.x = 0.0f; 23 mVector.y = 1.0f; 24 mKeyCode = Key_Code::Up; 25 26 } 27 else if (mInput->KeyDownHold(GLFW_KEY_DOWN) == true) 28 { 29 mVector.x = 0.0f; 30 mVector.y = -1.0f; 31 mKeyCode = Key_Code::Down; 32 33 } 34 else { 35 mSpeed = 0; 36 } 37///////////////////////////////////////////////////////////////////////////// 38 // 攻撃 39 if (mInput->KeyDown(GLFW_KEY_SPACE) == true) 40 { 41 bullet.push_back(Bullet(Owner, mPosition, mVector)); 42 } 43///////////////////////////////////////////////////////////////////////////// 44 45 // 弾 更新 46 for (std::vector<Bullet>::iterator itr = bullet.begin(); itr != bullet.end(); ) 47 { 48 // 画面の外に出たら削除 49 if (itr->getPosition().x > Owner->getWindowSize().x) 50 { 51 itr = bullet.erase(itr); 52 }else if (itr->getPosition().x < -Owner->getWindowSize().x / 2) 53 { 54 itr = bullet.erase(itr); 55 } 56 else if (itr->getPosition().y < -Owner->getWindowSize().y / 2) 57 { 58 itr = bullet.erase(itr); 59 } 60 else if (itr->getPosition().y > Owner->getWindowSize().y / 2) 61 { 62 itr = bullet.erase(itr); 63 } 64 else 65 { 66 itr->Update(); 67 itr++; 68 } 69 } 70 71 72// printf("size: %d\n",bullet.size()); 73 74 75 mPosition += mVector * (int)mSpeed; //実移動 76 mCol.Update(mPosition,glm::ivec2(CELL -1,CELL -1)); //当たり判定を更新 77 78} 79

cpp

1 2//アップデート 3void Game::Update() 4{ 5 player->Update(); 6 stage->Update(); 7 8 9 //ステージと自分の当たり判定 10 for (int i = 0; i < CELL_WIDTH * CELL_HEIGHT; i++) 11 { 12 // 当たり判定 13 if (Intersect_2D(player->mCol, stage->getMap().at(i).mCol) == true) 14 { 15 player->FixPos(stage->getMap().at(i).mCol.getPosition()); 16 // printf("Collision !\n"); 17 } 18 } 19 20 21/////////////////////////////////////////////////////////////////////////////////////// 22 //ステージと自分の弾との判定 23 for (int i = 0; i < CELL_WIDTH * CELL_HEIGHT; i++) 24 { 25 for (int b = 0; b < player->getBullet().size(); b++) { 26 // 当たり判定 27 if (Intersect_2D(player->getBullet().at(b).mCol, stage->getMap().at(i).mCol) == true) 28 { 29 //player->FixPos(stage->getMap().at(i).mCol.getPosition()); 30 printf("Collision !\n"); 31 } 32 } 33 } 34//////////////////////////////////////////////////////////////////////////////////////// 35 36 37 38 KeyInput(); //キー入力 39} 40

cpp

1#include "../Header/Fps.hpp" 2 3int Fps::mCount = 0; 4 5 6Fps::Fps() { 7 glfwSetTime(0.0); 8 9 mStartTime = 0; 10 mFps = 0; 11 } 12 13void Fps::Update() { 14 15 if (mCount == 0) { //1フレーム目なら時刻を記憶 16 mStartTime = GetTime(); 17 } 18 if (mCount == N) { //60フレーム目なら平均を計算する 19 // printf("60FPS !\n"); 20 int t = GetTime(); 21 mFps = 1000.f / ((t - mStartTime) / (float)N); 22 23 mCount = 0; 24 mStartTime = t; 25 } 26 mCount++; 27} 28 29 30 31void Fps::Wait() { 32 33 float tookTime = GetTime() - mStartTime; //かかった時間 34// printf("tookTime: %f\n", tookTime); 35// printf("(mCount * 1000.0f / FPS): %f\n", (mCount * 1000.0f / FPS)); 36 float waitTime = (mCount * 1000.0f / FPS) - tookTime; //待つべき時間 37 38 39 40 float f = waitTime * 1000; 41 std::chrono::milliseconds dura((int)f); 42 43 44 45 glfwSetTime(0.0); 46} 47 48int Fps::getFrameRate() 49{ 50 return mCount; 51} 52 53 54 55float Fps::GetTime() 56{ 57 return (float)glfwGetTime() * 1000.0f; 58 // return (float)glfwGetTime(); 59} 60

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

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

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

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

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

Zuishin

2021/01/30 03:32

> PCスペック的にも物凄く重くなるとはどうしても考えにくいです。 なぜ考えにくいのか説明してください。どんなスペックのコンピューターを使おうが、その性能を超えるプログラムを書くのは可能です。
guest

回答2

0

ベストアンサー

二重のfor文になっているところのCELL_WIDTH * CELL_HEIGHTplayer->getBullet().size()がどのぐらいの値をとるのか分からないのでなんとも言えませんが、C++の場合、1秒で計算できるのは、ループ内の処理がかなり単純であったとしても、10^8ぐらいのオーダーまでです。

60fpsで動くようにしたいのであれば、フレームあたりの処理は最大でも10^6ぐらいのオーダーになるようにする必要があると思います。

投稿2021/01/30 02:57

Amakaze

総合スコア313

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

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

退会済みユーザー

退会済みユーザー

2021/01/30 03:39

22 * 11 のfor文ですがstd::shared_ptrを使って参照するよにプログラムを変更したら治りました。
int32_t

2021/01/30 07:22

何をstd::shared_ptrにしたのでしょうか? その解決策とこの回答は関係あるのでしょうか?
退会済みユーザー

退会済みユーザー

2021/01/30 11:03

すいませんでした。
int32_t

2021/01/31 15:47

謝るのではなくて事実を説明しましょう。
退会済みユーザー

退会済みユーザー

2021/02/01 08:00

バッファオーバーラン的なものを推測しました。
guest

0

なにかのゲームのプログラムなのだと思われます。

問題の箇所(下記)のコードは、外側のforループで、画面の全てのセルについて当たり判定をして、当たっていたら"Collision !\n"と表示をするようになっています。

/////////////////////////////////////////////////////////////////////////////////////// //ステージと自分の弾との判定 for (int i = 0; i < CELL_WIDTH * CELL_HEIGHT; i++) { for (int b = 0; b < player->getBullet().size(); b++) { // 当たり判定 if (Intersect_2D(player->getBullet().at(b).mCol, stage->getMap().at(i).mCol) == true) { //player->FixPos(stage->getMap().at(i).mCol.getPosition()); printf("Collision !\n"); } } } ////////////////////////////////////////////////////////////////////////////////////////

「当たり」が画面の複数の箇所(セル)で同時に起きる可能性があり、そのすべてについて"Collision !\n"を表示しなくてはならない事情があるなら仕方ありませんが、「当たり」が起きるのが高々1か所なのであれば、「当たり」が見つかった時点でforループを終わらせることで、実行時間は短くなります。

例えば、以下の様に修正してみては如何でしょうか?

/////////////////////////////////////////////////////////////////////////////////////// collision=0; // 既に当たりと判定した(1)か、否(0)かの変数。 //ステージと自分の弾との判定 for (int i = 0; (i < CELL_WIDTH * CELL_HEIGHT) && (collision==0); i++) //まだ当たっていない時だけ、forループを継続する。 { a_mcol = stage->getMap().at(i).mCol; // 内側のforループの中で、毎回 stage->getMap().at(i).mCol を計算するのは無駄なので、ループの外で計算しておく。 for (int b = 0; b < player->getBullet().size(); b++) { // 当たり判定 if (Intersect_2D(player->getBullet().at(b).mCol, a_mcol) == true) { //player->FixPos(stage->getMap().at(i).mCol.getPosition()); printf("Collision !\n"); collison=1; // 「当たり」 } } } ////////////////////////////////////////////////////////////////////////////////////////

投稿2021/01/30 04:12

fumu7

総合スコア121

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問