シューティングゲーム製作技術総合 2機目
■ このスレッドは過去ログ倉庫に格納されています
0001名前は開発中のものです。
04/01/10 21:07ID:hzI9eQA5それは「シューティングゲーム製作」・・・。
このスレでは、そんなシューティングゲームの製作技術や技術の検証、成功談
失敗談笑い話、難易度の設定方法論、多弾の是非などについて語り合いましょう。
もちろんBulletMLなどで弾幕を作成してみたり、自分の作ったシューティングを
晒してみたり、プロジェクトをはじめてみるなどもOK!
ただし、シューティングの未来とか既存のゲームの話題などは、関連する他の
スレでやってくれ。
■ 前スレ
シューティングゲーム製作技術総合
http://bbs.gamdev.org/test/read.cgi/gamedev/1056635103/
0301名前は開発中のものです。
04/02/08 02:23ID:UAmt1vblSCORE SOLDIER -WINTER FESTIVAL 2004-のソースがいつの間にか上がってたから
見てみたが、すごいな。まさに富豪的プログラミング。
まあちゃんとプレイ出来て面白ければ、中で何してようが関係ないんだけど。
0302名前は開発中のものです。
04/02/08 02:42ID:S7hDCZ6g0303名前は開発中のものです。
04/02/08 03:25ID:NDW8I9X10304名前は開発中のものです。
04/02/08 09:34ID:7WHzyUn3そうそのとおり!
0305名前は開発中のものです。
04/02/08 09:47ID:7WHzyUn3ぅぉ!データの定義にマクロアセンブラを利用するとは
そんな手があったのか
この書き方は、元々コンシューマの人なのかな?
あまり富豪的に見えなかったのは、俺がPCどっぷりだからか?
しかし、この見事なデータ駆動っぷりは見習わねばならん
0306名前は開発中のものです。
04/02/08 13:30ID:S7hDCZ6g使い慣れてる点も強み
実は俺もシューティングじゃないけど同じ方法使ったことが
0307名前は開発中のものです。
04/02/08 14:56ID:+FkgUptrかなり無駄な労力だなあと思うことはあるなあ
テキストファイルから読み込めるようになれば
調整段階までいけばコンパイルしなくていいから便利
0308名前は開発中のものです。
04/02/08 15:05ID:+Z9WcfXNそこで質問なのですが、
1.キャラクタを動かす場合、基本的に
各キャラクタのタスクを生成→キャラクタ移動タスク(座標の移動)→
→当たり判定タスク→描画タスク
という流れになると思うのですが、
当たり判定タスク・描画タスクで、
各キャラクタの座標をどのように取得すればよいか悩んでいます。
座標は各タスクのワークエリアにもっています。
今、思いつくのは、
1)当たり判定クラス・描画クラスを別に作って、
各キャラクタの座標を登録する形式にして、当たり判定タスク・描画タスクが、
自動的に処理するようにする。
2)各タスクのリストを順にたどっていき、タスクの属性(敵・味方等)を元に、
各タスクのワークエリアから座標を取得する。
です。
なにかよい方法はないでしょうか?
0309名前は開発中のものです。
04/02/08 15:06ID:+Z9WcfXN動的確保のため、タスクの生成・削除が多いとメモリが虫食い状態になってしまいます。
静的配列を使った方がよいのでしょうか?
ただし、静的に確保するためには各タスクのデータ構造は構造体で定義しなくてはいけないため、
(クラスだとポインタを使うのと代わりないため)
外部から操作される可能性がでてきてしまいます。
それを考えると、
やはりクラスを使って動的に確保したほうがよいでしょうか?
3.現在、各タスクの登録時には実行する関数を登録しています。
関数ではなく、基本となるタスククラスを継承した各クラスを登録したほうが、
コンストラクタ・デストラクタを自然に使えるので実装も簡単なのですが、
ただし、そうすると、タスク内でタスクをチェンジした場合に、
タスクの情報(座標等)を引き継ぐことができません。
そのへんがクリアできれば、クラスの利点を生かしたタスクシステムが作れそうなのですが。
長くなってしまいましたが、ぜひ、アドバイスをよろしくお願いします。
0310名前は開発中のものです。
04/02/08 15:07ID:+Z9WcfXN動的確保のため、タスクの生成・削除が多いとメモリが虫食い状態になってしまいます。
静的配列を使った方がよいのでしょうか?
ただし、静的に確保するためには各タスクのデータ構造は構造体で定義しなくてはいけないため、
(クラスだとポインタを使うのと代わりないため)
外部から操作される可能性がでてきてしまいます。
それを考えると、
やはりクラスを使って動的に確保したほうがよいでしょうか?
3.現在、各タスクの登録時には実行する関数を登録しています。
関数ではなく、基本となるタスククラスを継承した各クラスを登録したほうが、
コンストラクタ・デストラクタを自然に使えるので実装も簡単なのですが、
ただし、そうすると、タスク内でタスクをチェンジした場合に、
タスクの情報(座標等)を引き継ぐことができません。
そのへんがクリアできれば、クラスの利点を生かしたタスクシステムが作れそうなのですが。
長くなってしまいましたが、ぜひ、アドバイスをよろしくお願いします。
0311名前は開発中のものです。
04/02/08 15:49ID:+FkgUptr1.に関して。そーいう実装方法は止めたほうがいいかなぁー?
無理に複雑な実装方法を選んでプログラムを複雑にしてるという印象です。
もっとオブジェクト指向的に考えてみては如何でしょうかね。
2,3に関して。最近のPCは性能が良いので動的メモリ確保しても問題ないけども、
気になるようなら、オブジェクトの基底クラスを作って、
operator new/deleteのオーバーライドを考えてみては。
0312名前は開発中のものです。
04/02/08 15:58ID:+FkgUptrゲームを実装するためにタスクループの考え方があるのです。
タスクループ上でゲームを実装するにはどうすれば?とは本末転倒。
0313名前は開発中のものです。
04/02/08 16:10ID:x52VAobY俺も昔同じようなところで悩んだな。
結局、良い方法思いつかなかったけど。
1の当たり判定は、全てのキャラ移動→一括して当たり判定
ってのをしていた。そうしないと変な判定するんで。
2は、結局動的で押し通した。その際になるべく、
虫食いにならないようにタスクの生成順番と
削除のタイミングを注意した。
デバッグ用途も含めて、new/deleteはオーバーライドしてたけど、
タスクごとのオーバーライドはしなかった。
やってもいいと思う。
3は、そもそもタスクの切り分け方を従来の方法と
変えてしまったんで、普通に継承して問題なかった。
実装の仕方が違うと思うのでなんとも。
0314名前は開発中のものです。
04/02/08 16:18ID:+Z9WcfXNやはり、汎用的なタスクシステムを作るより、
ゲームにあわせてクラスを構成したほうがいいですかね。
ただ、クラスのみを使ってつくるとした場合、
基底キャラクタクラス(敵1クラス)から派生した各キャラクタクラス(敵1−1、敵1−2等)を作るとして、
結局は、グローバルな変数(またはクラス)等で、各派生クラスを管理しなくてはならないですよね?
グローバルな配列の各要素に、各派生クラスを結びつけて、
その配列を元に各派生クラスのメンバにアクセスする等でよいのでしょうか?
0315名前は開発中のものです。
04/02/08 16:36ID:+FkgUptr俺ならclass World(=ゲーム世界全体を表すシングルトンクラス)を作って、
そいつにキャラクタを保持させる、という感じですかね。
class World { list<Character*> m_characters[NUM_CHARA_TYPES]; };
特化させてクラス別リストを用意するとか、色々と方法はあるかと。
0316名前は開発中のものです。
04/02/08 16:40ID:x52VAobY俺は管理タスク(クラス)を用意した。
管理タスクからすべてのキャラクタタスクにアクセスする形。
アクセスは、キャラクタタスクの先頭へのポインタだけを持っていて、
あとは、リスト構造(リングバッファ)で辿る形。
0317名前は開発中のものです。
04/02/08 18:00ID:EK///DT8どんな感じにしてる?
0318名前は開発中のものです。
04/02/08 18:07ID:+FkgUptr2Dと3Dの違いもあれば、拡大縮小回転や口パクアニメなんかもあるわけで
なんと答えていいか分からんのだが
0319317
04/02/08 18:26ID:EK///DT80320名前は開発中のものです。
04/02/08 18:28ID:S7hDCZ6g敵弾オブジェクトごとに、アニメ用カウンタが用意されてる
表示関数で、そのカウンタを使ってアニメ
ここまでは基本だよな
あとは使う言語によるかな。
0321名前は開発中のものです。
04/02/08 18:34ID:+FkgUptr悩むところではないと思うんだけど。
RPGツクールみたいに32*32限定でいいならソーステクスチャを32*32で区切って左上から番号振る。
アニメ順序にあわせてIDを配列で並べて、ついでにアニメ速度とかを定義とかすればいいし。
汎用性持たせるならソース上の矩形ごと並べてしまうとかでもいいし。
0322名前は開発中のものです。
04/02/08 18:34ID:Bpmlhhr/0323名前は開発中のものです。
04/02/08 19:03ID:jKRYdHAvどこに配置させてどうやって参照させるのが賢いのだろうか…
いつも悩んでます。
0324名前は開発中のものです。
04/02/08 20:35ID:+Z9WcfXN自分もタスククラスとタスクマネージャークラスを作っています。
たしかに、先頭のタスクのアドレスを取得すれば、
リストをたどっていけますが、
どうもいまひとつの気がしてやってませんでした。
ようは、
1.先頭タスクのアドレスを取得して、
2.次のリストへのポインタを取得する、を繰り返す
ってことですよね?
結局、外部からタスクの内部を参照するわけであって…。
総当りの上に、書き換えられる可能性もあるわけですよね。
そう考えるとやっぱりクラスを使ったほうがいいのかぁ。
0325名前は開発中のものです。
04/02/08 20:37ID:+Z9WcfXNもしクラス版のタスクシステムを作ったとしても、
(クラスを登録して、タスクを生成・削除・チェンジするタスクシステム)
座標計算と当たり判定・描画処理を独立してやることを考えると、
(座標計算と判定・描画を同関数内でやると、すりぬけ、が発生するため)
関数版のタスクシステムと同じく
1.座標情報等のデータをグローバルで持つか、
2.各クラスのアドレスをグローバルで持って参照するか
しないといけないわけで、
タスクシステムでつくる意味がほとんどないわけですよね?
そう考えると、タスク自身のワークエリアをなくして、
データ類はグローバルな配列で別個で管理するほうがいいんですかね?
単なる関数ポインタを使ったテーブルジャンプみたいになってしまうけど。
0326名前は開発中のものです。
04/02/08 20:50ID:+Z9WcfXN↑にクラスを使った基本的なタスクシステムがありますが、
これって、当たり判定・描画処理を各タスクごとに行ってるんで、
すりぬけや、思わぬ動作を引き起こす可能性がありますよね。
そう考えると、一番いいのは、
各クラスを割り当てた管理配列等を、forループ等で処理したりでしょうか??
なんかわけわからなくなってきました(T_T)
0327名前は開発中のものです。
04/02/08 21:12ID:x52VAobY書き換えられる可能性ってのはないと思うけど、
そもそも書き換えられて困るから、一括処理な訳で。
リスト構造にしてる意味は、動的生成な訳で、
それをやめるなら、配列でいいかと。
グローバルにする意味はあんま感じないな。
Singletonって意味ならそうだけど。
0328名前は開発中のものです。
04/02/08 21:23ID:x52VAobYそれ読んでないけど、処理が終わったタスクとのみ
当たり判定を行っていけば、タスクごとの当たり安定でもできると思う。
0329名前は開発中のものです。
04/02/08 21:26ID:+FkgUptr迷っておりますなw
まず一つ言うが、>>326のタスクシステムはCのタスクシステムよりうんこだから無視せい。w
真にCのタスクをC++に移植するならば、
ワーカークラスのインスタンスポインタとメソッドポインタのペアをリスト化しなきゃならん。
個人的には初心に戻ってオブジェクト指向的に考えることを勧めるよん。
キャラクタはどんな情報をもち、何をするのか?→位置情報を持ち、移動や描画を行う
class Character {
Vector2 m_pos;
public:
Vector2 getPosition() { return m_pos; }
virtual void move() = 0;
virtual void render() = 0;
};
キャラクタのリストは誰が保持するのか?→ゲームの世界が保持して管理する
ゲームの世界はどんな機能がある?→世界の時間を一定量進めるとか、世界全体を描画するとか
class World {
list<Character*> m_characters;
public:
updateOneFrame() { for(...); it->move(); }
renderScene() { for(...); it->render(); }
};
こんなんでよいではないか、と思うけどネェ。
0330名前は開発中のものです。
04/02/08 21:28ID:x52VAobYあ、あと、当たり判定に関して言えば、
ソートとかして高速化は必須な気がしてきた。
それ考えると、配列のがいいかもしれないな。
俺はそこまでせずに作るの辞めてしまったけど。
0331名前は開発中のものです。
04/02/08 21:32ID:+Z9WcfXN管理タスクからタスクにアクセスする処理はどのようにしていますか?
参考にさせてください。
先頭タスクのから、順にたどっていくんですよね?
各キャラの移動タスクは独自のワークエリアに座標を書き込むとして、
当たり判定タスク等で、
Temp = 先頭タスクのアドレス;
while(Temp <> null);
{
Work = (EnemyRecord)Temp->WorkArea; //敵パラメータ構造体にキャスト
(各種処理)
Temp = タスク->次のタスクへのポインタ;
}
みたいな感じでワークエリアを順に取得して処理してるのでしょうか?
0332名前は開発中のものです。
04/02/08 21:44ID:+Z9WcfXNですが、各タスクはタスク内で別の関数にチェンジすることを考えると、
タスク内での判定処理等はあまりよくない方法のような気が…。
実行優先度を自ら把握して管理することができれば問題ないでしょうけど。
>>329
用語がいまひとつわかないです(>_<)
実は、Delphiなんです ;>_<;
ゲームのためのシステムの構築となると、
参考資料が少なすぎて…(泣
やっぱりCですかね…。
CはDOSのTurbo C++でとまってます(--;
0333名前は開発中のものです。
04/02/08 21:48ID:gPdyOEsw管理タスクがタスクにする状況って例えばどんな時ですか?
0334名前は開発中のものです。
04/02/08 22:01ID:+Z9WcfXN316に対するレスだったんですが、
つまり、キャラの移動・当たり判定・描画を例にとると、
タスク処理の流れは、
1.移動タスク
(移動タスクはキャラクタ数分、存在し、
各タスクは自分のワークエリアに座標を書き込む)
2.あたり判定タスク
3.描画タスク
となると思うのですが、
移動タスクでは、ワークエリアに座標を書き込みます。
そして、当たり判定タスク・描画タスクでは、各キャラの座標を参照して処理するわけです。
リンクをたどるということですが、
たぶん、次のようなことですよね?
0335名前は開発中のものです。
04/02/08 22:03ID:+FkgUptrごめん、俺はDelphi全然知らんから文法に関する記述はなんとも言えんわ。
とにかく、タスクは目的ではなく手段なんだから、それに捕らわれてはいけないよん。
0336名前は開発中のものです。
04/02/08 22:07ID:+Z9WcfXN1.管理タスクが、登録されている一番最初のタスクのアドレスを返す。
2.そのアドレスをたよりに、次々とタスクをたどっていく。
316のような方法にするには、
まず、先頭タスクのアドレスがわからなければ、リストをたどれません。
タスク管理クラスが先頭タスクのアドレスを返す処理をしないといけないわけです。
えーと、つまり、
外部から各タスクのワークエリアを参照するには、リストをたどる必要があるわけで、
そのリストのたどり方の実装の仕方を聞きたかったわけです。
わかりにくい説明ですね(>_<)
0337delphian
04/02/08 22:15ID:+Z9WcfXN>>335
329のクラスの読み方は、
class Character { //キャラクタークラス
Vector2 m_pos; //位置情報を持つ型の変数
public:
Vector2 getPosition() { return m_pos; } //位置情報を返すメソッド
virtual void move() = 0; //オーバーライドして使う。移動メソッド
virtual void render() = 0; //オーバーライドして使う。描画メソッド
};
でいいでしょうか?
このクラスを継承して、各キャラクタのクラスを作るんですよね?
0338delphian
04/02/08 22:18ID:+Z9WcfXNclass World {
list<Character*> m_characters; //各キャラクタクラスのリスト
public:
updateOneFrame() { for(...); it->move(); }
renderScene() { for(...); it->render(); }
ここで、for(...); it->move(); 等がわかりません。
delphiとの文法の違いによるせいだと思いますが。
各キャラクタクラスのmoveメソッドをすべて呼び出す、
ということなのでしょうか?
0339名前は開発中のものです。
04/02/08 22:31ID:x52VAobYあと、俺なら、CharacterクラスはTaskクラスから継承させるけど、
この辺は、実装次第かな。
>>338
updateOneFrame() { for(...); it->move();
は、331と同じ意味です。
そもそも331でキャストする必要はないけど。
何か古いタスクシステムに頭が固まっているような。
0340名前は開発中のものです。
04/02/08 22:32ID:+FkgUptr>>338 は、ごめん、そこ面倒でかなり素っ飛ばしてた。
STL知ってることを前提で書いてたので…。正確にはこんな感じ。
class World
{
list<Character*> m_characters;
void moveAllCharacters() {
for( list<Character*>::iterator it = m_characters.begin(); it != m_characters.end(); it++ ) {
Character* target = *it;
target->move();
}
}
void checkCollision() { /* まあ適当に… */ }
public:
void updateOneFrame() {
moveAllCharacters();
checkCollision();
}
};
ちと具体的過ぎてアレだが、俺のプログラムは大筋でこんな感じです。
0341名前は開発中のものです。
04/02/08 23:03ID:+FkgUptr何故ならタスクとは「誰が何をするのか」ということで、キャラクタは仕事ではなく"誰"の部分。
だからCのタスクリストをC++のソースで移植するとしたらこうなるんじゃないかな。
class Worker { };
typedef void Worker::(*Work)(); // Workerクラスのvoid method(); の形のメソッドポインタの型=Work
class Task {
Worker* m_worker;
Work m_work;
public:
void execute() { m_worker->(*m_work)(); }
};
class TaskList {
list<Task> m_tasklist;
public:
void executeAllTask() { for(...) it->execute() }; //また手抜き
};
タスクリストは仕事を保持しているだけで、オブジェクトのリストは保持していない。
全ての敵キャラや敵弾を参照したいときにタスクリストを使うとおかしな話になるのは、
この辺を混同してるのが原因かなーと思ったり。
0342名前は開発中のものです。
04/02/08 23:14ID:x52VAobYその誰が必要ない部分をタスクとして管理するわけよ。
そのための継承。
全てをタスクでするわけではないよ。
0343delphian
04/02/08 23:16ID:+Z9WcfXNSTL、、、
見かけたことはありますが、よく知りません。
イテレータってのもよくわからない…。
ちょっと調べてきます。
ようは、つまり、、、
タスクシステムを持ちいらずとも、
リストとクラスを使えば、似たようなことができるんですね!!
しかも、この方法はオブジェクト指向という感じがします。
1.キャラクタークラスを作って、それをオーバーライドして、
各キャラクターをつくる。
キャラクターごとの動作、描画登録を記述する。
2.管理クラスを作って、
そのクラスがそれぞれのキャラクターなどをまとめて管理する。
(各キャラクタの移動メソッドと描画メソッドを呼び出す)
ということですね?
0344名前は開発中のものです。
04/02/08 23:23ID:gPdyOEswTCB* tama = 一番先頭のタスクのアドレス;
while( tama->prio < 0x1000 ){
tama = tama->next;
}
TCB* enemy = 一番先頭のタスクのアドレス;
while( enemy->prio < 0x2000 ){
enemy = enemy->next;
}
while( tama->prio <= 0x1FFF ){
while( enemy->prio <= 0x2FFF ){
GameObject* t = (GameObject*)(&tama->work);
GameObject* e = (GameObject*)(&enemy->work);
if( hitcheck(t->rect,e->rect) ){
t->hitflag = true;
t->hitflag = true;
}
enemy = enemy->next;
}
tama = tama->next;
}
とか考えているのですがどうでしょうか?>334&>ALL
0345delphian
04/02/08 23:31ID:+Z9WcfXNやはり、そのように優先度で管理する方法が一般的ですかねぇ。
自分のタスクシステムは属性フラグを用意してあるので、
その属性フラグを使って処理することもできます。
このようなタスクシステムだと、
タスクのデータを保持したまま、
別のタスクにチェンジできるのがいいですよね。
>>340 >>341のような方法もオブジェクト指向という感じでいいですが、
チェンジタスクができないのが、唯一の難点のような気がします。
キャラクタごとにクラスを継承して作れば対応できる気もしますが、
どうなんでしょう。
0346名前は開発中のものです。
04/02/08 23:33ID:gPdyOEswそれからこの板は古典的タスクシステム=悪みたいな風潮があるようなので
趣味だけでひっそりやっていくことにします
さようなら
0347名前は開発中のものです。
04/02/08 23:48ID:+FkgUptrそれは主語がない(クラスに属さない)処理が存在する、ということでいいですかね?
>>343
そういうことだと思ってます。タスクが目的ではなく手段だってのはそういうことです。
>>344
衝突判定中のenemyポインタを保存しといて各弾についてenemyを復元しないと駄目よん。
0348名前は開発中のものです。
04/02/08 23:51ID:Mp5JYoERより直接的である、という古典的手法のメリットと富豪プログラミングの相性も良い。
古典的手法を飽きるまでやるのも入門に向くし。
飽きたら抽象度の高いものでちょっと頭をパズル向けに使って楽をすればよい。
いきなり理想論でたたみかけて初心者を煙に巻くのはオタクさんの悪い癖だ。
0349delphian
04/02/08 23:53ID:+Z9WcfXNようは、リストをたどって、各タスク(各クラス)を順に処理していくってことになりそうですね。
それで、当たり判定まではよいとして、描画でどうするべきか…。
描画は、同じく順にリストをたどって各キャラを描画していけばいいと思うんですが、、、
たとえば、当たり判定により自機と敵が衝突した場合、、、
古典的タスクシステムでは、自機タスクなり敵タスクなりを、
当たり判定のときに、チェンジタスクで爆発タスクに切り替えればいいですよね??
と同時にフラグを立てて、
描画タスクでは、フラグによって描くキャラを変えればいい、んですよね?(^^;
>>340
のようなシステムの場合は爆発等に移行するにはどうすれば…
0350名前は開発中のものです。
04/02/09 00:13ID:9b1YXsM8>>340のは出来ないね。オブジェクトの状態をオブジェクトの内部で保持してオブジェクトの内部でswitch。
>>341のは古典的タスクをC++に移植しただけなのでタスクチェンジできるよ。Task::m_workにメソッドを代入。
>>348
全くどの発言内容もご尤もだと思います。俺オタクだな…
ただこの方法が一番初心者に向いてると思うから書いてるわけで。
タスクってそれ自体はわかりやすいけど実際にコード組むと混乱の種にならない?
(実際に最初の質問の種はタスクから発生してるものだと思うし)
>>349
オブジェクトに衝突したことを知らせるためには、
オブジェクトにOnConflictという関数を持たせればOKだよ。
衝突したら、例えばこんな感じで。
enemy->OnConflict( shot );
shot->OnConflict( enemy );
後は各関数内で適当に状態移行。
0351delphian
04/02/09 00:14ID:tFE9u6feあ、これはもしかして、次のようなことですか!?
Workerクラスを継承して、各キャラクタクラスを作る。
Workは各キャラクタクラス内で使う処理メソッド。
これらを含めてタスククラスとする。
Workerクラス内で変数等を宣言、各処理メソッドを必要数分書く。
処理の変更の際には、m_workのみを書き換えれば、
変数等を保持したまま、処理のみを変更できる。
実行、処理の変更等は、TaskListクラスが管理する。
ということでしょうか!?
文法がdelphiと違うので、はっきりとはわからないのですが、
もしかしてそういうことですか!?
0352名前は開発中のものです。
04/02/09 00:24ID:9b1YXsM8大体合ってる。古典的タスクを使ってるなら馴染みやすいと思うんだけど…
補足するとTaskはTaskListに登録する際にハンドルとして受け取るような感じかな。
んでTaskクラスにsetWorkMethodが付くから処理の変更はTaskクラスでやります。
TaskListクラスにsetAllTaskWorkMethodみたいのを付けてやれば一気にEndとかもできる。
あと>>348にも言われちゃったのでどのやり方がいいとか言うのはやめることにします…
0353名前は開発中のものです。
04/02/09 00:26ID:S4Ub6c9m(・∀・) 人(・∀・)ナカーマ
0354delphian
04/02/09 00:33ID:tFE9u6feなるほど!!
クラスを使ったタスクシステムはできないと思ってたのですが、
こんな方法もあるんですね!!
この方法なら、タスクが自分で自殺とかもできそうですね。
2ch.には初めて書き込んだのですが、
詳しく教えていただいて、ありがとうございます!!
Delphiでも応用できそうなので、ちょっと一から作り直してみます!
あ、
>補足するとTaskはTaskListに登録する際にハンドルとして受け取るような感じかな。
この一文がよくわからないのですが、これはどういう意味でしょうか??
0355名前は開発中のものです。
04/02/09 00:41ID:9b1YXsM8list<Task>っていうのはTask構造体(=ポインタではない)のリストなので、
そのリスト上のTask構造体のポインタをハンドルとして受け取るということです。
0356delphian
04/02/09 00:45ID:tFE9u6feなるほど…。
ちなみに、タスクが自殺やチェンジする場合、全タスク実行後に処理したいので、
(削除済みのタスクへの不正なアクセスを防止するため)
その場合、Taskクラスではフラグを立てるだけにして、
TaskListのexecute時に削除等すればよいということですよね!
0357名前は開発中のものです。
04/02/09 00:51ID:9b1YXsM8うーん、ぶっちゃけてC#のDelegateですね。
0358delphian
04/02/09 00:58ID:tFE9u6fetypedef void Worker::(*Work)(); // Workerクラスのvoid method(); の形のメソッドポインタの型=Work
delphiで↑のような型の宣言ができるかどうか…、
それが一番の問題ですが、これさえできそうなら、
クラスを使ったタスクシステムができそうです!
タスクシステムを使わない、クラスでの処理の構成もわかりましたし、
なんとか、今よりはスマートになりそうです。
また、わからなくなると思いますが、
そのときはアドバイスもらえればと思います。
今日は寝ようと思います。
また、結果報告します!
ありがとうございました!!
0359名前は開発中のものです。
04/02/09 01:03ID:OX8rMmrZうちのは >>340風。
case文だらけが嫌になって、stateパターンを導入するも、
溢れ返った状態を記述しきれず泥沼化。
リファクタリングしようと、共通部分を is-a、 has-aでくくりだして、
フラットな状態遷移マシーンから、複雑な階層化状態マシーンに。
把握しきれずに、頭おかしくなりそうになった。
古典的タスクも考慮して組んで見たい今日この頃です。
>>354
Delphi使いはC++も読めると、世界が広がりますよ
考えようによっては、(C++ + Delphi)分の情報が得られるわけで
0360名前は開発中のものです。
04/02/09 01:11ID:OX8rMmrZすれ違いになっちゃうけど
Delphiだとこうかな?
type
TWorkerMethod = procedure of object; // クラスの procedure Method(); の形のメソッドポインタ型
TTask = class
FWorker: TWorker;
FWork: TWorkerMethod;
:
クラスのメソッドへのポインタは、"of object"をつけてね
0361delphian
04/02/09 07:26ID:tFE9u6feありがとうございます!
これで、できそうです!
>>350
追加で質問です。お願いします。
ちなみに、>>341の方法で実装したとして、
各クラスごとにタスクにあたる各メソッドを書くので、
リストへの登録・チェンジができるのは、登録したm_workerとそのクラス内のメソッドのみになるってことですよね?
あ、m_workerの登録を変えれば、他のクラスのメソッドにもチェンジできるのかな??
でも、それだと、変数が保持されないか…。
各クラスで共通で使うタスク(メソッド)があるときは、各クラスごとにメソッドをかかないといけないわけですよね?
0362名前は開発中のものです。
04/02/09 12:06ID:9b1YXsM8クラスのメソッドは所属するクラスに密接に関わる関数だから。
もし別クラスのメソッドを呼ぶような必要がでてきたのならば、
それはそのクラスにあるべきメソッドではないということです。
それから各クラスで共通に使うメソッドがあるならば、それは基底クラスで定義します。
タスクにメソッドを登録するときは基底クラスのメソッドを登録すれば問題ありません。
余談ですが341の方法は基底クラスの仮想関数を登録すると派生クラスの仮想関数が呼ばれます。
ややこしいので↓を見て実行すると分かりやすいかも。こちらもソースコードがややこしいことになってます…
http://www.emit.jp/prog/prog_cpp0.html
0363Delphian
04/02/09 12:48ID:ayzrG5Mj共通の関数を仮想関数として基底クラスに書いたとして、タスクリストに登録ししても、
実際、呼ばれるのは派生クラスの仮想関数ということですか?
つまり、派生クラスの仮想関数を登録するのとかわらない、ってことですか?
共通のタスクを使うにはどうすればいいんでしょうか?
質問だらけですみません(>_<)
0364名前は開発中のものです。
04/02/09 12:52ID:9b1YXsM8派生クラスでオーバーライドしなければ基底クラスの関数が呼ばれるよ。
というか初めから基底クラスで仮想関数として定義しなければ
派生クラスでオーバーロードしても派生クラスの関数は呼ばれないよ。
0365Delphian
04/02/09 13:57ID:ayzrG5Mjオブジェクト指向を勉強しはじめて、一ヵ月ならないもので(>_<)
ちょっと混乱してしまいました。
仮想関数をオーバーロードすると派生クラスの関数が呼ばれて、
仮想関数として定義しないと、基底クラスの関数が呼ばれるんでしたよね。
0366名前は開発中のものです。
04/02/09 14:50ID:CGO83cRkgoogleで双方の単語入れて検索してみればすぐわかる
0367Delphian
04/02/09 15:48ID:ayzrG5Mj全然違いますね。
とりあえず、帰ったら今日まで覚えた知識でクラス版タスクシステムをつくってみようと思います。
0368名前は開発中のものです。
04/02/09 18:17ID:3mvRD+VM0369名前は開発中のものです。
04/02/09 18:25ID:OX8rMmrZDelphiなら virtualなメソッドを、派生クラスでoverrideつけないで再定義すると、
警告出るからすぐにわかるよ
>>368
半透明つかえないのが前提だよね?
VSYNC同期前提でよければ、抜き色で市松模様にして交互に表示する
もしくは、単純に表示/非表示を繰り返す
同期取らなくてもそれっぽく見えるけど、ちらついてしょうがない
0370名前は開発中のものです。
04/02/09 19:15ID:gpj6YV2G場合によっては、赤 青 非表示 のように
補色と非表示を組み合わせて
輝きのある半透明感を出すのもいい。やりすぎるとドギツイだけになるので注意
市松模様もそのうちやってみてえなあ
0371名前は開発中のものです。
04/02/09 19:27ID:G+LxwaHn素直にアルファ使おうよ
0372Delphian
04/02/09 19:31ID:8wpz1habTWorker = class
end;
type TWork = procedure of object;
//タスククラス
type
TTask = class
protected
FStat: TStat; //タスクステータス
FPrio: Word; //処理優先度
FDelay: Cardinal; //待機フレーム数
FPrev: TTask; //前タスクへのポインタ
FNext: TTask; //次タスクへのポインタ
FKill: Boolean; //キルタスクフラグ
FChng: Boolean; //チェンジコールフラグ
FWorker: TWorker;
FWork: TWork;
FAttr: Word; //タスク属性(ユーザーが自由に使用できる)
public
constructor Create(Worker: TWorker; Work: TWork);
destructor Destroy; override;
procedure Execute;
end;
0373Delphian
04/02/09 19:34ID:8wpz1habこんな感じになったんですがどうでしょうか?
タスククラスにワーカークラスを登録する場合、
あらかじめ生成したワーカークラスを引数として渡して登録したほうがいいのか、
それとも引数にクラス型を渡して、タスククラス生成の中でワーカークラスを生成したほうがいいのか、
どうしたらよいでしょうか?
次から次にわからないことが…
0374Delphian
04/02/09 19:53ID:8wpz1habWorker* m_worker;
Work m_work;
public:
void execute() { m_worker->(*m_work)(); }
};
の部分は
class Task {
Worker* m_worker;
Work m_work;
public:
void execute() { m_worker->(*m_work)(Task); }
};
にした方がいいですかね?
じゃないと、処理メソッドの中で自殺等できませんよね?
でも、処理メソッドの中でdelete Taskとかされたらこまりますよね…
0375名前は開発中のものです。
04/02/09 20:45ID:9b1YXsM8その必要はないよ。
ちなみに俺も数年前はソレと同じやり方でやってたんだけどね
タスクを登録するときタスクリストでTaskのインスタンスを作るんだけど
そのインスタンスのポインタを登録関数の戻り値としてやって、
それを各ワーカーが保持しておけば何時でも参照できるよ
0376Delphian
04/02/09 20:52ID:8wpz1hab実装の段階になると、壁にぶちあたりまくって、
タスクはやめようかと思ってきました(>_<)
登録関数がインスタンスのポインタを返すとしても、
登録したタスク(クラス)の外部では保持できても、タスクの内部では保持できませんよね?
0377名前は開発中のものです。
04/02/09 21:00ID:9b1YXsM80378Delphian
04/02/09 21:12ID:8wpz1habつまり、ワーカークラス(を継承した各クラス)のコンストラクタでタスクリストに登録するということですか?
で、ワーカークラスを生成すると、自動的に自らをタスクリストに登録するような構造にするということですか?
なんか、そういう手間を考えると、やはりクラスとリストを使ったほうがいいのかなぁ…
汎用性はなくなりますけどね…
クラスを使ったタスクシステムや、>>329 >>341のような方法の載った
サイトや本がありましたら、教えてください。
C++でもかまいませんので…
0379名前は開発中のものです。
04/02/09 21:33ID:9b1YXsM8タスクシステムを辞めた理由の中にはそういうのもあります。
具体的に実装方法が載っている本のことは知らないけど、
私はABA Gamesさんとこのゲームのソースコードがいいかなと思います。
shot.cなんか読んだら、なんだ、こんな簡単なことなのか、と思うんじゃないかな。
ゲーム自体も名作なので一押し。
0380名前は開発中のものです。
04/02/09 21:34ID:9b1YXsM8http://www.asahi-net.or.jp/~cs8k-cyu/windows/noiz2sa.html
0381名前は開発中のものです。
04/02/09 21:40ID:r7Ky+9tE>181がC++でやってたみたいだが、消えてるし
0382名前は開発中のものです。
04/02/10 00:11ID:Qv9eDjn5親タスクから小タスクへどんどんタスクを生成して、階層上に回す。
状態はStateパターンの亜種で実装。破壊とかね。
管理は親タスクで、その管理はその親タスクで。
こんな感じの実装だったな。
利点はタスクによる処理の一貫性が得られる点と、
どの階層からでもタスクを再構築できる点。
オブジェクト指向とは相反する。
当然最良の方法でもない。
0383名前は開発中のものです。
04/02/10 05:03ID:QjDGv5K4その間にデータを読み込むというのはどうやったらできますか?
使っている言語はC言語です よろしくおねがいします
0384名前は開発中のものです。
04/02/10 05:31ID:ZekKaigmすぐ諦めて訊くやつ→無理
383、内容が薄すぎる。
自分で考えたんならもうちょっと建設的な質問ができるはずだぞ
0385名前は開発中のものです。
04/02/10 08:03ID:rQrFL9Aoその間にデータを読み込めば良い
0386名前は開発中のものです。
04/02/10 08:07ID:lQiCBpHNそれともマルチスッドレにしたいのかな?
0387名前は開発中のものです。
04/02/10 09:04ID:XIpFljSzNOW LOADING処理表示中に、細切れにしたデータを逐次読み込むか、データ
読み込み中にNOW LOADING処理を逐次呼び出すとか。
後者が楽だと思うけど、俺は画面処理を軸にしたいから前者の方が好きかな。
0388名前は開発中のものです。
04/02/10 09:08ID:qDkTjytkCreateFile 非同期 で検索汁
0389Delphian
04/02/10 12:58ID:X/1Dxz8Qぁ、ワーカークラスのコンストラクタでタスクリストに登録すると、
継承したクラスごとに優先度とか変えられないですね。
そういういろいろややこしくなることを考えると、
やっぱりゲームごとにクラス作っていこうと思います。
みなさん、ありがとうございます!
0390Delphian
04/02/10 17:06ID:X/1Dxz8Q実際、タスク使ってつくる人より、
普通にクラスを使ってつくる人のほうが多いんですかね?
C++でいいのでゲームプログラミングでおすすめの本があったら、
教えてもらえるとありがたいです。
できれば中高度くらいで…
3Dものは作る予定ありません。
0391名前は開発中のものです。
04/02/10 22:49ID:jnigZ/TI0392名前は開発中のものです。
04/02/10 23:12ID:hqZnD59D0393名前は開発中のものです。
04/02/10 23:13ID:TgKzx3qfまずプログラムの基礎を勉強するべきかと。
この辺の本とか、
http://www.amazon.co.jp/exec/obidos/ASIN/479800314X/ref=sr_aps_b_/249-6758129-5407516
http://www.amazon.co.jp/exec/obidos/ASIN/4798006033/ref=pd_bxgy_text_2/249-6758129-5407516
C++の便利な使い方も書いてあるので読め。
0394名前は開発中のものです。
04/02/10 23:30ID:8DmWCK/o古典的手法でガレッガや怒蜂は十分作れるYO
本が合う人は本でやってみるのもいいと思う。
もしそれでできなくても挫けるな。
どんな泥臭い方法でも、まずは動いて遊べるゲームを一つ完成させることだ。
一つもできないうちからウダウダやってると限りある人生ムダにすることになるぜ
0395名前は開発中のものです。
04/02/11 00:54ID:ffzykx9Oで、もっと良い方法ないかなと模索する。
結果、タスクなりオブジェクト指向なりに行くと。
タスクに関してアセンブラと少ないメモリで少しでも
すっきりした形で作ろうした結晶のひとつ。
いきなり理解しようとするのが間違っている。
オブジェクト指向しかり。
0396名前は開発中のものです。
04/02/11 01:03ID:HavUqnN10397名前は開発中のものです。
04/02/11 13:33ID:WVAdP0V+WS→GBAと渡り歩いたら必然的にこうなったような。
しかしC++を覚えにくくなるという諸刃の剣。
結城浩尊師が御本を執筆なさる日を待っているとかいないとか。
0398名前は開発中のものです。
04/02/11 14:20ID:FwrI7GbYint y[MAX];
int kind[MAX];
for (int i = 0; i < MAX; i++) { ... }
こういうBASIC時代の身も蓋もない実装を、アセンブラやCで正常進化させていけば、
勝手に古典的タスクに行き着きますな。
俺も含めて、すべてのオヤジゲームプログラマが辿った道でしょう。
んでもってC++覚えたらゲームオブジェクトやらエンティティやらシーングラフやら
OO的アプローチで取り組んでみると。
歴史をそのまま辿ってるので、今どきのわきゃーモンにとって効率のいい道かは……
まあ、若いんだし、回り道してみてもいいんじゃない?と思うけどね(w
0399Delphian
04/02/11 16:05ID:3Fwk/VlRとりあえず、ここでアドバイスをいただいて、
オブジェクト指向でのゲームプログラミングについて、
わかってきました。
同じキャラクタが簡単に複製できるのでよいですね!
もう一歩レベルアップしたいのですが、
それは、あたり判定、、、(?)です。
シューティングというか、アクション要素の強いものにするつもりなんですが、
どういう方法をとればいいのかわかりません。
0400Delphian
04/02/11 16:06ID:3Fwk/VlR移動とか描画のイメージとしてはボンバーマンをイメージしてもらえると、
わかりやすいかと思います。
たとえば、1キャラ32×32のサイズだとして、
1キャラ単位の移動の場合には、
(右に移動するときは、8ドットずつ描画。
1キャラサイズ分移動するまでは操作できない)
キャラの座標を元に、スプライトを優先度順に描画して、
当たり判定も座標位置から処理することができますよね?
(この場合、当たり判定というより、座標からのチェックですね。)
これをドット単位の移動にしたい場合、
どうすればよいのでしょうか?
■ このスレッドは過去ログ倉庫に格納されています