ページ 11

vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 11:34
by iguana
ローグライクゲームを作っています。
C++のvectorを使ってアイテムのクラスを動的に生成、イテレータを使って内部の描画関数を呼び出して描画しているのですが、
描画時に何故か時間がかかります。
newを使用してリスト構造を組み、同じように描画した時では、100個ほど生成、描画しても動作が重くならなかったのですが、
vectorを使用すると10個足らずで重くなってしまいます。
都合上vectorを使って作成したいと考えています。
もし解決法を知っていらっしゃる方がおりましたらぜひご教授お願いします。

以下描画部分のみのソース

コード:

static void Draw(){
	VcItem::iterator ItemIterator;


	for (int i = -1; i < DrawMapChipNumY; i++){
		for (int j = -1; j < DrawMapChipNumX; j++){
                        //画面内にあるものだけを描画
			if (j + DrawPointX < 0 || i + DrawPointY < 0 ||
				j + DrawPointX >= MAP_WIDTH || i + DrawPointY >= MAP_HEIGHT) continue;
             //MapDraw
			/*マップチップの描画*/


			ItemIterator = vcItem.begin();
			while (ItemIterator != vcItem.end()){
				//アイテムの描画関数を呼び出し
                ItemIterator->Draw(i, j);

				ItemIterator++;
			}
			

		}
	}
}

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 12:52
by iguana
追記
VcItem, vcItem

typedef vector<Item> VcItem;
VcItem vcItem;
で定義されています
Itemはアイテムの座標、描画関数などの要素を含むクラスです

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 14:46
by かずま
動作が重くなったとという質問なら、
具体的な数値の提示が必要だと思います。

sizeof(Item) はいくつですか?
DrawMapChipNumX と DrawMapChipNumY はいくつですか?

生成は、
Item *p = new Item; vcItem.push_back(*p);
のようなものですか?

vcItem.size() が 10 ということですか?
生成にかかる時間は何ミリ秒ですか?
Draw() の実行時間は何ミリ秒ですか?
Item.Draw(i, j) が呼び出される回数は、
DrawMapChipNumX * DrawMapChipNumY * vcItem.size()
ということですよね。

生成と描画を繰り返しているということはありませんか?

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 15:01
by softya(ソフト屋)
MAP_WIDTH * MAP_HEIGHT * vcItem.size() 回はvcItemのDrawメソッドを呼ぶと思いますが、多すぎたりはしないのでしょうか? 無駄に感じるのですが。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 15:41
by iguana
情報不足でした申し訳ありません。
数値を示します。

//クラスItemの大きさ
sizeof(Item) : 20byte
//描画するマップチップの数
DrawMapChipNumX : 13
DrawMapChipNumY : 10

//生成

コード:

iGenerateNum = 10;

for (int i = 0; i < iGenerateNum; i++){
	vcItem.push_back(Item());
}
生成、描画にかかる時間は計測していませんが、
生成は一瞬で終わるため問題ありません。
また生成を100個ほどしても、描画さえしなければゲームが重くなることはないので生成は問題ありません。

呼び出される回数は仰るとおりです。
i, jとアイテムのX, Y座標が一致した場合に描画されます。
生成、描画は状態遷移プログラムにて場所がわかれているので繰り返されているということはありません。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 15:47
by softya(ソフト屋)
iguanaさんの思い込み・勘違い等が、このコードだけでは検証できません。
つまり、こちらでは確認しようがないので、iguanaさんに時間を実測してもらうしか方法がないようです。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 16:13
by へにっくす
iguana さんが書きました:生成、描画にかかる時間は計測していませんが、
生成は一瞬で終わるため問題ありません。
かずまさんが、具体的な計測値を出して、とレスしているのに、見当はずれな回答をしてますね。
仕事であれば、「じゃ勝手にすれば」と干されますよ。
時間の計測ってどうやるの?と聞けばまだいいんですけどね。

それぞれ怪しいと思う箇所の最初と最後にGetTickCount関数でもかましておいて、その差分を出してみてはどうでしょう?

コード:

int tmp = GetTickCount(); // 開始チックを保持
for (int i = 0; i < iGenerateNum; i++){
    vcItem.push_back(Item());
}
printf("生成:%d", GetTickCount() - tmp); // かかった時間を表示(msec単位)

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 16:43
by iguana
見当違いな解答申し訳ありませんでした

描画に関しては、
10体生成時 : 16ms
100体生成時 : 47ms

でした。


生成に関しては、精度が悪いのか
両方の場合で0と表示されてしまいました。
もっと正確に測定する方法はあるのでしょうか?

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 16:55
by へにっくす
iguana さんが書きました:描画に関しては、
10体生成時 : 16ms
100体生成時 : 47ms
では、newした場合と、vectorを使った場合とで計測してみてください。
iguana さんが書きました:生成に関しては、精度が悪いのか
両方の場合で0と表示されてしまいました。
もっと正確に測定する方法はあるのでしょうか?
いえ、ふつうはそこまで精度を上げることはしません。
時間がかかるところを特定したいのですよね?
その意味では、生成に関しては問題なさそうですね。
まあ生成に関する時間を調べたいのであれば、
たくさん生成してみて、その総合時間で一つ当たりの生成時間を割り出す方法が使えます。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 17:05
by iguana
先ほど上げた数値がvectorを使った時の数値です。

newを使った場合の描画は
10個生成時、100個生成時ともに、ごくたまに5, 6の文字がちらつくものの基本的に0から変動しませんでした。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 17:07
by へにっくす
iguana さんが書きました:先ほど上げた数値がvectorを使った時の数値です。

newを使った場合の描画は
10個生成時、100個生成時ともに、ごくたまに5, 6の文字がちらつくものの基本的に0から変動しませんでした。
んーそうですか。
もしかして1秒(=1000msec)以上かかるってことではない、ということでよろしい?
(個人的には問題ないと思ってるんですけどね)
目に見えて遅いということでしたら、その根拠を示してほしいですね。

【編集】書きなおしてたら、すでにレスされていたので元の文面に戻しました。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 17:16
by iguana
目に見えて遅くなりますね。
フレームレートを表示させると、20~30前後の値になります。

個人的に考える原因としては、イテレータを進める処理がnew使用時のポインタを進める処理より時間がかかっているということ、です。
描画回数を減らす新たなループを考えついたので、一応解決とさせていただきます。

ご回答くださった皆さん、大変有難うございました。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 17:17
by たいちう
コンパイラは何を使っていますか?
コンパイルオプションは?
特に速度に関する最適化について。

例えばVC++のデバッグモードとかだと、デバッグ用に色々とチェックが入り、
newだと一瞬で、vectorだと数10ミリ秒とか、ありえるかと。
その場合、最終的には最適化してコンパイルすれば問題ないですよね?

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 17:21
by softya(ソフト屋)
たいちう さんが書きました:コンパイラは何を使っていますか?
コンパイルオプションは?
特に速度に関する最適化について。

例えばVC++のデバッグモードとかだと、デバッグ用に色々とチェックが入り、
newだと一瞬で、vectorだと数10ミリ秒とか、ありえるかと。
その場合、最終的には最適化してコンパイルすれば問題ないですよね?
それにしても遅く感じるので、iguanaさんがなにかミスをしている可能性は捨て切れません。
コードを提示してもらえない以上は、ご自身で解決するしか無いわけですが、Drawを除いて計測していないのでイテレータが遅いと断言したのが本当であるか疑問が残る所です。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 17:28
by へにっくす
iguana さんが書きました:目に見えて遅くなりますね。
フレームレートを表示させると、20~30前後の値になります。
問題ないと書きましたが、
60fpsでやろうとするなら、1000/60=16.7msecなので、やっぱ問題アリです。
10体生成時の描画で16msなのですから。
Draw関数の内容を掲示した方がいいですよ。
(newとvectorしたときのそれぞれのDraw関数に差分がないのであれば、その旨書いてほしかったですね)

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 18:16
by iguana
コンパイラはvisual studio 2013で環境も特にいじっていないので初期設定かと。

コンパイルオプションとはどのように設定するものなのでしょうか

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 18:25
by iguana
Draw関数につきまして、
非常に効率の悪い書き方をしていたため、
新しく考えたループに書き換えたところ100個生成しても問題なく動作するようになりました。

改めて、ご協力くださった方々本当に感謝を申し上げます。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 19:35
by たいちう
> コンパイラはvisual studio 2013で環境も特にいじっていないので初期設定かと。
>
> コンパイルオプションとはどのように設定するものなのでしょうか

2013は使ったことないけど、多分プロジェクトのプロパティで細かく設定できます。
大雑把な設定のまとめが、デバッグモードとリリースモードなのですが、
その違いを知らなくて、初期設定のままならデバッグモードなのでしょう。

デバッグ時に有用な情報を提供してくれる替わりに、実行速度などが犠牲になっています。
速い遅いの話をするときに、デバッグモードでは見当違いなのです。
2つのモードのボトルネックの場所が違う場合も多いので。

ちなみに私の手元のVC2008の場合は、メニューの「ビルド」の「構成マネージャ」で、
「アクティブソリューション構成」で切り替えることで変更できます。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 19:59
by softya(ソフト屋)
同じような問題に悩んだ人のために、イテレータの回数が問題であったのか、それともDraw中のループなどが問題であったのかだけははっきり記載して頂けますか。

>非常に効率の悪い書き方をしていたため、
ここをもう少し細かくお願いします。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 20:52
by iguana
なぜnewと同じ構文で遅延が発生したのかは不明です。

最初におっしゃられたように、
MAP_WIDTH * MAP_HEIGHT * vcItem.size()回のループを回していたものを、
描画関数内に描画場所を直接書き込む事により
vcItem.size()回だけで良くなりました。

Re: vectorによって動的に作成されたオブジェクトの描画

Posted: 2014年3月30日(日) 21:43
by softya(ソフト屋)
iguana さんが書きました:なぜnewと同じ構文で遅延が発生したのかは不明です。

最初におっしゃられたように、
MAP_WIDTH * MAP_HEIGHT * vcItem.size()回のループを回していたものを、
描画関数内に描画場所を直接書き込む事により
vcItem.size()回だけで良くなりました。
無駄を無くしたので、解決したということですね。
イテレータの問題であると言う話はどうなったのでしょうか?
返答で分かることはループが13*10*100回=13000回から100回になったら余裕で間に合うようになったと言うことです。
イテレータなのかDraw側なのか、あるいは両方なのかは不明のままって事ですね。