擬似タスクの実装

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

擬似タスクの実装

#1

投稿記事 by TRUTH » 16年前

こんにちはー。
CからC++へと手を伸ばし、勉強をしているのですが
詰まってしまったので質問させてください。


STGの擬似タスクを作ろうと頑張っているのですが上手くいきません。

今に至った流れはこのような形です。
現在はC++のSTLのリストを使用しての擬似タスクを実装しています。
(ここを参考にして作ってます。http://www.tnksoft.com/reading/classgam ... 01/011.php

ですが、Cで制作した龍神録と比べると処理速度が極めて遅く、弾を600ほど生成しただけで処理落ち状態に陥りました。
(自分のコードで、処理速度が遅い可能性もあると思いますが…)
突き詰めると、疑似タスクの処理(挿入・削除)の遅さが速度に影響しているようでした。



このような場合は疑似タスク自体の変更から考えた方がいいのでしょうか?
アドバイスよろしくおねがいします。

GPGA

Re:擬似タスクの実装

#2

投稿記事 by GPGA » 16年前

STLを使っただけで、処理速度が極めて遅くなるということはほとんど考えられません。

コードのほうに問題がある可能性が非常に高いので、疑似タスクのソースを提示してください。

ねこ

Re:擬似タスクの実装

#3

投稿記事 by ねこ » 16年前

龍神録プロジェクトを使っているようなのでDXLIB仕様だと思います。
PCスペック、画像サイズ、描画モード等、色々な要素によって異なりますが
600個の画像描画というとそれなりの負荷になっています。

STLを使った場合、では無く単純にCの時とC++の時での1フレームの平均処理時間等を比較してみると
問題がもう少し違った位置に見えてくるかもしれません。

GPGA

Re:擬似タスクの実装

#4

投稿記事 by GPGA » 16年前

追記
生成でもっと速くしたいのであれば、リストと配列と併用することで
生成時の速度を稼ぐことができます。
更にメモリを食ってでも、削除の速度を上げたい場合bulletEnableListを
std::listの代わりにstd::setを使用することで削除速度を上げることができます。
ただし、生成時の速度が少し遅くなります。


#include <list>
#include <set>

#define USE_SET	// std::setを使う場合、こちらの定義を有効にする

class Bullet {
public :
	void Exec(){}
};

static const int MAX_BULETTE = 1000;
Bullet bullet[MAX_BULETTE];

#ifdef USE_SET
	std::set<Bullet*> bulletEnableList;		// 有効リスト
#else
	std::list<Bullet*> bulletEnableList;	// 有効リスト
#endif

std::list<Bullet*> bulletDisableList;		// 無効リスト


// 初期化
void Init() {
	// 弾を無効リストに格納
	for (int i = 0; i < MAX_BULETTE; ++i) {
		bulletDisableList.push_back(&bullet);
	}
}

// 挿入
bool Insert() {
	// 全ての弾が有効になっている
	if (bulletDisableList.empty()) {
		return false;
	}

#ifdef USE_SET
	bulletEnableList.insert(bulletDisableList.back());
#else
	bulletEnableList.push_back(bulletDisableList.back());
#endif
	bulletDisableList.pop_back();

	return true;
}

// 削除
void Delete(Bullet* p) {
#ifdef USE_SET
	bulletEnableList.erase(p);
#else
	bulletEnableList.remove(p);
#endif
	bulletDisableList.push_back(p);
}

// 実行
void Exec() {
#ifdef USE_SET
	std::set<Bullet*>::iterator it = bulletEnableList.begin();
#else
	std::list<Bullet*>::iterator it = bulletEnableList.begin();
#endif
	for (; it != bulletEnableList.end(); ++it) {
		(*it)->Exec();
	}
}
 

TRUTH

Re:擬似タスクの実装

#5

投稿記事 by TRUTH » 16年前

GPGA様

>>STLを使っただけで、処理速度が極めて遅くなるということはほとんど考えられません。
そうですよね…

コードですが…コメントなしに書いていっています。見づらいと思いますので…
基本的には参考にしましたサイト様と擬似タスク部分は同一ですので、そちらの方が見やすいと思います。
http://www.tnksoft.com/reading/classgam ... 00/000.php のゲームエンジンのダウンロード
解凍後、/TNKGEngine/GameObject.h GameObject.cppが擬似タスクの基底クラスです。



ねこ様

DXLIBではなく、今回は直接DirextXを使用して作ってみました。
自分も描画が原因では?と考えて、弾の描画をコメントアウトしたのですが
処理速度があまり変わらず…

TRUTH

Re:擬似タスクの実装

#6

投稿記事 by TRUTH » 16年前

追記です。

タスクへの追加・削除の遅さが原因ではありませんでした。
(一定まで弾を追加し、削除させないでいても処理速度は変わりませんでした。調査不足ですみません)

上記にも少し書きましたが、現在描画などの処理の重そうな動作はコメントアウトしている状態です。
弾の実行用関数はコメントアウトして何も動作させない状態なのですが

それでも弾を増やしていくと処理に時間がかかっています…

ねこ

Re:擬似タスクの実装

#7

投稿記事 by ねこ » 16年前

<DirectX使用
なるほど。描画もコメントアウトして一緒なら描画じゃないかもしれませんね。

コメントアウトして試してるようですが、ある程度のブロックで処理時間を計測するのはどうでしょうか?
満遍なく処理負荷が上がっているとは考えずらいため、各場所で現在時間を取得してブロック単位の処理時間を測定すると負荷の高い処理の位置が特定しやすいと思います。

内容うろ覚えなんですが、DirectXだと使用デバイスへのソフトウェアドライバとかハードウェアドライバとかの設定関数は正常に設定されているでしょうか?
昔とあるPCではそれらの処理が正常に設定されず、謎にFPSが落ちるという現象に遭遇した記憶があります。
Cで動いてるので違うとは思いますが、一応。

GPGA

Re:擬似タスクの実装

#8

投稿記事 by GPGA » 16年前

>それでも弾を増やしていくと処理に時間がかかっています…
これはつまり、Execメソッドの実行が遅いということでしょうか?
それとも追加処理を行う瞬間が遅いということでしょうか?

処理を見る限り、追加、削除の部分の負荷が非常に高いのはわかるのですが
実行部分が遅いと思われる場所はありませんでした。

このタスクリストは、弾のような数を処理する物に向いていません。
このタスクリストに追加するのは弾のマネージャークラスのみを追加し
そのマネージャークラスの中で、弾専用のタスクリストを生成したほうが
好ましい結果を得ることができるでしょう。

TRUTH

Re:擬似タスクの実装

#9

投稿記事 by TRUTH » 16年前

進展がありましたので詳細を書きます。
①タスクに弾を追加する瞬間(一瞬だけ重くなるのでカクついていました)は、やはりかなり負荷がかかっています。
②全体的な重さは、弾がいくつタスクに入っているか調べる列挙関数でした。(デバック用に弾数を調べるために使ってました)

上記を改善するために、弾用のタスクを作りたいと考えています。



ねこ様

設定の方は大丈夫だと思います。
これからはブロックごとにしっかり処理時間を計測してみます。



GPGA様

サイト様とはゲームの仕様の違いがあるので(こちらは弾幕、サイト様は通常のSTG)
弾幕用のタスクを作りたいと思います。




連続した質問になってしまいますが…
弾を大量にタスクに追加・処理・削除する場合
どのようなタスクを作るのが適切なのか分かりません。


弾幕STGですが、なるべく低スペックで動作するように考えています。
この場合でも、GPGA様が書いて下さった様に
配列である程度確保した後、リストに加え管理する方がいいのでしょうか?
(弾幕STGなので、弾は必ず一定量まで増えてしまうと考えられるので)


まだまだひよっこですので…タスクを実装するに関しても
毎回オブジェクトを作り、削除してしまう形と、最初から配列で確保してしまう形との
処理の差がどれほどあるのか分かりません。

もし教えていただける方がいらっしゃいましたら、よろしくお願いします。

Justy

Re:擬似タスクの実装

#10

投稿記事 by Justy » 16年前

[color=#d0b0c0" face="monospace]
>タスクに弾を追加する瞬間(一瞬だけ重くなるのでカクついていました)は、
>やはりかなり負荷がかかっています
[/color]

 追加をする際、テクスチャをロードするなどHDDなどにアクセスはしていないですよね?


[color=#d0b0c0" face="monospace]
>弾を大量にタスクに追加・処理・削除する場合
>どのようなタスクを作るのが適切なのか分かりません。
[/color]

 タスクシステムそのものより、その使い方に少し問題がある気もします。

 弾幕ゲーム、なんですよね?
 なら1つの弾=1タスクではなく、1つの弾幕=1タスクで作っても良さそうな。
 そうすれば一連の流れを持つ弾幕も使う時、1つのタスクを起動させるだけで済みますし、
1弾幕での最大弾数の予測もつくので管理もしやすいでしょう。
 
 勿論必要に応じてその子タスクを作って細かく管理するものがあってもいいですが。


[color=#d0b0c0" face="monospace]
>配列である程度確保した後、リストに加え管理する方がいいのでしょうか?
[/color]
 
 まずは普通に毎回オブジェクトを生成・破棄する方法にしておいて、
それがボトルネックになったと判ったとき、別の方式に差し替えればいいと。

 その場合、差し替えが容易にできるようにしてくといいですね。

TRUTH

Re:擬似タスクの実装

#11

投稿記事 by TRUTH » 16年前

大変遅くなりましたが、GPGA様のやり方で上手くいきました。

Justy様

テクスチャのロードを事前にしていたのですが、オブジェクトの生成を毎回行っていたのが
どうやらまずかったようです。
はい、弾幕ゲームですので弾幕タスクに子タスク(弾)を作る方法にしました。



相談にのってくれた方々、本当にありがとうございました。
また何かありましたらよろしくお願いします。

ととろ

csvファイルは読み取っているが画像が表示されない

#12

投稿記事 by ととろ » 16年前

すみませんが。文章が長すぎでエラーがでたのでテキストを開いて読んでください。

ファイルの続き。
int  enemy_num_search(){
        for(int i=0;i<ENEMY_MAX;i++){//フラグのたって無いenemyを探す
                if(enemy.flag==0){
                        return i;//使用可能番号を返す
                }
        }
        return -1;//全部埋まっていたらエラーを返す
}

//敵の移動パターン0での移動制御

//敵情報を登録
void enemy_enter(){//敵の行動を登録・制御する関数
 void load_story();
	int n,i,j;
        for(n=0;n<ENEMY_ORDER_MAX;n++){
                if(enemy_order[n].cnt==stage_count){//現在の瞬間がオーダーの瞬間なら
					if((i=enemy_num_search())!=-1){								
							    enemy.flag   =1;
                                enemy.cnt    =0;
                                enemy.pattern=enemy_order[n].pattern;
                                enemy.muki   =1;
                                enemy.knd    =enemy_order[n].knd;
                                enemy.x      =enemy_order[n].x;
                                enemy.y      =enemy_order[n].y;
                                enemy.sp     =enemy_order[n].sp;
                                enemy.bltime =enemy_order[n].bltime;
                                enemy[i].blknd  =enemy_order[n].blknd;
                                enemy[i].blknd2 =enemy_order[n].blknd2;
                                enemy[i].col    =enemy_order[n].col;
                                enemy[i].wait   =enemy_order[n].wait;
                                enemy[i].hp     =enemy_order[n].hp;
                                enemy[i].hp_max =enemy[i].hp;
                                enemy[i].vx     =0;
                                enemy[i].vy     =0;
                                enemy[i].ang    =0;
                                for(j=0;j<6;j++)
                                        enemy[i].item_n[j]=enemy_order[n].item_n[j];
                        }
                }
        }
}

//敵の行動制御
void enemy_act(){
    
	int i;
    if((i=enemy_num_search())!=-1){		
    for(i=0;i<ENEMY_MAX;i++){
        if(enemy[i].flag==1){//その敵のフラグがオンになってたら
            enemy_pattern0(i);
            enemy[i].x+=cos(enemy[i].ang)*enemy[i].sp;
            enemy[i].y+=sin(enemy[i].ang)*enemy[i].sp;
            enemy[i].x+=enemy[i].vx;
            enemy[i].y+=enemy[i].vy;
            enemy[i].cnt++;
            enemy[i].img=enemy[i].muki*3+(enemy[i].cnt%24)/6;
            //敵が画面から外れたら消す
            if(enemy[i].x<-20 || FIELD_MAX_X+20<enemy[i].x || enemy[i].y<-20 || FIELD_MAX_Y+20<enemy[i].y)
                enemy[i].flag=0;
        }
    }
}
}

//敵処理メイン
void enemy_main(){
    enemy_enter();
    enemy_act();
}
//ヘッダーの中身です

GLOBAL enemy_t enemy[ENEMY_MAX];

GLOBAL enemy_order_t enemy_order[ENEMY_ORDER_MAX];//敵の出現情報

#define ENEMY_MAX 30

#define ENEMY_ORDER_MAX 500

GLOBAL void load();

GLOBAL void load_story();


敵情報をcsvファイルで取り込む。龍神録とほぼ同じコトをしているはずなのに、敵が画面に表示されません。
csvファイルは正常に最後まで読み込まれています。
回答お願いします
なおcsvファイルは龍神録11章のをそのまま使っています

Dixq (管理人)

Re:csvファイルは読み取っているが画像が表示されない

#13

投稿記事 by Dixq (管理人) » 16年前

投稿されたコードを一字一句見てないのですが、
龍神録のサンプルと何か違いがあるのでしょうか?

「ほぼ」と書かれているからにはどこか変更されているのだと思いますが、
どの辺をどう変えたか教えてもらえると回答し易いかと思います。

また、ご自分でも、サンプルとどう違うか、何を変えたからおかしくなったのか見比べたりしてみて下さい。
何か解決の糸口になるかもしれません。

ととろ

Re:csvファイルは読み取っているが画像が表示されない

#14

投稿記事 by ととろ » 16年前

はい。ほぼなんて適当な質問すみません。
じっくり見てみます

閉鎖

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