ページ 11

タスクシステムについて

Posted: 2012年2月12日(日) 11:40
by Fimbul

コード:

#define TASK_MAX 200
#define ENM_MAX 100
#define ENM_SHOT_MAX 100

//タスクシステム?
int main() {
	Task* task[TASK_MAX];
	Enm* enm[ENM_MAX];
	EnmShot* enmShot[ENM_SHOT_MAX];
	//EnmクラスとEnmShotクラスはTaskクラスを継承したクラス
	
	//初期化
	for(int index = 0; index < TASK_MAX; index++) {
		task[index] = NULL;
	}
	for(int index = 0; index < ENM_MAX; index++) {
		enm[index] = NULL;
	}
	for(int index = 0; index < ENM_SHOT_MAX; index++) {
		enmShot[index] = NULL;
	}
	
	//何らかのきっかけでインスタンスを生成する
	for(int index = 0; index < ENM_MAX; index++) {
		if(enm[index] == NULL) {
			enm[index] = new Enm;
			break;
		}
	}
	for(int index = 0; index < ENM_SHOT_MAX; index++) {
		if(enmShot[index] == NULL) {
			enmShot[index] = new EnmShot;
			break;
		}
	}
	
	//タスクシステムに登録
	for(int index = 0; index < ENM_MAX; index++) {
		if(enm[index] != NULL) {
			for(int index_ = 0; index_ < TASK_MAX; index_++) {
				if(task[index_] == NULL) {
					task[index_] = enm[index];
					break;
				}
			}
			break;
		}
	}
	for(int index = 0; index < ENM_SHOT_MAX; index++) {
		if(enmShot[index] != NULL) {
			for(int index_ = 0; index_ < ENM_SHOT_MAX; index_++) {
				if(task[index_] == NULL) {
					task[index_] = enmShot[index];
					break;
				}
			}
			break;
		}
	}
	
	//何らかのきっかけで任意のタスクを削除、インスタンスも破棄する
	//インスタンスが登録されたタスクの番号を保持している必要がある
	task[インスタンスが登録されている番号] = NULL;
	delete enm[破棄したいインスタンスの番号];
	enm[破棄したいインスタンスの番号] = NULL;
	
	//タスクの実行
	//Calc()とDraw()はオーバーライドされた関数
	//この多態性を活かしたいのだと思う
	for(int index = 0; index < TASK_MAX; index++) {
		if(task[index] != NULL) {
			task[index]->Calc();
			task[index]->Draw();
		}
	}
	
	//インスタンスの破棄
	for(int index = 0; index < ENM_MAX; index++) {
		delete enm[index];
	}
	for(int index = 0; index < ENM_SHOT_MAX; index++) {
		delete enmShot[index];
	}
	
	return 0;
}
タスクを登録するリスト(タスクリスト? とします)は連結リストで可変長だと聞きました。
では、上記のコードの様に固定長のタスクリストはいけないんでしょうか。
そもそも、上記のコードがタスクシステムになっているかどうかが怪しいのですが・・・。

コードが長くなるので説明の簡単のために、Taskクラスのインスタンスを保持してタスクの登録と削除を行うTaskMgrクラスを定義せずに、上記の様にタスクの登録と削除をしています。

また、上記のコードはタスクを削除した後にタスクの整理(タスクの穴が出来ない様に、登録してあるタスクを前に詰める作業)をしていないので、タスクの実行時にタスクの最大登録数分ループしなければなりません。
そうではなく、タスクの整理をして次のタスクがヌルポインタかどうかを判断すれば、必要最小限でループが終了します。
ただ、タスクの最大登録数に依存すると思いますが、タスクの最大登録数分ループする時間とタスクを整理する時間の長さ、一般的にはどちらの処理の時間が短いのでしょうか。

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

Posted: 2012年2月12日(日) 12:21
by softya(ソフト屋)
結局のところリストにするのは全検索しないのでアクセス効率が良いからとリスト化することで優先順位ソート・マージが可能などのメリットが多いからです。
配列でも構わないのですが、「タスクの整理をして」と言うガベージコレクションをするならいっその事リストのほうがよくないかって話にはなると思います。

あと
Enm* enm[ENM_MAX];
EnmShot* enmShot[ENM_SHOT_MAX];
この2つの配列は不要では?

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

Posted: 2012年2月12日(日) 14:23
by Fimbul
softya(ソフト屋) さんが書きました: Enm* enm[ENM_MAX];
EnmShot* enmShot[ENM_SHOT_MAX];
この2つの配列は不要では?
以下の様に直しました。

コード:

#define TASK_MAX 200
 
//タスクシステム?
int main() {
    Task* task[TASK_MAX];
    
    //タスクリストの初期化
    for(int index = 0; index < TASK_MAX; index++) {
        task[index] = NULL;
    }
    
    //何らかのきっかけでインスタンスを生成、タスクリストに登録
    //EnmクラスとEnmShotクラスはTaskクラスを継承したクラス
    for(int index = 0; index < TASK_MAX; index++) {
    	if(task[index] != NULL) {
    		task[index] = new Enm;
    	}
    	break;
    }
    for(int index = 0; index < TASK_MAX; index++) {
    	if(task[index] != NULL) {
    		task[index] = new EnmShot;
    	}
    	break;
    }
    
    //何らかのきっかけで任意のタスクを削除、インスタンスも破棄する
    //インスタンスが登録されているタスクの番号を保持している必要がある
    delete task[削除したいタスクの番号];
    task[削除したいタスクの番号] = NULL;
    
    //タスクの実行
    //Calc()とDraw()はオーバーライドされた関数
    //この多態性を活かしたいのだと思う
    for(int index = 0; index < TASK_MAX; index++) {
        if(task[index] != NULL) {
            task[index]->Calc();
            task[index]->Draw();
        }
    }
    
    //インスタンスの破棄
    for(int index = 0; index < TASK_MAX; index++) {
        delete task[index];
    }
    
    return 0;
}
softya(ソフト屋) さんが書きました: 配列でも構わないのですが、「タスクの整理をして」と言うガベージコレクションをするならいっその事リストのほうがよくないかって話にはなると思います。
そうなんですか。
では、リストのタスクシステムと配列のタスクシステム(タスクの詰めをしない)でそんなに大きく効率は違うものなのでしょうか。
リストのタスクシステムを調べると、タスクの追加と削除の作業が煩わしく、そんなに効率が変わらないのなら配列のタスクシステムを使いたくなってしまいます。

また、忘れていたのですが、listクラステンプレートを使ってリストのタスクシステムを作る事は出来るのでしょうか。

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

Posted: 2012年2月12日(日) 14:35
by softya(ソフト屋)
Fimbul さんが書きました:では、リストのタスクシステムと配列のタスクシステム(タスクの詰めをしない)でそんなに大きく効率は違うものなのでしょうか。
リストのタスクシステムを調べると、タスクの追加と削除の作業が煩わしく、そんなに効率が変わらないのなら配列のタスクシステムを使いたくなってしまいます。
タスクシステムの場合実行順序の制御が必要になります。
これをどうやって実現するかですが結局リスト構造なようなものが必要になってくると思います。
色々やってみて実感して見ることが大事だと思いますので、まず実験してみては?
Fimbul さんが書きました:た、忘れていたのですが、listクラステンプレートを使ってリストのタスクシステムを作る事は出来るのでしょうか。
listクラスを使うことは可能です。まぁ、クラス化されたリスト構造って事です。
なので配列を止めてリスト構造にするって事になるのでは?

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

Posted: 2012年2月12日(日) 15:55
by 名前は開発中のものです。
C++を使っているなら std::vector, std::list などの標準コンテナを使えば簡単になるでしょう。配列・リストなどデータ構造の入れ替えも簡単になります。

そのうえで、効率については実測して判断すべきでしょう。挙げられた箇所についてはおそらく Calc(), Draw() の中のほうがはるかに重くなるのでどちらでも大差ないでしょうが。

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

Posted: 2012年2月12日(日) 20:27
by Fimbul
softya(ソフト屋) さんが書きました: listクラスを使うことは可能です。まぁ、クラス化されたリスト構造って事です。
なので配列を止めてリスト構造にするって事になるのでは?
そうなりますね。
softya(ソフト屋) さんが書きました: タスクシステムの場合実行順序の制御が必要になります。
これをどうやって実現するかですが結局リスト構造なようなものが必要になってくると思います。
色々やってみて実感して見ることが大事だと思いますので、まず実験してみては?
実行順序の制御がなぜ必要か分からないので、色々試して再度分からない所が出てきたら質問する事にします。

softyaさん、名前は開発中のものです。さん、ありがとうございました。