トップページgamedev
935コメント361KB

OOとゲームプログラミング

■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。01/11/07 23:55ID:HnYWCQK1
OOをどのように用いれば美しくゲームプログラミングを
行うことが出来るのか語り合うスレです。
021120601/11/12 01:09ID:???
>>210間違い
それぞれのab_collectionから継承させたオブジェクトで
>for(vector<ab*>::iterator i=abc.begin(); i!=abc.end(); i++){ (*i)->update(_stat); }
を呼ぶのは愚の骨頂ですね。ab_collectionに置くべき処理でした。
失礼…。
0212名無しさん@お腹いっぱい。01/11/12 03:36ID:???
少なくともPCゲームのプログラムを組む場合、
C++を利用したことによるオーバーヘッドはほとんど
気にしなくていいような気がします。
0213名無しさん@お腹いっぱい。01/11/12 07:13ID:???
PC(Windows)のゲームでメモリの断片化気にして組まれてるのはどのくらいあるんだろ…。
0214名無しさん@お腹いっぱい。01/11/12 07:56ID:???
というか断片化の話はoperator newのオーバーロードで対処。
CTaskの継承クラスのサイズに最大128バイトとか制限かけて、
メモリプールから確保するようにする。
0215名無しさん@お腹いっぱい。01/11/12 21:17ID:???
>というか断片化の話はoperator newのオーバーロードで対処。
オーバーライドだと思うが…。
細かい突っ込みかな。

malloc自体が仮想メモリを利用することが前提の関数だし、おそらくnewもそうだろうと思います。
仮想メモリがある環境だと、あまりメモリの分断化は気にしないかも。
コンシューマだとガベージコレクトやメモリコンパクションやらを考えないと
いけないでしょうね。
メモリマップを始めにきっちりと作るというのも手だと思いますけど。
0216名無しさん@お腹いっぱい。01/11/12 21:24ID:???
>>215
オーバーロードでも対処できるよ。
newに特殊なパラメータ(フラグ)を取らせてそれによって、デフォルトのnewとは
動作を変える。
この場合、newの動作が暗黙のうちに最適化されるのではなく、プログラマが必要
に応じてメモリ割り当ての方法を選択できる。
うまくやれば、こっちの方が便利かもしれないよ。
0217名無しさん@お腹いっぱい。01/11/12 21:28ID:???
昔、擬似タスク処理をC++で実現しようとしたとき、処理とその処理で使う
メモリ領域をどうすり合わせるかで挫折した。

Cの場合は、構造体内部に関数へのポインタがあればそれを切りかえることで
簡単に実現できた。
C++の場合、上記メソッドのオーバーロードで簡単に実現できるのはひとつの
メソッドだけ。
無理やりやろうとすると、オーバーロードするメソッドの中で
処理するメソッドへのポインタを利用して処理を飛ばすという、
なんとも汚いものになった。
こんなことするくらいなら、構造体+関数へのポインタで処理させたほうがまし
だと思った。
0218名無しさん@お腹いっぱい。01/11/12 21:36ID:???
>>217
ごめん、ちょっとわかりにくい。
「オーバーロードで簡単に実現できるのは1つだけ」というのは
operator newのオーバーロードが1つだけってこと?
0219名無しさん@お腹いっぱい。01/11/12 23:02ID:aPZmJhKt
>処理するメソッドへのポインタを利用して処理を飛ばすという、
>なんとも汚いものになった。

あまり解釈に自信がないんだけど、例えばこういうの? 汚いかなあ。

typedef void(Task::*TaskFunc)();

class Task {
public:
  void SetMethod(TaskFunc updateFunc) { m_updateFunc = updateFunc; }
  void Update() { (this->*m_updateFunc)(); }
private:
  TaskFunc m_updateFunc;
};

class HogeTask : public Task {
public:
  HogeTask() {
    SetFunc((TaskFunc) Func1);
  }
  void Func1() {
    ...
    SetFunc((TaskFunc) Func2);
  }
  void Func2() { ... }
  void Func3() { ... }
};
022021901/11/12 23:06ID:???
こうやってTaskManagerから直接呼び出してもいいか。

class Task {
  friend class TaskManager;
public:
  void SetMethod(TaskFunc updateFunc) { m_updateFunc = updateFunc; }
private:
  TaskFunc m_updateFunc;
};
022121901/11/12 23:07ID:???
ギャース
s/Method/Func/g
0222名無しさん@お腹いっぱい。01/11/13 00:29ID:???
C++のソースはなぜこうも美しく無いのだろうか?
0223名無しさん@お腹いっぱい。01/11/13 00:30ID:???
>>222 Cで同じもん書いてみてみそ。
0224名無しさん@お腹いっぱい。01/11/13 04:25ID:???
Cの人はなぜ、継承だけで解決しようとしたり、
C++で関数ポインタ使うのはイヤみたいに言うのかわからん。
0225名無しさん@お腹いっぱい。01/11/13 10:18ID:???
とりあえず、タスクを1ステップ進行させるメソッドの名前は
みんなUpdateですか。
0226名無しさん@お腹いっぱい。01/11/13 13:13ID:ClbS1Bbe
もうvirtual関数無しではプログラム組めないっす。

ゲーム系だと特に期限ギリギりでの仕様変更が多いので(仕様書な
んてものが存在しない場合も多いけど)、パッチ当てる感覚でその場
がしのげて良いです。

その後の事はしらん(藁。
0227名無しさん@お腹いっぱい。01/11/13 14:05ID:FoEbYEta
>>219
Func1 は
typedef void (HogeTask::*FuncType)();
であって、
typedef void(Task::*TaskFunc)();
ではない。
メンバ関数へのポインタはクラスによってサイズが違うという話を聞いたんだが、
SetFunc((TaskFunc) Func1);
このキャストは安全なのか?
0228名無しさん@お腹いっぱい。01/11/13 14:08ID:???
典型的なC++のタスクと、Game Programming Gemsの3.0みたいな
マクロ使った状態マシン組みあわせてみない?
オレは今から試すにょ。
0229名無しさん@お腹いっぱい。01/11/13 14:17ID:???
>>227
安全じゃないからキャストしてると思われ(w
仕様上は安全じゃない(プログラミング言語C++第3版15.5.1)が、
C++の実装上は上手くいくのではないか。
ちとキモチワルイ感はある。
0230名無しさん@お腹いっぱい。01/11/13 14:36ID:???
ありゃ、キャストしたからってうまくいくのか?
エラーが出そうなものだが。

g++でコンパイルしてみたけど、駄目だった。
コンパイラの問題かな。
0231名無しさん@お腹いっぱい。01/11/13 14:58ID:???
こんなのどう?

#define DECLARE_TASK(TypeName) \
void (TypeName::*m_updateFunc)();\
public:\
virtual void Update(){(this->*m_updateFunc)();}\
private:\

#define SET_TASK_FUNC(FuncName) {m_updateFunc = FuncName;}

class Task
{
public:
  virtual void Update() = 0;
};

class HogeTask : public Task
{
  DECLARE_TASK(HogeTask)
public:
  HogeTask(){
   SET_TASK_FUNC(Func1);
  }

  void Func1(){
   …
   SET_TASK_FUNC(Func2);
  }
  void Func2(){};
};
023221701/11/13 15:31ID:4q6jfi+W
わたしが昔、書いたのは大体こんな感じでした。
219さんのソースを利用させてもらいます。

extern "C" {
#include <stdio.h>
}

//-----------------------------------------------------------
// 基本擬似タスク
//-----------------------------------------------------------
class Task {
public:
 Task() {};
 virtual ~Task() {};
 virtual void SetFunc(void) {}
 virtual void Update(void) {}
};

//-----------------------------------------------------------
// 擬似タスク定義部
//-----------------------------------------------------------
class HogeTask;

typedef void(HogeTask::*TaskFunc)(void);

class HogeTask : public Task {
public:
 HogeTask() { SetFunc(&HogeTask::Func1); }
 ~HogeTask() {};

 void SetFunc(TaskFunc updateFunc) { m_updateFunc = updateFunc; }
 void Update() { (this->*m_updateFunc)(); };

 void Func1() { printf("Func 1\n"); SetFunc(&HogeTask::Func2); }
 void Func2() { printf("Func 2\n"); SetFunc(&HogeTask::Func3); }
 void Func3() { printf("Func 3\n"); SetFunc(&HogeTask::Func1); }
private:
 TaskFunc m_updateFunc;
};
023321701/11/13 15:32ID:4q6jfi+W
続き
//-----------------------------------------------------------
// 擬似タスク実行部
//-----------------------------------------------------------
class ExecuteTask {
 Task *taskArray[100];
 int iTaskPoint;
public:
 ExecuteTask() { iTaskPoint = 0; }
 void SetTask(Task* prtTask) { taskArray[iTaskPoint++] = prtTask; }
 void execute(void) {
  {for(int i = 0; i < iTaskPoint; i++) {
   taskArray[i]->Update(); }
  }
 }
};
023421701/11/13 15:34ID:4q6jfi+W
最後

//-----------------------------------------------------------
// メイン
//-----------------------------------------------------------
int main(int argc, char** argv) {
 HogeTask hogeTask;
 HogeTask hogeTask2;
 ExecuteTask executeTask;

 printf("<<1st>>\n");
 executeTask.SetTask(&hogeTask); // タスク1セット
 executeTask.execute(); // タスク実行

 printf("<<2nd>>\n");
 executeTask.execute(); // タスク実行

 printf("<<3rd>>\n");
 executeTask.SetTask(&hogeTask2); // タスク2セット
 executeTask.execute(); // タスク実行

 return 0;
}
023521701/11/13 15:43ID:???
実際は、タスク実行終了時の資源の解放とか、タスク実行順序とか
いろいろ機能がありました。
ともあれ、結局構造体+関数へのポインタで実装したほうが
分かりやすい上に、パフォーマンスの上という理由で捨てました。
0236名無しさん@お腹いっぱい。01/11/13 15:46ID:???
>>230
VC だとメンバ関数のアドレスはその名前だけでよいが、
C++ の仕様だと &クラス名::関数名 でないとダメ
そこ以外でエラーはでないと思われ
023723001/11/13 20:52ID:???
>236
うむ確かに、うまくいった。
つうか、なぜ気がつかない、俺。

こうなると、219のコードが一番スマートなのかな?
キャストが嫌ってことなら、231になるか。
0238名無しさん@お腹いっぱい。01/11/13 21:09ID:xYb3Zs4n
試しにこんな感じにモデル化してみたんですが、どんなもんですかねえ。
これをいかに楽に記述する方法を考えるかみたいなー。
何かタスク記述言語でも作って、
C/C++ソースに変換するフィルタでも用意するのがええかのう。

タスク {
  タスク変数
  タスクの状態

  タスク作成時の処理
  タスク破棄時の処理
  汎用イベント処理

  状態1 {
    状態の初期化
    更新処理
    状態の後始末
    汎用イベント処理
  }
  状態2 {
    状態の初期化
    更新処理
    状態の後始末
    汎用イベント処理
  }
  ...
}
023923001/11/13 21:25ID:???
なんかここまで来ると、クラスの必要ないじゃないか
って感じもするな…。

#include <iostream>

class Task;
class TaskManager;

typedef void(Task::*TaskFunc)();

class Task {
 friend class TaskManager;
public:
 void SetFunc(TaskFunc updateFunc) { m_updateFunc = updateFunc; }
 // void Update() { (this->*m_updateFunc)(); }
private:
 TaskFunc m_updateFunc;
};

class HogeTask : public Task {
public:
 HogeTask() {
  SetFunc(static_cast <TaskFunc> (&HogeTask::Func1));
 }
 void Func1() {
  cout << "Func 1\n";
  SetFunc(static_cast <TaskFunc> (&HogeTask::Func2));
 }
 void Func2() { cout << "Func 2\n"; }
 void Func3() { cout << "Func 3\n"; }
};

class TaskManager {
 Task *taskArray[100];
 int iPoint;
public:
 TaskManager() { iPoint = 0; }
 ~TaskManager() {}
 void setTask(Task* task) { taskArray[iPoint++] = task; }
 void execute(void) {
  {for(int i = 0; i < iPoint; i++) {
   (taskArray[i]->*(taskArray[i]->m_updateFunc))();
  }}
 }
};
0240名無しさん@お腹いっぱい。01/11/13 22:00ID:???
でも、Cで書いてUpdate関数にp->xとかp->vxとか並びまくったり、さらに
#define VX (p->vx)
みたいな真似をしたりするのもどうも気が引けるとゆーか・・・。
0241名無しさん@お腹いっぱい。01/11/14 12:35ID:???
オブジェクトの挙動のパフォーマンスなんて
多少高かろうが低かろうが屁みたいなもんじゃん。
描画エンジンの都合で……ならわかるけど。
0242名無しさん@お腹いっぱい。01/11/14 12:52ID:???
>>241
文句言っている人は、たぶんコストが無視できないプラットフォームで作ってるんですよ・・・。
0243名無しさん@お腹いっぱい。01/11/14 23:11ID:???
age
0244名無しさん@お腹いっぱい。01/11/15 00:27ID:rnP2aOWi
>>241
んなことはない。
オブジェクト指向ヲタはSetPixel,GetPixelとかまで仮想関数
にしたがるから。
それにパフォーマンスが問題にならないような上位層はスクリプトにするのが普通だし。
0245名無しさん@お腹いっぱい。01/11/15 00:36ID:???
>>244
それ描画まわりじゃねえか
0246名無しさん@お腹いっぱい。01/11/15 01:25ID:???
>>241
そういう簡単な挙動しか実装しない場合は
オブジェクト指向化の恩恵も少ないと思われ。
0247名無しさん@お腹いっぱい。01/11/15 02:14ID:???
>>239
たぶんサンプルコードだからだと思うけど、
Task *taskArray[100]; とかがいや。std::list使おうよぅ
0248名無しさん@お腹いっぱい。01/11/15 11:09ID:???
>>247
禿同。
0249名無しさん@お腹いっぱい。01/11/15 12:18ID:uH85Rn+s
皆さんどうしても関数ポインタ使わないと気が済まないの?
なんで?
パフォーマンスのため?
タスクシステムを忠実にC++で再現したいから?

CSomeTask::update ()
{
 switch(this->mode){
 case UPDAETMODE_DEFAULT:
  this->do_default ();
  break;
 case UPDATEMODE_PAUSE:
  this->do_pause ();
  break;
 case UPDATEMODE_DEBUG:
  this->do_debug ();
  break;
 }
}

実際これでほぼ十分でしょ。
0250名無しさん@お腹いっぱい。01/11/15 12:36ID:???
まあ、実用上はそういうコードでほぼ大丈夫なんだけども。

>タスクシステムを忠実にC++で再現したいから?
それに加えて、激しく状態遷移するタスクのデバッグは
もうこりごりってのもあるです。
0251名無しさん@お腹いっぱい。01/11/15 13:55ID:???
>249
ゲーム全体で擬似的なスレッド処理を実現させたいからだと思われ。
背景をスクロールさせながら、ウィンドウをアニメショーンさせつつ移動させたり
するのをスレッドで実装すると分かりやすいからでしょう。
普通に、ループのなかでやるとifの連発になりそうだし。

>std::list使おうよぅ
STLを使うとついてこれない人がいるから…。
という冗談はさておき、サンプルだからでしょう。
0252名無しさん@お腹いっぱい。01/11/15 14:27ID:???
>>249はその「擬似的なスレッド処理」の中身だと思うですが。
0253名無しさん@お腹いっぱい。01/11/15 15:05ID:???
>>249
汎用性の問題。
関数ポインタの場合はswitchと違って、
機能を増やしても書き直す必要がない。
0254名無しさん@お腹いっぱい。01/11/15 17:07ID:???
ついでに
C++のメンバ関数へのポインタでやると
関数1つ追加ごとにヘッダーへの変更が発生するのも問題。
privateな関数をどうしてヘッダーに書かねばならん!
0255名無しさん@お腹いっぱい。01/11/15 17:56ID:???
>>251
listは遅いのでvector使おう。
0256名無しさん@お腹いっぱい。01/11/15 19:27ID:???
あんまり関数ポインタを多用するのは
オブジェクト志向っぽくない気がする。
0257名無しさん@お腹いっぱい。01/11/16 00:18ID:RSv3E/5D
>254
C++は、クラス定義を見ただけで、だいたい何をやってるか分かって
便利だと思っていた俺は厨なのかしらん。

っていうか、みんなVC++のClassViewを使いませんか?
0258名無しさん@お腹いっぱい。01/11/16 00:30ID:???
>>241
何言ってるのよ
市販品かいとりますがな
0259名無しさん@お腹いっぱい。01/11/16 00:31ID:qXQUQt+7
>257
MFCに不満が山ほどあるから、使ってない。
0260名無しさん@お腹いっぱい。01/11/16 00:42ID:???
>>255
あのコードだとタスクは死なないみたいだけど、
ふつー死ぬでしょ 順番かんけーなく
eraseのコスト考えたらlist
0261名無しさん@お腹いっぱい。01/11/16 00:47ID:???
ClassViewマンセー

>>259
SDKベースでもClassViewは使えるよ。コード補完も。
0262名無しさん@お腹いっぱい。01/11/16 00:59ID:???
>>261
あ、ClassViewか
スマソ、ClassWizardと勘違い
0263名無しさん@お腹いっぱい。01/11/16 01:54ID:???
ちなみに、タスク間のデータの受け渡しって、みなさんどうやってます?

enum{
WORK1,
WORK2,

WORK_MAX,
};
DWORD Work[WORK_MAX];
をグローバルで宣言して共用してます。

もっとスマートで近代的なやり方を教えてプリーズ。

OOと関係無い可能性があるので、sage
0264名無しさん@お腹いっぱい。01/11/16 03:09ID:???
ソケット
026525401/11/16 06:16ID:???
>>257
べつにヘッダーに書く手間が面倒なわけじゃない。
外部が使用するインターフェースに変更があるわけじゃないのに
内部に機能を追加するだけで、インターフェースを使用している
モジュールに再コンパイルがかかるのが嫌なだけ。
026625401/11/16 06:21ID:???
しまった、俺もClassWizardと勘違い
0267名無しさん@お腹いっぱい。01/11/16 15:25ID:???
>>265 Bridgeパターン
026825401/11/16 15:58ID:???
結局、派生先を生成してるファイルは再コンパイルせないかん。
まぁそのくらいはどうでもいいが、いちいち基底クラス作って
どうたらこうたらなんてやってられんと思うのだが…
0269名無しさん@お腹いっぱい。01/11/16 18:20ID:???
>>268
VC++使ってると全然気にならないんだけどな。
0270名無しさん@お腹いっぱい。01/11/16 23:37ID:???
Delphi使ってると再コンパイルの手間すら気にならんけどな。
0271名無しさん@お腹いっぱい。01/11/17 00:32ID:9iW0SS+5
仕様がしっかりしている場合に限るけれど、
こーゆー書き方なら、たまぁにする。
class CMain;
class CSub
{
public:
CSub(){}
virtual ~CSub(){}
virtual void FunkA(CMain*pMain) = 0;
virtual void FunkB(CMain*pMain) = 0;
};
class CSubNull : public CSub
{
public:
void FunkA(CMain*){}
void FunkB(CMain*){}
};
class CMain
{
CSub*m_pSub;
static CSubNull m_SubNull;
public:
CMain(){ m_pSub = &m_SubNull; }
virtual ~CMain(){}
void FunkA(){ m_pSub -> FunkA(this); }
void FunkB(){ m_pSub -> FunkB(this); }
void SetSub(CSub*pSub)
{
if(pSub == NULL)pSub = &m_SubNull;
m_pSub = pSub;
}
CSub*GetSub(){ return m_pSub; }
};
0272名無しさん@お腹いっぱい。01/11/17 00:51ID:???
それは立派なStateパターンでんな。
0273名無しさん@お腹いっぱい。01/11/17 13:55ID:???
C使いでC++がダメ!って言う人は、実装継承とか深い継承とかを試してみてダメって言ってる気がする。
デザインパターン勉強すれば便利に使えるんだけど、使えるかどうか試してみるだけの人にデザパタ勉強しろとは言えないからなぁ。
0274名無しさん@お腹いっぱい。01/11/17 18:20ID:???
OOの真髄はデザインパターンによるコーディングのパターン、及びテンプレート化だからなぁ・・・
ボトルネックとか、無駄な継承等を最適化していったら、どっかで既に使われていたパターンの
亜流だったなんての事は、実際かなりあったよ・・・
0275名無しさん@お腹いっぱい。01/11/17 19:25ID:???
>>273
意味不明
0276名無しさん@お腹いっぱい。01/11/18 02:39ID:???
>>275
デザパタの学習をやり出せば解る。
デザパタはOOを十分理解してる事が前提で話を進めてるので。
0277ラム01/11/18 09:59ID:m/JYi1e1
ageるっちゃ。
0278名無しさん@お腹いっぱい。01/11/18 10:48ID:???
>>276
違う、そういう意味じゃない。デザインパターンまで実務に使ってる。
キミの言ってることのつながりが全然わからないと言っている。
0279名無しさん@お腹いっぱい。01/11/18 20:54ID:???
ゲ技版にもデザパタ馬鹿が出るのか・・・・。
0280名無しさん@お腹いっぱい。01/11/18 21:18ID:???
別になあ、今更デザパタでもなかろうに。
つかっててあたりまえだといいたいんだろう? >>279
0281名無しさん@お腹いっぱい。01/11/18 22:29ID:???
Design Pattern for Computer Games
http://www.totempole.net/patterns/gamepatterns.html
こんな試みもあるがね。
0282名無しさん@お腹いっぱい。01/11/19 22:42ID:???
とてもヨワヨワな質問でスマソ。
カードゲームを作ろうとしたときカード1枚1枚をクラスとして扱う?
カードの枚数だけクラスが出来るんかな…
0283名無しさん@お腹いっぱい。01/11/19 23:38ID:???
>>282
MT:G 系のカードごとにルールがあるカードゲーム?
カードクラスとルールクラスで構成するか、それぞれをクラスにするかだね。
Prototype や Flyweight パターンを参照してみて。
↓だけじゃ分からないと思うけど、参考までに。
http://www.ff.iij4u.or.jp/~ahirusan/Java/patterns/prototype.html
http://www.ff.iij4u.or.jp/~ahirusan/Java/patterns/flyweight.html
0284名無しさん@お腹いっぱい。01/11/20 00:08ID:???
さっそくのお答えありがとです。
Flyweight パターンが近そうなので
もうちょっと勉強してみます。
0285名無しさん@お腹いっぱい。01/11/20 20:34ID:???
太閤立志伝Iは、オールアセンブラと思われる古いゲームだが
オブジェクト志向してたんじゃないだろうか。
基底クラス武将を継承するプレイヤー武将クラス、大名武将クラス、一般武将クラス。
それらのオブジェクトが家臣団ツリー構造で管理され、
マルチスレッド処理で並列で動いてる。
当時これをつくったひとは本当に天才だとおもう。
ずっと後に出た、これと似たシステムのガンパレードマーチはさんざん自慢しまくってたが。
0286名無しさん@お腹いっぱい。01/11/20 21:25ID:???
大抵のゲームプログラマーはとっくの昔に自分でOOPやデザパタ発見してるよ。
本に出てるのは他人に教えても良いゴミテクと知れや。
0287名無しさん@お腹いっぱい。01/11/20 23:36ID:2YNiudBT
>>99

例えば、ゲームボーイとか、タイトなパフォーマンスが要求されるとことか、
まぁあったでしょうけど、やっぱ今後は開発効率の向上が必須項目。

例えば、全部組み込みJavaでゲームが書かれるようなことにも数年後にはなり
かねないしさ。

>101
モジュールやデータ構想の勉強っって何ですか?
0288名無しさん@お腹いっぱい。01/11/20 23:43ID:???
タイトなパフォーマンスが要求されないゲームってPCぐらいしかないんじゃ?
アマですか>287
0289名無しさん@お腹いっぱい。01/11/21 07:35ID:???
>>286
こういうやつよくいるわ。
0290名無しさん@お腹いっぱい。01/11/21 11:44ID:kTxoHJqc
ま、とりあえず>>286がデザインパターンの存在意義を
理解してないのは分かるわねー。
0291名無しさん@お腹いっぱい。01/11/21 12:33ID:???
個人的にはパフォーマンスよりも
開発効率のほうが今後のネックだと思うが。
納期に追われたこと無いの?>288
0292名無しさん@お腹いっぱい。01/11/21 17:02ID:???
+→描画デバイス
+→シーン+→キャラクタ→モーション
     +→キャラクタ→モーション
なんて風にオブジェクトを階層構造にしてるとき
キャラクタの描画メッセージは、どいつがどのように送りますか?
それとも、こんな構造にはしませんか。
0293名無しさん@お腹いっぱい。01/11/21 20:28ID:7vVUdWJ9
>>286
確かにデザパタ厨房は、
今は物理シミュレーションの時代だとか言ってるゲーハー厨並に痛いけど
(そんなのファミコン時代からやってるって…)

デザインパターン自体には、
昔からの手法に共通の名前を与えるという意義はあると思う。
0294名無しさん@お腹いっぱい。01/11/21 20:52ID:BPHGewxM
>>271-272みたいな感じでんな。
プログラマ間の意思疎通がシャア並みに速くなる。
029528601/11/21 23:12ID:ukm0fF12
>>293
逆に名前がついてないと頑なに認めないのが一杯居て困る事多し。
1)マルチスレッド的プログラム構造の実際。
2)外部からの通信でどのような状態にも自由に遷移できる構造
3)どのような状態でもメッセージを受け取れる構造
4)正規の処理以外のエラー処理への随時対応可能構造
といった事を教えても「スタイルの違い」と理解せず変更せず、
挙句の果てに人のバグだと言い始める逐次プログラマーの多いこと
多いこと。
0296名無しさん@お腹いっぱい。01/11/21 23:16ID:zJxGH1jK
それは、貴殿が新しいパターンを作って文書化すればいいのでわ。
GoFとかに載ってるのだけがすべてじゃないよ。
0297HN01/11/21 23:22ID:qbFQMeve
> http://www1.linkclub.or.jp/~zhidao/zlab/
> オブジェクト指向を用いてぷよぷよを作る記事がある。

ウェブページだけ見ていて、ソースはそんなに真剣には見てはいなんだけど・・・。

これはこれで、イイっていえばイイのかもしれないんですけども。
オブジェクト指向の例題とするには納得しかねるなぁ〜。

1)
連鎖発生時の「ファイヤ〜」「ばよえ〜ん」とか、ここはキャラクター
が変わることによってメッセージが変わるわけだから、ここでこそ、
Character クラスでも作るのがイイのでは。

2)
Puyo クラスの中に座標を持っているんですけど、これは
明らかに無意味なような気が。

まぁもし、ぷよ一つ一つが、特別な性質を持っていて(例えば、
赤ぷよだけ5つ繋がらないと消えないとか、黄色ぷよを消すと
回りのぷよも変色するとか)そういうことなら、Puyo クラス
でも作って、自分が存在する座標とゲームフィールドの参照を
持って設計するのが、正しいと思うんですけど・・・、うーん、
ぷよぷよっていうゲームの場合、ルールは完全にゲームフィー
ルド毎に決められてるんだから、べつにint型の二次元配列
でやっても、一向にかまわないと思いますよ。

後は、MVC の分離をきっちりやるといいのかなぁ〜。でもこれも
単純なゲームにおいてはほとんど無意味だからやらなくていいか。

まぁ、ぷよぷよというゲームの本質とOOPはあまり関係ないやね。
0298HN01/11/21 23:27ID:qbFQMeve
Model(ゲームデザインの部分)のコト書いたんですけども、

View(表示する部分)の話でしたら、Puyo クラス書く意味は
大いにありますよね。消すときのエフェクトは、ぷよの色ごと
に違ったりしますから、その Puyo クラスごとに絵画方法を
定義すればラクチン。
0299HN01/11/21 23:28ID:qbFQMeve
ごめん、↑の2つ、ミス
0300マルチポストは止めよう01/11/21 23:36ID:???
どうでもいいけど語尾の『なぁ〜。』って口癖?
0301名前は開発中のものです。01/11/25 17:49ID:LE15OAAJ
age
0302きえさっぱ01/11/26 01:21ID:???
んー、ぷよぷよをOO学習のサンプル題材として議論しているのは
分かるんだけど、ベーシックでもできるものなので、題材として
適切かどうかはちょっと疑問だと思うー

「再帰呼び出し学習材料」としてなら、ぷよぷよは好材料だと思うけど。
0303_01/12/01 02:43ID:psjJyxPy
age
結局、タスクマネージャC++版は、デキなんですかね?
0304名前は開発中のものです。01/12/02 13:44ID:???
>デキなんですかね?

どう言う意味ですか?
0305名前は開発中のものです。01/12/12 13:09ID:T2PuoAFH
salvAGE
0306名前は開発中のものです。01/12/17 16:26ID:???
OOやるならレミングスとかが良いんじゃないかなー。
正直ぷよぷよはOO向きではないよね。
0307名前は開発中のものです。01/12/31 23:56ID:6Qd2dWNa
下がってる…。

やっぱり RPG 系こそOOの真価が発揮されると思うんだけど。
0308名前は開発中のものです。02/01/01 12:43ID:YwsXNczB
というか日常的に考えてシナリオとかプロジェクトというものをOO的に変換して
うまくいかないんだから
プログラムを全部OOでやろうってのがどだい間違いでは?
0309名前は開発中のものです。02/01/01 14:59ID:7Da5Jozt
>>308
じゃあ何ならうまくできるの?
構造化言語?アセンブラ?

速度的な問題点っていうのは別として、
組み方としてうまくいかないって言う人は絶対 OO 解っていない人だよ。
0310名前は開発中のものです。02/01/01 15:56ID:???
全部OOでやろうってのは非効率的(になることが多い)。
■ このスレッドは過去ログ倉庫に格納されています