ページ 11

ゲーム作りについて part.1

Posted: 2012年4月19日(木) 16:03
by 電気屋
こんにちは電気屋と申します。
私は、C++をさわり今年で2年になるのですが、本格的なゲーム開発を一度もしたことが無く、ゲームをどのように作るのか全くわからない状態です。しかし今回、そろそろゲーム開発を真剣に考えてやってみようと、このサイトのサンプルやテキストを読んで自分なりにゲーム開発をしてみたのですが、まだゲームとは言える状態では無く、今後どのような機能が有れば、もっとゲームらしくなるのか、現在のコードをどのようにいじれば、もっとゲーム開発に有っているのか教えてほしく、書き込みしました。作りかけのソースコードしかないですが、一様動くので書き込みよろしくお願いします。画像の宣言が有るので32*32で「KIRAI.bmp」と適当に作って下さい。わかりにくい書き込みですが、優しくお願いします

コード:

 
#include "DxLib.h"
#include "math.h"
///////////////////////////////////////////////////////////////
//宣言
///////////////////////////////////////////////////////////////
#define Window_H 480 //MAP(高さ・Y)
#define Window_W 480 //MAP(広さ・X)
#define BOX 32       //BOXサイズ
#define CH_SPEED 1.0 //移動スピード(PLAY1)
#define SHOTSPEED 4  //移動スピード(  弾 )
#define SHOTMAX 50   //最大弾数
#define SHOT_RANGE 16//弾サイズ
#define SHOT_LONG 10 //弾間隔
#define TAMEMAX 5    //最大保持弾数
#define PI 3.1415926535897932384626433832795//π
///////////////////////////////////////////////////////////////
//構造体
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
//PLAYER1(X,Y方向:muki:WALKING_FLAG:)
///////////////////////////////////////////////////////////////
typedef struct{
	double x;
	double y;
	int muki;
	int walking_flag;
	int range;
}BODY_ch_t1;
BODY_ch_t1 ch;
///////////////////////////////////////////////////////////////
//PLAYER1・弾(X,Y方向:muki:FLAG:)
///////////////////////////////////////////////////////////////
typedef struct{
        double x;
		double y;
		int muki;
        int flag;
		int counter;
		int range;
} SHOT_t;
SHOT_t Shot[SHOTMAX];

///////////////////////////////////////////////////////////////
//PLAYER1・機雷尾(X,Y方向:FLAG:)
///////////////////////////////////////////////////////////////
typedef struct{
        double x;
		double y;
        int flag;
		int counter;
		int range;
} tame_t;
tame_t tame;


////////////////////////////////////////////////////
//グローバル変数
////////////////////////////////////////////////////
char Key[256];//キー入力
int counter; //カウント
int image;   //ハンドルを受け取るためのint型変数を宣言

int hantei[15][15]={
	{0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,1,0,1},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,1,0,0,0,0,0,0,0,0,0,0,0,1},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,1,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,1,0,0,0,0,0,1},
};//MAP

////////////////////////////////////////////////////
//プロトタイプ宣言
////////////////////////////////////////////////////
void PlayerControl();//PLAY
void WindowMode();   //ウインドウモード切り替え
void Init();     //初期化
void Map();          //MAPデータ

////////////////////////////////////////////////////
//関数
////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
//MAP・CANNOT
///////////////////////////////////////////////////////////////
int can_or_cannot(int x,int y){
	if(hantei[y/BOX][x/BOX]==1)return 1;
	return 0;
}

///////////////////////////////////////////////////////////////
//PLAYER1・表示
///////////////////////////////////////////////////////////////
void PlayerDraw(int x, int y){
	DrawBox (  ch.x , ch.y , ch.x+BOX , ch.y+BOX , GetColor(0,255,255) , TRUE );
}
///////////////////////////////////////////////////////////////
//PLAYER1・行動
///////////////////////////////////////////////////////////////
void PlayerControl(){
	int i;
	if((int)ch.x%32==0 && (int)ch.y%32==0){
		ch.walking_flag=1;
		if     ( Key[ KEY_INPUT_UP   ]  == 1 )ch.muki=0;
		else if( Key[ KEY_INPUT_LEFT ]  == 1 )ch.muki=1;
		else if( Key[ KEY_INPUT_DOWN ]  == 1 )ch.muki=2;
		else if( Key[ KEY_INPUT_RIGHT]  == 1 )ch.muki=3;
		else                          ch.walking_flag=0;
		for(i=0;i<=SHOTMAX;i++)if(Shot[i].flag==0)Shot[i].muki=3-ch.muki;
	}
	if(ch.walking_flag==1){
		if(ch.muki==0)(ch.y<   0   )?ch.y=    0     :ch.y-=CH_SPEED;
		if(ch.muki==1)(ch.x<   0   )?ch.x=    0     :ch.x-=CH_SPEED;
		if(ch.muki==2)(ch.y>=Window_H-BOX)?ch.y=(Window_H-BOX):ch.y+=CH_SPEED;			
		if(ch.muki==3)(ch.x>=Window_W-BOX)?ch.x=(Window_W-BOX):ch.x+=CH_SPEED;
		tame.flag=0;
	}
}
///////////////////////////////////////////////////
//ウインドウモード切り替え
///////////////////////////////////////////////////
void WindowMode(){
	if     (Key[KEY_INPUT_F1]==1)ChangeWindowMode(TRUE);
	else if(Key[KEY_INPUT_F2]==1)ChangeWindowMode(FALSE);
}
///////////////////////////////////////////////////
//初期化
///////////////////////////////////////////////////
void Init(){		
	ch.x=0;
	ch.y=0;
	ch.muki=0; 
	counter=0;
	tame.counter=0;
	tame.flag=0;
	for(int i=0;i<SHOTMAX;i++){
		Shot[i].flag=0;
	}
    image = LoadGraph( "KIRAI.bmp" ) ;       //ハンドルを代入
      

}
///////////////////////////////////////////////////
//MAP・描画
///////////////////////////////////////////////////
void Map(){
	int i,j;
	DrawBox (  Window_W , 0 , 640 , Window_H , GetColor(255,255,255) , TRUE ) ;
	for(i=0;i<15;i++){
		for(j=0;j<15;j++)
			if(hantei[j][i]==1)DrawGraph( i*32 , j*32  , image , TRUE );
	}

	for(i=0;i<=480;i+=BOX){
		DrawLine(i,0,i,Window_H,GetColor(255,255,255));
		DrawLine(0,i,Window_W,i,GetColor(255,255,255));
	}
	static int FpsTime[2]={0,},FpsTime_i=0;
	static double Fps=0.0;

	if(FpsTime_i== 0)FpsTime[0]=GetNowCount();              //1周目の時間取得
	if(FpsTime_i==49){
		FpsTime[1]=GetNowCount();                           //50周目の時間取得
		Fps = 1000.0f / ((FpsTime[1] - FpsTime[0]) / 50.0f);//測定した値からfpsを計算
		FpsTime_i=0;
	}
	else FpsTime_i++;                                       //現在何周目かカウント
	if(Fps != 0)DrawFormatString(565,460,GetColor(0,255,255),"FPS %.1f",Fps);
	DrawFormatString(565,420,GetColor(0,255,255),"%d",tame.counter);
}
////////////////////////////////////////////////////
//弾・行動
////////////////////////////////////////////////////
void ShotCalc(){
        int j;
        if(Key[KEY_INPUT_Z]==1&&counter%SHOT_LONG==0){
                for(j=0;j<SHOTMAX;j++){
                        if(Shot[j].flag==0){
                                Shot[j].flag=1;
                                Shot[j].x=ch.x+(BOX/4);
                                Shot[j].y=ch.y+(BOX/4);
								Shot[j].muki=3-ch.muki;//上
								break;
                        }
                }
        }
        for(j=0;j<SHOTMAX;j++){
                if(Shot[j].flag==1){
			        Shot[j].x+= SHOTSPEED * cos(90*Shot[j].muki*PI/180); 
                    Shot[j].y+= SHOTSPEED * sin(90*Shot[j].muki*PI/180); 
					if( Shot[j].x > 480 || Shot[j].x < 0-BOX || Shot[j].y > 480 || Shot[j].y < 0-BOX )Shot[j].flag=0;
                }
		}
}
//////////////////////////////////////////
//弾・描画
//////////////////////////////////////////
void ShotDisp(){
        int j;
        for(j=0;j<50;j++){
			Shot[j].range=SHOT_RANGE;
                if(Shot[j].flag==1)DrawBox (  Shot[j].x , Shot[j].y , Shot[j].x+Shot[j].range , Shot[j].y+Shot[j].range , GetColor(0,255,255) , TRUE );
        }
}
////////////////////////////////////////////////////////////////////////////////////////////////
//待ち時間
////////////////////////////////////////////////////////////////////////////////////////////////
void wait_func(){
    static int t=0;
	int term = GetNowCount()-t;
    if(16-term>0)Sleep(16-term);
    t=GetNowCount();
}
/////////////////////////////////////////////////////
//機雷
/////////////////////////////////////////////////////
void Kirai(){
		if( (int)can_or_cannot((int)ch.x,(int)ch.y)==0 && Key[KEY_INPUT_A] && (int)ch.x%32==0 && (int)ch.y%32==0 && tame.counter<TAMEMAX){
			hantei[(int)ch.y/BOX][(int)ch.x/BOX]=1;
			tame.counter++;
			tame.flag=1;
		}
		if((int)can_or_cannot((int)ch.x,(int)ch.y)==1 && tame.flag==0 && (int)ch.x%32==0 && (int)ch.y%32==0 ){
			hantei[(int)ch.y/BOX][(int)ch.x/BOX]=0;
			if(tame.counter>0)tame.counter--;
		}
}

/////////////////////////////////////////////////
//main
/////////////////////////////////////////////////
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
	if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理
	SetDrawScreen(DX_SCREEN_BACK);
/////////////////////////////////////////////
//初期値
/////////////////////////////////////////////
	Init();
/////////////////////////////////////////////
	while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
        ////////////////////////////////////////////////////////////////////////////////
        //プログラム
		////////////////////////////////////////////////////////////////////////////////
		
		PlayerControl();
		PlayerDraw((int)ch.x, (int)ch.y);
		ShotCalc();
		ShotDisp();
		Kirai();
	    Map();	
		////////////////////////////////////////////////////////////////////////////////////////
		counter++;
		WindowMode();
		ScreenFlip();
		wait_func();

	}
		DxLib_End() ;				// DXライブラリ使用の終了処理
		return 0 ;					// ソフトの終了
}



Re: ゲーム作りについて part.1

Posted: 2012年4月19日(木) 17:20
by nil
ChangeWindowMode関数を使用するとすべてのグラフィックハンドルが
削除されるので、画像等は読み直さなければいけません

Re: ゲーム作りについて part.1

Posted: 2012年4月19日(木) 17:22
by softya(ソフト屋)
ざっと今実装されているゲームの操作やルールの説明をお願いします。何をしたいゲームなのかよくわかりませんでした。

[ちょっと訂正]
で、プログラミングの読みやすくなる書き方やバグの出ない書き方、やっては行けない危険なことなどはアドバイスできますが、ゲームの面白さは人それぞれなので面白さの基準はご本人が決めるのが一番です。参考程度の意見は書くことは出来ると思いますが現状目指しているものが良く分かりません。こういうのを作りたいがやり方が分からないと言う事であればアドバイスはもちろん可能ですよ。
ちなみに、プログラムの書き方としてはいくつか問題を感じます。

Re: ゲーム作りについて part.1

Posted: 2012年4月19日(木) 18:24
by h2so5
「C++をさわり今年で2年」という割には完全にC言語の規格で書いているのが気になります

Re: ゲーム作りについて part.1

Posted: 2012年4月20日(金) 10:57
by 電気屋
涼雅 さんが書きました:ChangeWindowMode関数を使用するとすべてのグラフィックハンドルが
削除されるので、画像等は読み直さなければいけません
ChangeWindowMode関数については初めて聞きました。ありがとうございます

Re: ゲーム作りについて part.1

Posted: 2012年4月20日(金) 11:02
by 電気屋
softya(ソフト屋) さんが書きました:ざっと今実装されているゲームの操作やルールの説明をお願いします。何をしたいゲームなのかよくわかりませんでした。

[ちょっと訂正]
で、プログラミングの読みやすくなる書き方やバグの出ない書き方、やっては行けない危険なことなどはアドバイスできますが、ゲームの面白さは人それぞれなので面白さの基準はご本人が決めるのが一番です。参考程度の意見は書くことは出来ると思いますが現状目指しているものが良く分かりません。こういうのを作りたいがやり方が分からないと言う事であればアドバイスはもちろん可能ですよ。
ちなみに、プログラムの書き方としてはいくつか問題を感じます。
そうですね、仕様書をwordで作ってはいるのですが。このサイト、アップロードできますか?
できなければ、写しますが・・・・・時間がかかると思います

Re: ゲーム作りについて part.1

Posted: 2012年4月20日(金) 11:07
by 電気屋
h2so5 さんが書きました:「C++をさわり今年で2年」という割には完全にC言語の規格で書いているのが気になります
はい、そうです。一応C++よりC言語寄りに今回はソースを書いてみました。
なぜかというと、ゲーム開発のときC言語のほうが基本的で、万人に受けると思ったからです。
一応勉強したのはC++となっているので今回は「C++を2年」と表記しました。

Re: ゲーム作りについて part.1

Posted: 2012年4月20日(金) 11:35
by softya(ソフト屋)
電気屋 さんが書きました:そうですね、仕様書をwordで作ってはいるのですが。このサイト、アップロードできますか?
できなければ、写しますが・・・・・時間がかかると思います
ここのファイル添付機能を使いためにはユーザー登録して貰う必要があります。
ユーザー登録リンクは、このページの下の方の右隅にあると思います。

ただ、そんなに大きな仕様なのでしょうか?数行で書けるほどのもので良いのですよ。
あと何処の部分が具体的に実装できないでいるか説明してもらってよいでしょうか。

それとソースコードの問題点はアドバイスしたほうが良いでしょうか?
電気屋 さんが書きました: なぜかというと、ゲーム開発のときC言語のほうが基本的で、万人に受けると思ったからです。
ソースコードは万人に受けるという意味がわからないんですが、どういう意味なのでしょう。
C++が得意ならC++で書かれたほうが良いと思いますけど。

Re: ゲーム作りについて part.1

Posted: 2012年4月20日(金) 11:44
by 電気屋
わかりました。仕様書は簡潔にまとめるのでちょっと待ってください。
万人に受けると書いたのは、
「C言語の書き方のほうが、JAVAやほかの言語の人が見たとき、理解しやすいから」と他のサイトで書いてあったので、「万人に受ける」と書きました。仕様書は画像を使ったりや自分の考えをまとめた文章なので、時間をください

Re: ゲーム作りについて part.1

Posted: 2012年4月20日(金) 11:48
by 電気屋
プログラムの間違えや、警告があれば遠慮なく教えてください。
プログラムは組んではいたのですが、我流なので間違った考え方や、ソースの書き方が多いと思うので教えてくださると助かります

Re: ゲーム作りについて part.1

Posted: 2012年4月20日(金) 12:27
by h2so5
例えば122行目からのこの行ですが、無駄に見にくい書き方です。

コード:

if(ch.muki==0)(ch.y<   0   )?ch.y=    0     :ch.y-=CH_SPEED;
if(ch.muki==1)(ch.x<   0   )?ch.x=    0     :ch.x-=CH_SPEED;
if(ch.muki==2)(ch.y>=Window_H-BOX)?ch.y=(Window_H-BOX):ch.y+=CH_SPEED;          
if(ch.muki==3)(ch.x>=Window_W-BOX)?ch.x=(Window_W-BOX):ch.x+=CH_SPEED;
自分ならこう書きます。

コード:

switch (ch.muki) {
    case 0:
        if (ch.y < 0) ch.y = 0;
        else ch.y -= CH_SPEED;
        break;

    case 1:
    ...
}

Re: ゲーム作りについて part.1

Posted: 2012年4月20日(金) 12:44
by softya(ソフト屋)
それでは気になる点を。

・コメントが自己主張しすぎているとおもいます。
 なんでもかんでも////////////////////////////はいらないかと。
 //---------------------------------------
//============================
とか使い分けではどうでしょう。
・//プログラムなどの見て分かるコメントは必要ありません。
・インデントの一部が乱れています(字下げの空白数も統一性がありません)。
・引数をもっと多用してしてください。
・引数と絡みますが出来るだけグローバル変数は使わないで下さい。
・処理と描画のタイミングは分離して下さい。描画だけScreenFlip();前にまとめた行ったほうが良いです。
・1つの関数に複数の機能がある場合があり関数名と機能が一致しません
・関数名は動詞+名詞で統一されると良いと思います。
・弾や機雷はPlayerに属するなら名前をそういう風にしたほうが良いかと。

Re: ゲーム作りについて part.1

Posted: 2012年4月20日(金) 13:01
by nullptr
じゃあ私も少し。一番気になったのは、命名規則がバラバラなことです。一般的でない命名規則を使っているのも気になります。
例えば、Key[256]やcounter、can_or_cannot関数とPlayerDraw関数など。
まぁ個人製作ならどんな命名規則を使うかは好みで使えばいいと思いますが、変数や構造体や関数の名前の命名規則は統一したほうが見やすいし、タイプミスも減ると思います。

あとコメントですが、
////////////////////////////////////////////////////////////////////////////////
//プログラム
////////////////////////////////////////////////////////////////////////////////
soft屋さんも指摘しているように主張が強すぎて肝心のコードが見難いです。
これくらい主張するコメントは、コードの始めにコード全体の概要をまとめるなどのレベルに使うべきかと。

それと、プロトタイプ宣言の意味が大してありません。まぁ、コード内に定義してある関数がまとまってわかるのであって損はしないですが。

Re: ゲーム作りについて part.1

Posted: 2012年4月26日(木) 15:17
by 電気屋
仕様書遅れました。下記の記述が仕様書です。
ゲーム名『バトルシップ』
ストーリ:
基本はボンバーマンみたいな感じで、複数のプレイヤー(またはCP)が1画面内で先頭をするゲーム

攻撃方法は3種類
直線的攻撃:画面外出るまで直線的に進むみ当たると高ダメージ
範囲的攻撃:自分範囲(半径)から一定の中ダメージ
トラップ式攻撃:ボンバーマンのボム見たいに一定条件を満たすと爆発(範囲によってダメージが異なる)
ダメージ表↓(3は高ダメージ、2は中ダメージ、1は小ダメージ)
ーーーーーーーーー    
  121
 12321
 23◆32
 12321
  121
ーーーーーーーー

HP表記:ゲージ制(値は100とする)
    値が減少するにつれて移動スピードを減少させる。(最大5段階変化)

障害物:ランダムで表示
    playerは障害物を破壊しない限り、その障害物のある道を通ることはできない
    一定ダメージで破壊

勝敗条件:相手か自分のHPが0になるか時間オーバーでHPを比べて勝敗を出す

移動方法:一定間隔の移動中は方向転を換認めない。また後退は禁止(使用不可)とする
     playerには方向が記憶されてダメージを受ける際、正面やサイドでダメージ倍率が変わる

これが自分の作った仕様書の簡易版です。まだほかにストーリー用の的の動きや細かいゲームルールもありますが、上記のことができるようになることが今の目標なのでこれを読んだらコメください

Re: ゲーム作りについて part.1

Posted: 2012年4月26日(木) 15:47
by softya(ソフト屋)
仕様を読みました。
まず、やりたい事とと出来ていることにギャップがあります。
なので、もっと簡易的な部分からステップアップから組み立てていくほうが良いでしょう。
自機の移動、攻撃、ゲージ表示、障害物、敵の出現、攻撃、ダメージ処理あたりを順番に作ってみてはどうでしょうか?
それと機雷なんかは後で良いんじゃないでしょうか。自機と弾の処理で最初はいっぱいいっぱいだと思います。

「気になること」
・色々な所に気が回っていないポイントとして船なのにwalking_flag;と変数名に付けている所でしょうか。もっと良い名前がありますよね。
・後進不可など部分が全く実装されていないこと。