タスクシステムの実装について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
koki

タスクシステムの実装について

#1

投稿記事 by koki » 15年前

龍神録プログラミングの館の解説を参考に、STLのdequeとstack、
そしてplacement newを使ったタスクシステムを実装した形にアレンジしたいと思っています。

具体的には、弾クラスと同じサイズのchar配列を使う弾の数だけnewし、その先頭アドレスをstackに順次格納。
必要に応じて格納したアドレスをstackからdequeに持って行っていき、そのアドレスを使って
placement newして弾オブジェクトを生成、必要なくなればオブジェクトを破棄してdequeからstackに戻す、
という手順を踏んでいます。

自機とボスを作り、弾を打ち出すところまでは出来たのですが、
敵の打ち出す弾の数があまり多くない状態でも処理落ちが酷くなってしまいます。

以下がプロジェクトファイルです。
http://www1.axfc.net/uploader/H/so/100995&key=koki

何が原因なのか分からず困っています。
どなたか教えていただけないでしょうか。
宜しくお願いします。 画像

Justy

Re:タスクシステムの実装について

#2

投稿記事 by Justy » 15年前

 実際に計測したわけではないので確かではないですが、
bmanage変数で operator[/url]を使って多数のアクセスをしていますよね?

 環境不明なので推測ですが、これは環境によってはデバッグビルドだと
ちょっと遅い処理になるかもしれません。

 なので、これを止めてみる、或いは最小限にしてみてはどうでしょうか?

 forなどによるループで使用するときには

for(int i = 0; i < (int)bmanage.size(); ++i)
{
Bullet *bullet = bmanage;
...
}
のように一旦 Bulletクラスのポインタで受け、以後はそのポインタを使ってアクセスをする、とか。

 あぁ、operator[/url]ではなくイテレータを使うとやはり環境によっては更に少し速くなるかもしれません。

dic

Re:タスクシステムの実装について

#3

投稿記事 by dic » 15年前

イテレータを使って実装してみました
もとのスピードが遅いので、早くなった感覚はあまりしませんが
改善はされてます
//ここで弾の移動処理を行う。
    std::deque<Bullet*>::iterator p;

    p = bmanage.begin();
    while( p != bmanage.end() )
    {
        (*p)->x += cos((*p)->angle*(*p)->spd);
        (*p)->y += sin((*p)->angle*(*p)->spd);
        (*p)->cnt++;
        if( (*p)->cnt > (*p)->till ){
            if( (*p)->x < -50 || (*p)->x > FIELD_MAX_X+50 ||
                (*p)->y < -50 || (*p)->y > FIELD_MAX_Y+50 ){
                    (*p)->flag = 0;
            }
        }
        p++;
    }
    /*
    for(int i = 0; i < (int)bmanage.size(); ++i) {
        if(bmanage->flag > 0){    //その弾が登録されていたら
        bmanage->x += cos(bmanage->angle)*bmanage->spd;
        bmanage->y += sin(bmanage->angle)*bmanage->spd;
        bmanage->cnt++;
            if(bmanage->cnt>bmanage->till){
                if(bmanage[i]->x<-50 || bmanage[i]->x>FIELD_MAX_X+50 ||
                        bmanage[i]->y<-50 || bmanage[i]->y>FIELD_MAX_Y+50){//画面から外れたら
                                bmanage[i]->flag=0;//消す
                }
            }
        }
    }
    */

//弾のflagが0なら登録を解除する
    p = bmanage.begin();
    while( p != bmanage.end() )
    {
        if( (*p)->flag == 0 )
        {
            (*p)->~Bullet();
            p = bmanage.erase(p);
        }
        else
            p++;
    }
    /*
    for(int j = 0; j < (int)bmanage.size(); ++j) {
        if((bmanage[j]->flag) == 0) {
            bmanage[j]->~Bullet();
            char* memory = (char*)bmanage[j];
            //delete bmanage[j];
            bmanage.erase(bmanage.begin() + j);
            bmem.push(memory);
            memory = 0;
            --j;
        }
    }
    */


//ボスの弾幕描画
void Boss::DrawBossBullet(){
    SetDrawMode( DX_DRAWMODE_BILINEAR ) ;//線形補完描画
    std::deque<Bullet*>::iterator p;
    p = bmanage.begin();
    while( p != bmanage.end() )
    {
        DrawRotaGraphF(
            (*p)->x+FIELD_X, (*p)->y+FIELD_Y,
            1.0, (*p)->angle+PI/2,
            img_bullet[(*p)->knd][(*p)->co[/url], TRUE );

        if( (*p)->eff == 1 )
            SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0 );
        p++;
    }
    /*
    for(int l = 0; l < (int)bmanage.size(); ++l) {
        DrawRotaGraphF(
        bmanage[[/url]->x + FIELD_X, bmanage[[/url]->y + FIELD_Y,
        1.0, bmanage[[/url]->angle + PI/2,
        img_bullet[bmanage[[/url]->knd][bmanage[[/url]->co[/url],TRUE);

    if(bmanage[[/url]->eff==1)
        SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0) ;
    }
    */
    SetDrawMode(DX_DRAWMODE_NEAREST);//描画形式を戻す
}


これで結構速くなったのですが、まだまだ改善するところはあるようです
boss->Move( stage_count, player );
のところです

dic

Re:タスクシステムの実装について

#4

投稿記事 by dic » 15年前

>これで結構速くなったのですが、まだまだ改善するところはあるようです
>boss->Move( stage_count, player );
>のところです
おもいっきり同じところ言ってますねw
これ以上はアルゴリズムを考えるしか私には思いつきません
deque(STL)使わないとか
私もSTL使ってるんですが、結構重いですね

Justy

Re:タスクシステムの実装について

#5

投稿記事 by Justy » 15年前

>イテレータを使って実装してみました
 イテレータから Bullet *に取り出してからアクセスすると
もう少し早くなるかもしれません。

 とはいえ、Releaseで処理落ちなければ気にすることはないと思います。

dic

Re:タスクシステムの実装について

#6

投稿記事 by dic » 15年前

たしかにReleaseでは処理落ちしないですね
私の実装したソースでは30秒くらいでバグが起きます

ってVCメモリ食いすぎ・・・
遅いのは私の環境のメモリ不足の可能性もあるかも

koki

Re:タスクシステムの実装について

#7

投稿記事 by koki » 15年前

質問の際に環境を書いていなかったですね。申し訳ないです。
私はVisualC++2008を使っています。

operator[/url]を使って多数のアクセスをしていたことが原因だったのですね。
イテレータに関する理解が今一つ浅く、使用するのに不安があった事と、forループを回す際に
見た目に分かりやすいという理由から使っていたものだったのですが、それが仇になってしまっていたとは…。
とても勉強になりました。ご回答ありがとうございました。

Justy

Re:タスクシステムの実装について

#8

投稿記事 by Justy » 15年前

>dicさん
> たしかにReleaseでは処理落ちしないですね

 デバッグビルドで処理落ちするのは、Windowsに限らずよくある話なんですよね。
 デバッグビルドなのに自分の担当分のところだけ最適化を切ってそれ以外は最適化を
かけておくとか。


>kokiさん
> operator[/url]を使って多数のアクセスをしていたことが原因だったのですね

 これは環境・状況次第なところもありますが、普通の配列でも同じだったりします。
 bmanageが普通の Bullet*の配列だったとしても毎回 bmanage->xとアクセスするより、
一旦 bmanageをポインタで受けて そのポインタ経由で pBman->xとした方が
(ほんの僅かかもしれませんが)速いことが多いです。



> 私はVisualC++2008を使っています

 なら
[color=#d0d0ff" face="monospace]
for each(Bullet *b in bmanage)
{
b->x += cos(b->angle) * b->spd;
...
}
[/color]

なんて書き方もできますね。
http://msdn.microsoft.com/ja-jp/library/ms177203.aspx

koki

Re:タスクシステムの実装について

#9

投稿記事 by koki » 15年前

環境によって別の書き方が出来る場合もあるんですね。
参考になります。ありがとうございます。

閉鎖

“C言語何でも質問掲示板” へ戻る