- ベストアンサー
ソースの分け方がよく分かりません
ソースの量が増えてきたので分けることにしました。 ・メインのソース ・クラスの定義のヘッダ(1),(2) ・クラスのメンバ関数の定義用のソース(1)、(2) このように3種類の構成にしています。 そして、クラス(1)の実体は次のように配列の形で作ります。 int aaa[] = {1,2,3}; const int Num = (sizeof aaa /sizeof aaa[0]); static DATA data[Num]; しかし、上記のコードをどこに書けば良いか分からず、とりあえずクラス(1)のソース内に書いたんですが、クラス(2)のヘッダとソース内でもNumを使うため、このままではNumが定義されていないというエラーになります。一体どのように書くべきでしょうか。よろしくお願いいたします。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
あっ直し忘れました。 Enemy.hはこれが正解です。 /*ここからEnemy.h*/ #include "../../../../Selene.h" using namespace Selene; class ENEMY_DATA { public: enum eState { STATE_STANDBY, STATE_ACTIVE, } State; private: Scene::IModelActor *pActor; Math::Vector3D vPosition; Math::Vector3D vStartPos; public: void Initalize(Math::Vector3D EnemyPos); void Create( Scene::ISceneManager *pScene, Renderer::Object::IModel *pModel); void Update(Sint32 Time); void Rendering( void ); };
その他の回答 (4)
- zwi
- ベストアンサー率56% (730/1282)
ソースを見て理解しました。クラスとしての設計が間違っています。 クラスの構造を見ると手続き言語の組み方でクラスを書いていますね。 1つのクラスは1体に敵データを保持して、一体のデータだけを処理する形に組みなおす必要があります。 こんな感じ↓。初期化までしか書いてないです。 void dummymain(void) { // 将来的には、データファイル移すべきですよ。 Math::Vector3D EnemyPos[] = { Math::Vector3D( 0,10, 0), Math::Vector3D( 10,10, 10), Math::Vector3D( 20,10, 20), Math::Vector3D( 30,10, 30), Math::Vector3D( 40,10, 40), Math::Vector3D( 50,10, 50)}; const Sint32 EnemyNum = (sizeof EnemyPos /sizeof EnemyPos[0]); // インスタンスはメインが保持するだけでよい。 // 本当はnewで動的にインスタンス生成すること。EnemyNumがマップごとに可変するのはゲームでは当たり前なので。 // そもそもENEMY_DATAクラスはEnemyNumを知る必要はありませんよ。 // メインが知っていれば済むことです。 ENEMY_DATA Enemy[EnemyNum]; // 初期化 //Initalizeでは無くコンストラクタでやるべきだと思いますけど取り合えずと言うことで。 for(int i=0;i< EnemyNum;i++) { Enemy.Initalize(EnemyPos[i]); } } /*ここからEnemy.h*/ #include "../../../../Selene.h" using namespace Selene; class ENEMY_DATA { public: enum eState { STATE_STANDBY, STATE_ACTIVE, } State; private: Scene::IModelActor *pActor; Math::Vector3D vPosition; Math::Vector3D vStartPos; public: void Initalize(); void Create( Scene::ISceneManager *pScene, Renderer::Object::IModel *pModel); void Update(Sint32 Time); void Rendering( void ); }; /*ここからEnemy.cpp*/ #include"Enemy.h" void ENEMY_DATA::Initalize(Math::Vector3D EnemyPos) { State = STATE_STANDBY; pActor = NULL; vStartPos = EnemyPos; } void ENEMY_DATA::Create( Scene::ISceneManager *pScene, Renderer::Object::IModel *pModel) { if( State == STATE_STANDBY ) { State = STATE_ACTIVE; pActor = pScene->CreateActor( pModel ); } } void ENEMY_DATA::Update(Sint32 Time) { switch ( State ) { case STATE_STANDBY: break; case STATE_ACTIVE: vPosition.Set(vStartPos.x + Math::Sin( Time * 256 ) * 20.0f,vStartPos.y,vStartPos.z ); pActor->TransformReset(); pActor->Translation(vPosition); pActor->TransformUpdate(); break; } } void ENEMY_DATA::Rendering( void ) { switch ( State ) { case STATE_STANDBY: break; case STATE_ACTIVE: pActor->TransformReset(); pActor->Translation( vPosition ); pActor->Scaling(0.5f,0.5f,0.5f ); pActor->TransformUpdate(); pActor->RenderingRequest(); break; } }
- zwi
- ベストアンサー率56% (730/1282)
mainのヘッダを作れば解決する気もするが。 ただし、実体は1つにしてextern宣言する必要あり。 int aaa[] = {1,2,3};これもextern const int Num = (sizeof aaa /sizeof aaa[0]);これもextern static DATA data[Num]; これがヘッダにあるとまずい。つうかDATAってクラス名? と書いといてなんだが、これってクラスの設計そのものが変な気がする。 クラスの定義部分だけでも見たいのでお願いします。
補足
/*ここからEnemy.h*/ #include "../../../../Selene.h" using namespace Selene; class ENEMY_DATA { public: enum eState { STATE_STANDBY, STATE_ACTIVE, }State; Scene::IModelActor *pActor; Math::Vector3D vPosition; Math::Vector3D vStartPos; void Initalize(); void Create( Scene::ISceneManager *pScene, Renderer::Object::IModel *pModel); void Update(Sint32 Time); void Rendering( void ); }; /*ここからEnemy.cpp*/ #include"Enemy.h" Math::Vector3D EnemyPos[] = { Math::Vector3D( 0,10, 0), Math::Vector3D( 10,10, 10), Math::Vector3D( 20,10, 20), Math::Vector3D( 30,10, 30), Math::Vector3D( 40,10, 40), Math::Vector3D( 50,10, 50)}; const Sint32 EnemyNum = (sizeof EnemyPos /sizeof EnemyPos[0]); ENEMY_DATA Enemy[EnemyNum]; void ENEMY_DATA::Initalize() { for(int i=0;i< EnemyNum;i++) { ENEMY_DATA &EnemyObj = Enemy[i]; EnemyObj.State = STATE_STANDBY; EnemyObj.pActor = NULL; EnemyObj.vStartPos = EnemyPos[i]; } } void ENEMY_DATA::Create( Scene::ISceneManager *pScene, Renderer::Object::IModel *pModel) { for(int i=0;i< EnemyNum;i++) { ENEMY_DATA &EnemyObj = Enemy[i]; if ( EnemyObj.State == STATE_STANDBY ) { EnemyObj.State = STATE_ACTIVE; EnemyObj.pActor = pScene->CreateActor( pModel); } } } void ENEMY_DATA::Update(Sint32 Time) { for(int i=0;i< EnemyNum;i++) { ENEMY_DATA &EnemyObj = Enemy[i]; switch ( State ) { case STATE_STANDBY: break; case STATE_ACTIVE: EnemyObj.vPosition.Set(vStartPos.x + Math::Sin( Time * 256 ) * 20.0f,vStartPos.y,vStartPos.z ); EnemyObj.pActor->TransformReset(); EnemyObj.pActor->Translation(vPosition); EnemyObj.pActor->TransformUpdate(); break; } } } void ENEMY_DATA::Rendering( void ) { for(int i=0;i< EnemyNum;i++) { ENEMY_DATA &EnemyObj = Enemy[i]; switch ( State ) { case STATE_STANDBY: break; case STATE_ACTIVE: EnemyObj.pActor->TransformReset(); EnemyObj.pActor->Translation( vPosition ); EnemyObj.pActor->Scaling(0.5f,0.5f,0.5f ); EnemyObj.pActor->TransformUpdate(); EnemyObj.pActor->RenderingRequest(); break; } } } 質問内容に書いたものを正確に示すと以下のようになります。 Math::Vector3D EnemyPos[] = { Math::Vector3D( 0,10, 0), Math::Vector3D( 10,10, 10), Math::Vector3D( 20,10, 20), Math::Vector3D( 30,10, 30), Math::Vector3D( 40,10, 40), Math::Vector3D( 50,10, 50)}; const Sint32 EnemyNum = (sizeof EnemyPos /sizeof EnemyPos[0]); static ENEMY_DATA Enemy[EnemyNum]; Enmeyの位置を書き足す分だけ生産しようという仕組みです。質問内容で言うところのクラス(1)です。
- BLK314
- ベストアンサー率55% (84/152)
>とりあえずクラス(1)のソース内に書いたんですが、クラス(2)のヘッダとソース内>でもNumを使うため、このままではNumが定義されていないという >エラーになります。 Numの情報が共有されるのでNumの定義をクラス(1)のヘッダに記述し、 クラス(2)のヘッダで"includeする必要があります。 しかし、この場合 Numがaaaを使って定義されています。 そのaaaは int aaa[] = {1,2,3}; と定義されています。 クラス宣言ではこの記述はできません。 恐らく、この様に記述すれば int aaa[] = {1,2,3,4} とするだけで 自動的にNumが4となり、 その情報をクラス(2)でも使いたいのだと思います。 この様な記述はできません。 ソースを分割するのは良いことですが、 >ソースの量が増えてきたので分けることにしました。 安易に分けようとするのも良くないことです。 分割する際には、 それぞれのクラスが果たすべき役割を明確にして、 分割することが必要です。 また、それぞれの情報をできるだけブラックボックス化できるよう 考えるべきです たとえば、 クラス(1)は1レコードを表す クラス(2)はクラス(1)の集合を表す という風に分けます クラス(1)はそれがどのように使われるか一切関知すべきではありません。 クラス(2)はクラス(1)がどのようなフィールドからなるか知らなくても動作するべきです。(現実には厳しい場合もあります。それでも、知らなければならない情報が少ない方が好ましいです。) もう一度、クラス分けを考え直すことをお勧めします、
お礼
多くなったらとりあえず分ければ良いという考えを持っていましたが、後先考えずに分けてはいけないのですね。 今からもう一度見直してきます。ありがとうございました。
- asuncion
- ベストアンサー率33% (2127/6289)
>・クラスの定義のヘッダ(1),(2) >・クラスのメンバ関数の定義用のソース(1)、(2) このあたりを見せていただいてもいいですか?
補足
/*ここからSystem.h*/ #include "../../../../Selene.h" using namespace Selene; class SYSTEM { public: Bool LockOnStart; Float Distance[EnemyNum]; Float MostShortDistance; Math::Vector3D LockOnPos; Bool LockOn; Sint32 TargetID,Min; SYSTEM() { LockOnStart = false; LockOn = false; } enum LOCK_ON_STATE { STANDBY, START, ACTIVE, }LockOnState; void LockOn_Initalize(); void LockOnManage(Math::Vector3D vPlayerPos,Renderer::IRender *pRender); void DebugPrint(Renderer::IRender *pRender); void MeasureDistance(Math::Vector3D vPlayerPos,Renderer::IRender *pRender); void MeasureMostShortDistance(Renderer::IRender *pRender); void SetLockOnEnemy(); void PutLockOn(); }System; /*ここからSystem.cpp*/ #include"System.h" void SYSTEM::LockOn_Initalize() { LockOnState = STANDBY; } void SYSTEM::LockOnManage(Math::Vector3D vPlayerPos,Renderer::IRender *pRender) { if(LockOnState == STANDBY) { MeasureDistance(vPlayerPos,pRender); MeasureMostShortDistance(pRender); if(LockOn)LockOnState = START; } if(LockOnState == START)SetLockOnEnemy(); if(LockOnState == ACTIVE) { PutLockOn(); MeasureDistance(vPlayerPos,pRender); } } void SYSTEM::DebugPrint(Renderer::IRender *pRender) { } void SYSTEM::MeasureDistance(Math::Vector3D vPlayerPos,Renderer::IRender *pRender) { for(int i=0;i<EnemyNum;i++) { Float Ax,Ay,Az,Bx,By,Bz; Ax = vPlayerPos.x; Ay = vPlayerPos.y; Az = vPlayerPos.z; Bx = Enemy[i].vPosition.x; By = Enemy[i].vPosition.y; Bz = Enemy[i].vPosition.z; Distance[i] = fabs(sqrt((Ax-Bx)*(Ax-Bx) + (Ay-By)*(Ay-By) + (Az-Bz)*(Az-Bz))); } } void SYSTEM::MeasureMostShortDistance(Renderer::IRender *pRender) { static int j = 0; for(int i=0;i< EnemyNum;i++) { if(MostShortDistance >= Distance[i] ) { MostShortDistance = Distance[i]; Min = i; } else if(MostShortDistance == Distance[0]) { MostShortDistance = Distance[0]; Min = 0; } } pRender->DebugPrint( Math::Point2DI(85,460), CColor(255,255,255), "jは:%d",j); } void SYSTEM::SetLockOnEnemy() { TargetID = Min; LockOnState = ACTIVE; } void SYSTEM::PutLockOn() { if(Distance[TargetID] > 50.0f || LockOn == false) { LockOnState = STANDBY; LockOn = false; }; LockOnPos = Enemy[TargetID].vPosition; } これが質問内容で言うところのクラス(2)です。 生産したEnemyの位置を把握し、Enemyの各々の位置と自身との距離など測定しようとするものです。
お礼
何度もありがとうございます。 いろいろ書き直して何とかEnemyNumをメインのソースのみに収めることができました。 おかげさまで素晴らしい学習ができました。これからに生かしていこうと思います。