トップページ > 過去ログ > 記事閲覧
戦車や船などの走った跡
名前:M 日時: 2009/02/05 13:06

戦車や船などに限った話ではないのですが、 現在、戦車の進んだ跡や船のたてた波を画面に描画しようと考えています。 (トップビュー2Dです。) 私が思いついた方法は、戦車の場合、 ある程度進むごとに、元いた場所の座標と角度を保存したクラスオブジェクトをつくり、 deque(グローバル変数)にそれを入れて、毎フレームdequeにあるすべての情報に基づいて描画する方法です。 画像は、20×5ぐらいで、非常に短いものですが、これがたくさんdequeによって連続で描画されるため、ひと繋がりに見えるということです。 画像には縦に二本のキャタピラの跡が描かれています。 ですが、戦車と比べるとマップは広大であるため これを大量に保存する必要ができてしまいます。 するとやや重くなってきてします。 保存する数を減らすために画像の縦幅を長くすると、 今度は作られた跡がかくかくしてしまいます。 (戦車は移動しますし、車体の角度も変えます。) 座標のみ保存して点と点を繋いでいくのも考えましたが、画像をその線に沿って描画できる方法も思いつきません。 (PhotoShop のペンツールのような表現ができればいいのですが…) 現状では非常に遅いわけではありませんが、700個あたりから気になるぐらいの処理落ちがでてきてしまいます。 700個もあれば、やりくりできるとは思うのですが、もっと良い方法がありましたらご提案お願いします。

Page: 1 |

Re: 戦車や船などの走った跡 ( No.1 )
名前:さかな 日時:2009/02/05 17:02

MakeGraph等で作ったハンドルにどんどん上書きしていけばいいのではないでしょうか?
× ( No.2 )
名前:M 日時:2009/02/07 06:25

<編集しました。> 似たスレッドかあり目的の関数が見つかりました。 しかし失敗しました。 =以下コピペ= int SubScreen; SetDrawValidGraphCreateFlag( TRUE ); SubScreen = MakeGraph( 640, 480 ); SetDrawValidGraphCreateFlag( FALSE );  こうして作成した画像ハンドルは SetDrawScreen で描画先とすることが出来ます。 SetDrawScreen( SubScreen ); //コピペここまで ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=past&no=387 より、管理人様の返信のコピー&ペーストです。 解決はしていません。(↓のスレッドに続きます。)
解決していませんでしたorz ( No.3 )
名前:M 日時:2009/02/07 06:52

以下のコードとまったく同じ効果を違う方法で得たいのですが、上手く行きません。 #include "DxLib.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){ ChangeWindowMode(TRUE);//ウィンドウモード if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化 int SubScreen; SetDrawValidGraphCreateFlag( TRUE ); SubScreen = MakeGraph(800,640); SetDrawValidGraphCreateFlag( FALSE ); while(ProcessMessage()==0){ SetDrawScreen( SubScreen ); DrawString(0,0,"dsa",GetColor(0,0,255)); SetDrawScreen(DX_SCREEN_BACK ); DrawGraph(0,0,SubScreen,true); ScreenFlip(); } DxLib_End(); return 0; } //↑このコードでは、期待通りの働きをしてくれます。(後述で例外を指摘します。) 何より一番の問題は・・・ ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=past&no=387 より、管理人様の返信にある、  「ただ、この機能は他の機能に比べて正常に動作するグラフィックチップの 敷居が高いので、余りお勧めできません。」 ということです。 これが、もし1%や2%などのPCにしか当てはまらないのならば、余り気にしないのですが… 実際のところ、どの程度のPCは正常に動作できないのかが分からないので、他の方法を探している次第です。 どのグラフィックカード(チップ?)でも大抵は正常に表示できるようにしたいのです。 この正常に動かない可能性を踏まえて、それを妥協した場合ですが、 上記のコードの MakeGraph(int,int) で、少なくとも私の環境ではなぜか intの値を5000などと大きくすると、上記の描画時にウィンドウではなく、 スクリーン全体の左上を0,0として描画されてしまいます。 例えば、ゲームしかウィンドウを開いていなかった場合、ゲームをウィンドウモードで表示しているにも関わらず、デスクトップ左上に描画されているような感じです。 また、MakeGraph の代わりに LoadGraphも試みましたが、画像が800×5120と大きいためか、 これも上記と同じ症状です。  ・「なぜそんなに大きくしたいのか?」 私は背景が縦にスクロールされるタイプのゲームを作成していて、 戦車などのオブジェクトは背景を無視してウィンドウ左上を0,0として座標を保存しているため、 戦車の跡などは、背景画像に直接、書き込むのが一番楽だと思ったのですが、 どうもその背景が大きすぎるためか、上記の方法では上手くいきませんでした。 ちなみに画像は、(800,5120) のjpg 150kb です。 (背景が動いた同じ量だけ、戦車も動かして地上に戦車があるように表示しています。) どうにか、どのグラフィックチップでも大抵問題なく、同じような効果を得られないでしょうか?
Re: 戦車や船などの走った跡 ( No.4 )
名前:管理人 日時:2009/02/09 19:38

> 以下のコードとまったく同じ効果を違う方法で得たいのですが、上手く行きません。 具体的にはどのように上手く行かないのでしょうか? > どのグラフィックカード(チップ?)でも大抵は正常に表示できるようにしたいのです。 それがご希望でしたら、MakeGraph で作成した画像に描画する機能を使用するべきではないと思います > intの値を5000などと大きくすると、上記の描画時にウィンドウではなく、 > スクリーン全体の左上を0,0として描画されてしまいます。 スクリーン全体の左上を0,0として描画されてしまうのはDXライブラリのバグである可能性が 高いですが、何が原因であるにしても 4096 を超えるサイズのテクスチャはここ数年で登場した グラフィックチップでようやく対応が始まったというところなので、殆どの環境で正常に 動作させたいとお考えでしたら尚のこと描画可能画像は使用すべきではないと思います > どうもその背景が大きすぎるためか、上記の方法では上手くいきませんでした。 > ちなみに画像は、(800,5120) のjpg 150kb です。 本件とは直接関係ありませんが、DirectX は jpeg画像を jpeg画像のまま扱う機能は備わっていませんので、 LoadGraph で読み込まれた画像が無圧縮BMPや無圧縮Tga等以外の場合はまず無圧縮の BMP 形式(に近いもの)に 変換されます。すると、800x5120 サイズの画像は、読み込み後には 800×5120×4バイト=16384000バイト  (16bitカラーの場合は半分の8192000バイト) 16384000バイト=15.625メガバイト と、16MB弱のサイズになります グラフィックチップに拘りのないノートPC等ではこの時点で正常に動作しない可能性がありますので、 多くの環境で正常に動作させることをお考えの場合は2DRPGのマップ表示のように、32×32サイズの チップセットを並べてマップを表現する方法を採用された方が良いと思います > どうにか、どのグラフィックチップでも大抵問題なく、同じような効果を得られないでしょうか? まず跡の表現方法としては最初にMさんが採られていた一つ一つDrawGraph 等の関数で描画する方法で 良いと思います( 一番正常に動作する環境が多くなると思いますので ) そして、700個という数ですが、CPU負荷が原因で700個描画すると処理落ちが発生するということでしたら 最適化有りのリリースビルドをすることでそれなりに処理が高速化されますのでもしかしたら元のままの処理で 700個を処理落ちなく処理することができるかもしれません もしそうではなくグラフィックチップの性能がネックになって処理落ちが発生しているとしますと、 残念ながら700個という数をあきらめるしかありません また、Mさんの環境で700個描画しても処理落ちしないようになっても、Mさんが「これくらいの環境だったら 処理落ちなく動いてほしい」という環境で処理落ちせずに動作しなければ意味が無いので、その点も考慮する 必要があります 最後に高速に描画処理を行うポイントです 1.同じ画像は可能な限り連続して描画するとテクスチャ変更と頂点フラッシュが発生しないので描画処理が高速になります 2.扱う画像は 2 のn乗のサイズ( 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 )にすると   テクスチャ分割が行われる可能性が無いので高速な描画が期待できます 3.DerivationGraph で派生させたグラフィックハンドル達はすべて派生元のグラフィックハンドルの   テクスチャを使用するので、同じ画像から DerivationGraph させたグラフィックハンドルは、   グラフィックハンドルが違っても1と同じ高速描画効果が得られます   ( ただし、DerivationGraph をする元の画像が 2 のn乗サイズである必要があります )    なので、開発効率に支障が出ない範囲で、色々な画像を 2のn乗サイズの画像に敷き詰めて、   DerivationGraph で派生させて使用すると、高速に描画することができます 4.LoadDivGraph はDXライブラリの中で分割元画像を LoadGraph して、DerivationGraph で   派生させているので、LoadDivGraph で分割読み込みしたグラフィックハンドル達も、1と同じ   高速描画効果が得られます( ただし、LoadDivGraph で読み込む分割元画像が 2 のn乗サイズである   必要があります ) 5.描画関数の処理負荷は DrawGraph < DrawExtendGraph < DrawRotaGraph < DrawModiGraph ≒ DrawRectGraph です   ( ただ、同じテクスチャを使用した描画を連続させることで得られる高速化効果よりも処理負荷への影響は少ないです )
Re: 戦車や船などの走った跡 ( No.5 )
名前:M 日時:2009/02/10 09:00

細かい解説ありがとうございます。<(_ _)> >具体的にはどのように上手く行かないのでしょうか? というのは、ただたんに思いつかないというだけです。 ややこしい言い方をしてしまって、すみません。 面倒くさがってタイル(チップ)を避けてました>< 背景は、チップで表示するようにします。 >最適化有りのリリースビルドをする そういえば、そのことを忘れていました。 >LoadGraph で読み込まれた画像が無圧縮BMPや >無圧縮Tga等以外の場合はまず無圧縮の BMP 形式(に近いもの)に変換されます。 なんと!! それは壮大なメモリ(?)の無駄遣いではないですかw 跡のほうは、MakeGraphはあきらめて、たくさん描画する方針にしてみます。 >最後に高速に描画処理を行うポイントです ありがとうございます!! めっさ助かります。 すぐには解決の報告はできないかもしれませんが、教えていただいた事を参考にして直してきます。 (*追加) ひとつだけ質問があります。 >同じ画像は可能な限り連続して描画するとテクスチャ変更と頂点フラッシュが発生しないので描画処理が高速になります ということですが、すると、チップで表示する際も左上から右下と描画する方法 for(int x = 0; x < (xのMAX値);x++) for(int y = 0; y < (yのMAX値); y++) DrawGraph(x*32,y*32,ChipGraph[ GraphicChipAt[x][y] ],false); //ChipGraph[int]は、指定されたチップの種類の画像ハンドルを返す。 //GraphicChipAt[int][int] は、指定された座標のチップの種類を返す。 とやるよりも、チップをベースでループする方法 for(int chipNum = 0; chipNum < (chipNumの種類数);chipNum++){ for(int x = 0; x < (xのMAX値);x++) for(int y = 0; y < (yのMAX値); y++){ if(graphicChipAt[x][y] == chipNum) DrawGraph(x*32,y*32,ChipGraph[chipNum],false); } } の方が高速ということでしょうか? ループの量は、かなり増えてますが・・・。
Re: 戦車や船などの走った跡 ( No.6 )
名前:憂煉 日時:2009/02/10 15:23

はじめましてMさん。 追加質問に関してですが、描画前に描画順序の並び替えをするのはどうでしょうか? struct POSLIST { int x,y; POSLIST *next; POSLIST():x(0),y(0),next(NULL){} }; POSLIST posdata[x_max * y_max]; //描画する分だけ準備 POSLIST *poslist[chipNum]; //チップの種類だけ準備 void draw() { int i = 0; POSLIST *tmp; for(i = 0;i < chip_max;++i)poslist[i] = NULL; for(int x = 0;x < x_max;++x) for(int y = 0;y < y_max;++y) { //チップの種類別リストを生成するループ posdata[i].next = poslist[graphicChipAt[x][y]]; posdata[i].x = x * 32; posdata[i].y = y * 32; poslist[graphicChipAt[x][y]] = posdata + i; ++i; } for(i = 0;i < chip_max;++i) for(tmp = poslist + i;tmp != NULL;tmp = tmp->next) { //リストに従って描画するループ DrawGraph(tmp->x,tmp->y,i,false); } } 一気に書いたのでバグがあるかも知れませんがご参考程度にどうぞ
Re: 戦車や船などの走った跡 ( No.7 )
名前:管理人 日時:2009/02/10 19:36

> ひとつだけ質問があります。 チップ画像が全て個別の画像ファイルになっていて、それを一つ一つ LoadGraph で読み込んで ChipGraph 配列にグラフィックハンドルを代入したのだとしたらMさんが書き込まれた後者の プログラムのようにチップ別に描画したほうが描画処理としては高速ですが、2のn乗サイズの 画像にチップを並べて、それを LoadDivGraph で読み込んだ場合は ChipGraph に格納される グラフィックハンドルの値は全て別ですが使用しているテクスチャは同じものとなりますので、 前者のプログラムでも「同じ画像を連続して描画している」ことと同じになり、高速に描画することができます。
Re: 戦車や船などの走った跡 ( No.8 )
名前:M 日時:2009/02/11 05:20

なるほど! ありがとうございます<(_ _)> ご協力のおかげで、かなり進歩しました。 戦車の足跡の方ですが、代替案を思いつきました。 やはり、細かくたくさん描画するのは数がどうしてもすごいことになり処理落ちがありうるため、避ける事にしました。 その代わりに、やや残念ですが、移動ルートをチップに合わせて固定します。 そこで、新たなチップレイヤー(第二レイヤー)を背景の上に作成し、 戦車が通ったルートと同じチップ上の第二レイヤーに足跡を描画することで、解決しそうです。 チップベースに描画をする事で、意外と本来の問題を解決することができました。 ありがとうございました。<(_ _)>

Page: 1 |