C++を用いたクラス型2次元配列の一括処理について

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

C++を用いたクラス型2次元配列の一括処理について

#1

投稿記事 by 田中那珂 » 12年前

こんばんは、数年ぶりに利用させて頂きます。
プログラミング暦はCとJavaを趣味で数年齧った程度で、CとDXライブラリで2DSTGを作成したこともあります。

さて、現在、C++とDXライブラリを利用したゲーム作成を行っておりまして、その準備として
必要な機能のテストを行っているところなのですが、表題のように
「何名所属するかわからない団体が複数あり、団体ごとに所属者数を変えたり何名所属していても特に気にせず利用でき、
 その上で全ての団体に対し、各団体の全所属者に対してまとめて処理を行いたい」
と考えております。
団体数は2から4のみ存在するものとし、開発は自分のみで行う予定です。

試行錯誤の結果、下記コードの形で上記条件を達成できたと考えております。
しかし、C++にはあまり慣れていないもので、

・vectorなどの使い方が今回の条件を満たすのにふさわしいのか
・団体数も可変長にできるのでは
・ソースの書き方自体にツッコミ所はないか
 (名称の付け方、カプセル化、値の渡し方、new deleteのタイミングなど)
・もっといいやり方があるのでは

といった点などについて、皆様のご意見を頂けないでしょうか。
当初はvector<vector<CMember> > CGroupといった形で処理しようとしたのですが、
どうしてもうまくいかず、下記の形になりました。
可能であれば、団体を更に統括する大団体を作成し、それに対して一括で処理ができれば
なお理想的ではあります。

実行環境はWindows7 32bit VC++2008EE になります。
以上、宜しくお願い致します。


コード:

#include <iostream>
#include <vector>

using namespace std;

class CMember{	//所属者クラス
private:
	int x,y;

public:
	CMember(){ x=y=0; }

	void Init(int i){	//初期化は適当
		x=rand();
		y=2*i;
	}

	void Exec(vector<CMember>& A){	//処理内容も仮のもの
		static int j = 1;
		cout << "-------------" << endl;
		cout << "count:" << j << endl;
		cout << "-------------" << endl;
		for(unsigned int i=0; i < A.size(); i++){
			cout << "No." << i << endl;
			cout << "x=" << A[i].x << ",y=" << A[i].y << endl;
			cout << "x*y = " << A[i].x * A[i].y << endl;
			cout << "-------------" << endl;
		}
		j++;
		cout << endl;
	}
};


class CGroup{	//団体クラス
private:
	vector<CMember> Members;	//所属者が何名でも対応できるようにvector

public:
	void SetMembers(vector<CMember>& A){ Members=A; }
	vector<CMember> GetMembers(){ return Members; }
};


int main(){
	unsigned int num = 4;			//団体数
	unsigned int num2 = 6;			//所属数

	CMember* A;						//所属者
	A = new CMember[num2];

	CGroup* X;						//団体
	X = new CGroup[num];

	vector<CMember>* Buf;			//バッファ		
	Buf = new vector<CMember>[num];


	for(unsigned int i=0; i<num; i++){		//実際は、初期化・団体への所属数は各々異なる
		for(unsigned int j=0; j<num2; j++){	//ここでは面倒なのでループさせている
			A[j].Init(j*(i+1));	
			Buf[i].push_back(A[j]);
		}
		X[i].SetMembers(Buf[i]);
	}
	delete[] Buf;


	for(unsigned int i=0; i<num; i++){						//全団体に対して行う
		X[i].GetMembers().at(0).Exec( X[i].GetMembers() );	//各団体の所属者全てを一括で処理
	}


	delete[] X;

	return 0;
}

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: C++を用いたクラス型2次元配列の一括処理について

#2

投稿記事 by みけCAT » 12年前

各団体の所属者に対してまとめて行いたい処理と、所属者の数の最大はだいたいどのくらいですか?
100人程度か、4000人程度か、100000人程度かなどによって処理方法が変わるかもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: C++を用いたクラス型2次元配列の一括処理について

#3

投稿記事 by h2so5 » 12年前

こんな方法はどうでしょうか。団体の階層はいくらでも深くできます。
本当はスマートポインタを使ったほうがいいですが、VS2008で使えるのかどうか分からないのでCGroupにメモリの管理を任せています。

コード:

#include <iostream>
#include <vector>
#include <string>

using namespace std;
class CMember;


// インターフェイス
class IVisitor
{
public:
	virtual void Visit(const CMember& member) const = 0;
};

class IAcceptor
{
public:
	virtual void Accept(const IVisitor& command) = 0;
};


// メンバー
class CMember : public IAcceptor
{
public:
	CMember(const string& name) : name_(name) {}
	string Name() const { return name_; }

	/* virtual */ void Accept(const IVisitor& command)
	{
		command.Visit(*this);
	}

private:
	string name_;
};


// グループ
class CGroup : public IAcceptor
{
public:
	void Push(IAcceptor* acceptor)
	{
		acceptors_.push_back(acceptor);
	}

	/* virtual */ void Accept(const IVisitor& command)
	{
		typedef vector<IAcceptor*>::iterator AccIterator;
		for (AccIterator it = acceptors_.begin(); it != acceptors_.end(); ++it) {
			(*it)->Accept(command);
		}
	}

	~CGroup()
	{
		typedef vector<IAcceptor*>::iterator AccIterator;
		for (AccIterator it = acceptors_.begin(); it != acceptors_.end(); ++it) {
			delete *it;
		}
	}

private:
	vector<IAcceptor*> acceptors_;
};


// コマンド
class WhatsYourName : public IVisitor
{
public:
	/* virtual */ void Visit(const CMember& member) const
	{
		cout << "my name is " << member.Name() << endl;
	}
};


int main()
{
	// 東京
	CGroup* shibuya = new CGroup();
	shibuya->Push(new CMember("foo"));
	shibuya->Push(new CMember("bar"));

	CGroup* shinjuku = new CGroup();
	shinjuku->Push(new CMember("baz"));

	CGroup* tokyo = new CGroup();
	tokyo->Push(shibuya);
	tokyo->Push(shinjuku);

	// 愛知
	CGroup* nagoya = new CGroup();
	nagoya->Push(new CMember("hoge"));

	CGroup* toyota = new CGroup();
	toyota->Push(new CMember("fuga"));

	CGroup* aichi = new CGroup();
	aichi->Push(nagoya);
	aichi->Push(toyota);

	CGroup japan;
	japan.Push(tokyo);
	japan.Push(aichi);

	WhatsYourName command;

	cout << "全国: " << endl;
	japan.Accept(command);
	
	cout << "東京: " << endl;
	tokyo->Accept(command);
}

田中那珂

Re: C++を用いたクラス型2次元配列の一括処理について

#4

投稿記事 by 田中那珂 » 12年前

皆様

ご回答頂きありがとうございます。
みけCAT さんが書きました:各団体の所属者に対してまとめて行いたい処理と、所属者の数の最大はだいたいどのくらいですか?
100人程度か、4000人程度か、100000人程度かなどによって処理方法が変わるかもしれません。
各団体の所属者数は最低1人、最大でも60人程度を想定しています。
団体は最低1個、最大で4個までで、それらをまとめる大団体が最低2個、最大4個です。
よって、所属者の総数は最大で1,000名程度ということになります。
また、各団体の所属者に対して以下のような処理を行いたいと考えております。

・団体のリーダー(各団体の一番目に登録された所属者)の後をカルガモのように追随する
 もしくは、特定のフォーメーションを構築する
・条件を満たした場合、リーダーと同じアクションを同時に起こす
 任意で個別のアクションを起こさせることも出来ればなお良い
・特定条件で脱落者が発生し、それがリーダーの場合は団体が消滅、リーダー以外かつ最後尾ではない所属者が
 脱落した場合は、その所属者の後ろにいる者が前に詰める
 所属者が途中で増えることはない

団体のうちの一つをプレイヤーが直接制御し、同じ大団体に属する団体はプレイヤーが発する簡単な
命令に従い行動します。
プレイヤーが属さない大団体・団体は自動で行動します。
そのため、各団体のリーダーに対する処理を個別に行うこと、それ以外の所属者は、
自分の一つ前の所属者の情報を参照して処理するように出来なければならないものと思われます。
h2so5 さんが書きました:こんな方法はどうでしょうか。団体の階層はいくらでも深くできます。
本当はスマートポインタを使ったほうがいいですが、VS2008で使えるのかどうか分からないのでCGroupにメモリの管理を任せています。
ソースをご提示いただきありがとうございます。
これを確認したところ、かなり理想に近い挙動を確認できました。
ただ、上記条件を満たさなければならないため、これをどう活用するか悩んでおります。

・大団体・団体・所属者の数はゲーム開始前にセットされたcsvファイルから読み取り、必要数だけ生成する
 (csvから読み出す処理は出来ています)
 現状だと、自動的に必要な数だけ生成することができない?
・団体のリーダー(その団体に初めて登録された所属者)の識別方法
 団体のイテレータがbegin()の際に処理するのではないかとは思いますが、その後に続く所属者が
 どのようにして、自分の手前にいる所属者の情報を参照し、受け取るのか

現状では、下記コードのように、団体そのものを引数とする関数に、各団体を直接投げ込むことにより
リーダーとそれに続く所属者の処理を行っております。
現時点ではプレイヤーが直接制御する団体と、背景しか作成しておりませんが、他団体も同じクラスから
インスタンスを生成したいと考えております。
その際には、プレイヤーとそれ以外を識別し、処理を変えるようにする予定です。

コード:

#include "DxLib.h"
#include <math.h>
#include <stdlib.h>

#define PI 3.14159265359

#define CNUM 6

#define BGVMAX 10
#define BGHMAX 10
#define BGWIDTH 640
#define BGLENGTH 480

float extR;
float viewX;
float viewY;

int circleNum;

class CP{
public:
	float x,y;
	CP(){
		x=y=0;
	}
};

class CCircle{
public:
	float x,y,r,angle,space,spd,diag,width,length,rx,ry,sx,sy;
	int color,count,handle[12],frmn,cnum;
	float rectAngle[4];
	float X[6],Y[6],R;
	CP p[4];
	CP q[4];

	void Init(CCircle A[CNUM], int circleNum, int handle){
		A[0].cnum = circleNum;
		for(int i=0;i<A[0].cnum;i++){
			A[i].color = GetColor(255,30*i,20*i);
			A[i].spd = 3;
			A[i].r = 16;
			A[i].space = 80;
			A[i].angle = 0*PI/180;
			A[i].x = 320 - i*space*cos(A[i].angle);
			A[i].y = 240 - i*space*sin(A[i].angle);
			A[i].width = 20 - i;
			A[i].length = 50 - i*2;
			A[i].diag = atan2( A[i].length, A[i].width) ;
			A[i].handle[0] = handle;
			A[i].count = 0;
			A[i].frmn = 0;
		}
	}

	void calcMove(CCircle A[CNUM]){
		int NUMW = BGWIDTH  * BGHMAX;
		int NUML = BGLENGTH * BGVMAX;

		if( A[0].x > NUMW - A[0].r )A[0].x = NUMW - A[0].r;
		if( A[0].y > NUML - A[0].r )A[0].y = NUML - A[0].r;
		if( A[0].x < A[0].r )		A[0].x = A[0].r;
		if( A[0].y < A[0].r )		A[0].y = A[0].r;

		viewX=A[0].x-320;
		viewY=A[0].y-240;

		A[0].rx=A[0].x-viewX;
		A[0].ry=A[0].y-viewY;

		for(int i=0;i<A[0].cnum;i++){
			A[i].rectAngle[0] = PI/2 + A[i].angle;
			A[i].rectAngle[1] = 3*PI/2 - 2*A[i].diag + A[i].angle;
			A[i].rectAngle[2] = 3*PI/2 + A[i].angle;
			A[i].rectAngle[3] = 5*PI/2 - 2*A[i].diag + A[i].angle;
			A[i].calcRect();
			if( i>0 ){
				A[i].spd = A[i-1].spd;
				A[i].sx = A[i-1].x - A[i].x;
				A[i].sy = A[i-1].y - A[i].y;
				A[i].rx = A[i-1].rx - A[i].sx * extR;
				A[i].ry = A[i-1].ry - A[i].sy * extR;
			}
			A[i].count++;
		}

		A[0].x += A[0].spd * cos(A[0].angle);
		A[0].y += A[0].spd * sin(A[0].angle);
		
		if( CheckHitKey( KEY_INPUT_RIGHT ) == 1 )	A[0].angle += 1*PI/180;
		if( CheckHitKey( KEY_INPUT_LEFT ) == 1 )	A[0].angle -= 1*PI/180;
		if( CheckHitKey( KEY_INPUT_UP ) == 1 )		A[0].spd += 0.1;
		if( CheckHitKey( KEY_INPUT_DOWN ) == 1 )	A[0].spd -= 0.1;
		if( CheckHitKey( KEY_INPUT_NUMPAD0 ) == 1 )	A[0].spd = 0;
		if( CheckHitKey( KEY_INPUT_NUMPAD1 ) == 1 )	extR = 1;
		if( A[0].spd <= 0 )							A[0].spd = 0;

		if( CheckHitKey( KEY_INPUT_1 ) == 1 )		A[0].frmn = 0;
		if( CheckHitKey( KEY_INPUT_2 ) == 1 )		A[0].frmn = 1;

		A[0].calcFormation(A,A[0].frmn);
	}

	void calcRect(){
		for(int i=0;i<4;i++){
			p[i].x = x + width/2 * cos(rectAngle[i]) - length/2 * sin(rectAngle[i]);
			p[i].y = y + width/2 * sin(rectAngle[i]) + length/2 * cos(rectAngle[i]);
			q[i].x = rx + (p[i].x-x) * extR;
			q[i].y = ry + (p[i].y-y) * extR;
		}
	}

//formationNumberは仮のもの、現在はカルガモの動きのみ
	void calcFormation(CCircle A[6], int formationNumber){
		for(int i=1;i<6;i++){
			X[i] = A[i-1].x - A[i].x;
			Y[i] = A[i-1].y - A[i].y;
			if( A[i].space * A[i].space < X[i]*X[i] + Y[i]*Y[i] ){
				A[i].angle = atan2(Y[i],X[i]);
				A[i].x += A[i].spd * cos(A[i].angle);
				A[i].y += A[i].spd * sin(A[i].angle);
			}
		}
	}

	void Draw(CCircle A[6]){
		for(int i=0;i<6;i++){
			DrawRotaGraphF( A[i].rx, A[i].ry, extR, A[i].angle+PI/2, A[i].handle[0], TRUE, FALSE);
			DrawCircle( A[i].rx, A[i].ry, A[i].r/4 * extR, A[i].color, TRUE);
			A[i].DrawRect();
		}
	}

	void DrawRect(){
		for(int i=0;i<4;i++){
			DrawLine( q[i%4].x, q[i%4].y, q[(i+1)%4].x, q[(i+1)%4].y, color);
		}
	}
};

class CBackGround{
public:
	float x,y;
	float width,length;
	float sx,sy;
	float rx,ry;
	int handle;
	CP p[4];
	CP q[4];

	void Init(CBackGround bg[BGVMAX][BGHMAX], int bghandle){
		for(int i=0;i<BGVMAX;i++){
			for(int j=0;j<BGHMAX;j++){
				bg[i][j].width = BGWIDTH;
				bg[i][j].length = BGLENGTH;
				bg[i][j].x = BGWIDTH/2 + BGWIDTH*j;
				bg[i][j].y = BGLENGTH/2 + BGLENGTH*i;
				bg[i][j].handle = bghandle;
				bg[i][j].p[0].x = bg[i][j].x - BGWIDTH/2;
				bg[i][j].p[1].x = bg[i][j].x + BGWIDTH/2;
				bg[i][j].p[2].x = bg[i][j].x + BGWIDTH/2;
				bg[i][j].p[3].x = bg[i][j].x - BGWIDTH/2;
				bg[i][j].p[0].y = bg[i][j].y + BGLENGTH/2;
				bg[i][j].p[1].y = bg[i][j].y + BGLENGTH/2;
				bg[i][j].p[2].y = bg[i][j].y - BGLENGTH/2;
				bg[i][j].p[3].y = bg[i][j].y - BGLENGTH/2;
			}
		}
	}

	void Calc(CBackGround bg[BGVMAX][BGHMAX], CCircle A[6]){
		for(int i=0;i<BGVMAX;i++){
			for(int j=0;j<BGHMAX;j++){

				bg[i][j].sx = A[0].x - bg[i][j].x;
				bg[i][j].sy = A[0].y - bg[i][j].y;

				bg[i][j].rx = A[0].rx - bg[i][j].sx * extR;
				bg[i][j].ry = A[0].ry - bg[i][j].sy * extR;

				bg[i][j].width = BGWIDTH * extR;
				bg[i][j].length = BGLENGTH * extR;

				bg[i][j].q[0].x = bg[i][j].rx - bg[i][j].width/2;
				bg[i][j].q[0].y = bg[i][j].ry - bg[i][j].length/2;
				bg[i][j].q[1].x = bg[i][j].rx + bg[i][j].width/2;
				bg[i][j].q[1].y = bg[i][j].ry - bg[i][j].length/2;
				bg[i][j].q[2].x = bg[i][j].rx + bg[i][j].width/2;
				bg[i][j].q[2].y = bg[i][j].ry + bg[i][j].length/2;
				bg[i][j].q[3].x = bg[i][j].rx - bg[i][j].width/2;
				bg[i][j].q[3].y = bg[i][j].ry + bg[i][j].length/2;
			}
		}
	}

	void Draw(CBackGround bg[BGVMAX][BGHMAX]){
		for(int i=0;i<BGVMAX;i++){
			for(int j=0;j<BGHMAX;j++){
				DrawModiGraphF(
					bg[i][j].q[0].x, bg[i][j].q[0].y,
					bg[i][j].q[1].x, bg[i][j].q[1].y,
					bg[i][j].q[2].x, bg[i][j].q[2].y,
					bg[i][j].q[3].x, bg[i][j].q[3].y,
					bg[i][j].handle, TRUE
				);
			}
		}
	}

};


int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定

	extR=1;
	circleNum=6;

	int bghandle=LoadGraph("dat/bg01.png");//640px*480pxの画像
	CBackGround bg[BGVMAX][BGHMAX];
	bg[0][0].Init(bg, bghandle);

	int handle[12];
	LoadDivGraph("dat/0.png",12,4,3,73,73,handle,TRUE);//仮の画像を利用中
	CCircle *A;
	A = new CCircle[circleNum];
	A[0].Init(A, circleNum, handle[0]);


	while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 ){

		extR-=GetMouseWheelRotVolF()*0.01;
		if(extR<=0.2)extR=0.2;

		A[0].calcMove(A);
		bg[0][0].Calc(bg, A);

		bg[0][0].Draw(bg);
		A[0].Draw(A);

		if(CheckHitKey(KEY_INPUT_ESCAPE) == 1)break;
	}
    
    DxLib_End(); // DXライブラリ終了処理
    return 0;
}
作成中のため色々と見苦しい点が多いとは存じますが、なにかご助言を頂ければ幸いです。
以上、よろしくお願い致します。
(余談ですが、3Dのカメラが使えないので、スクロール処理と拡大縮小処理に苦労しました)

閉鎖

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