ページ 11

インベーダーゲーム作成のアドバイス

Posted: 2014年5月01日(木) 15:03
by 電気屋
現在コマンドラインで動く「インベーダーゲーム」を制作しているのですが、弾の軌道を関数で定義するとどうしても上手くいきません。
特に、弾を発射時の描画と移動定義が現在のところうまくいきません。下記がソースプログラムです。
「インベーダーゲーム」を作る上で改善したほうが良い場所もあればコメントくださいお願いします

コード:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#define MAP 10
#define T_MAX 3
#define ENEMY 3
int chx;
int chy;

struct tamadeta {	/* 構造体の宣言 */
	int x;
	int y;
	int flag;
};
struct tamadeta tama[T_MAX];

int rdm;
int stg[MAP][MAP]={0};
int i,j;
char st;

void init();
void display();
void Key();
int move(int,int,int);
int enmove();
int wall(int,int,int);

int main(void){
	int time=0;

	init();
	while(1){
		if(kbhit())Key();//キーボード入力

		if(time<5000)time++;//タイマー
		
		else {
			for(i=0;i<T_MAX;i++){
				move(tama[i].x,tama[i].y,tama[i].flag);
				wall(tama[i].x,tama[i].y,tama[i].flag);;
			}
			display();
			time=0;
		}
		if(st==' ')break;
	}
	return 0;
}

void Key(){
	st=getch();
	switch (st){
		case 'K'://←
			if(stg[chx][chy-1] !=1){
				stg[chx][chy]=0;
				chy--;
			}
			break;
		case 'H'://↑
			if(stg[chx-1][chy] !=1){
				stg[chx][chy]=0;
				chx--;
			}
			break;
		case 'M'://→
			if(stg[chx][chy+1] !=1){
				stg[chx][chy]=0;
				chy++;
			}
			break;
		case 'P'://↓
			if(stg[chx+1][chy] !=1){
				stg[chx][chy]=0;
				chx++;
			}
			break;
		case 'z':
			for(i=0;i<T_MAX;i++){
				if(tama[i].flag == 0 ){
					tama[i].x=chx-1;
					tama[i].y=chy;
					tama[i].flag=1;
				}
			}
			stg[chx-1][chy]=3;
			break;
	}
	stg[chx][chy]=2;
}
void init(){
	chx= MAP-2;
	chy=((MAP/2)+(MAP%2));
	
	for(i=0;i<T_MAX;i++)tama[i].flag = 0;
	
	for(i=0;i<MAP;i++){
		for(j=0;j<MAP;j++){
			if(i==0 || i==MAP-1 || j==0 || j==MAP-1)stg[i][j]=1;
			else                                    stg[i][j]=0;
		}
	}
	stg[chx][chy]=2;
}

void display(){
	system("cls");
	for(i=0;i<MAP;i++){
		for(j=0;j<MAP;j++){
			if     (stg[i][j]==0)printf(" ");
			else if(stg[i][j]==1)printf("■");
			else if(stg[i][j]==2)printf("凸");
			else if(stg[i][j]==3)printf("||");
			else                 printf("G");
		}       
		printf("\n");
	}
	
}

int move(int x,int y,int flag){
	if(flag==1){
		x--;
		if(stg[x+1][y]==3)stg[x+1][y]=0;
		stg[x][y]=3;
	}
	return x,y,flag;
}

int wall(int x,int y,int flag){
	if(stg[x-1][y]==1){
		flag=0;
		stg[x][y]=0;
	}
	return 0;
}

int enemove(int x,int y,int flag){
	if(stg[x+1][y]==1){
		flag=0;
		stg[x][y]=0;
	}
	if(flag==1){
		x++;
		if(stg[x-1][y]==4){
			stg[x-1][y]=0;
			}
			
		stg[x][y]=4;
	}
	return x,y,flag;

Re: インベーダーゲーム作成のアドバイス

Posted: 2014年5月01日(木) 16:31
by 電気屋
こちらのコードが関数分けする前のコードです。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#define MAP 11
#define T_MAX 3

int chx;
int chy;

struct tamadeta {	/* 構造体の宣言 */
	int x;
	int y;
	int flag;
};
struct tamadeta tama[T_MAX];

int rdm;
int stg[MAP][MAP]={0};
int i,j;
char st;

void init();
void display();
void Key();
void move();

int main(void){
	int time=0;

	init();
	while(1){
		if(kbhit()){
			Key();//キーボード入力
			move();
		}

		if(time<5000)time++;//タイマー
		
		else {
			display();
			time=0;
		}
	}
	return 0;
}

void Key(){
	st=getch();
	switch (st){
		case 'K'://←
			if(stg[chx][chy-1] !=1){
				stg[chx][chy]=0;
				chy--;
			}
			break;
		case 'H'://↑
			if(stg[chx-1][chy] !=1){
				stg[chx][chy]=0;
				chx--;
			}
			break;
		case 'M'://→
			if(stg[chx][chy+1] !=1){
				stg[chx][chy]=0;
				chy++;
			}
			break;
		case 'P'://↓
			if(stg[chx+1][chy] !=1){
				stg[chx][chy]=0;
				chx++;
			}
			break;
		case 'z':
			for(i=0;i<T_MAX;i++){
				if(tama[i].flag == 0 ){
					tama[i].x=chx-1;
					tama[i].y=chy;
					tama[i].flag=1;
				}
			}
			break;
	}
	stg[chx][chy]=2;
}
void init(){
	chx= MAP-2;
	chy=((MAP/2)+(MAP%2));
	
	for(i=0;i<T_MAX;i++)tama[i].flag = 0;
	
	for(i=0;i<MAP;i++){
		for(j=0;j<MAP;j++){
			if(i==0 || i==MAP-1 || j==0 || j==MAP-1)stg[i][j]=1;
			else                                    stg[i][j]=0;
		}
	}
	stg[chx][chy]=2;
}


void display(){
	system("cls");
	for(i=0;i<MAP;i++){
		for(j=0;j<MAP;j++){
			if     (stg[i][j]==0)printf(" ");
			else if(stg[i][j]==1)printf("■");
			else if(stg[i][j]==2)printf("凸");
			else if(stg[i][j]==3)printf("||");
			else                 printf("G");
		}       
		printf("\n");
	}
}

void move(){
	for(i=0;i<T_MAX;i++){
		if(tama[i].x==1){
			tama[i].flag=0;
			stg[tama[i].x][tama[i].y]=0;
		}
		else if(tama[i].flag==1){
			stg[tama[i].x][tama[i].y]=3;
			if(stg[tama[i].x-1][tama[i].y]!=2)stg[tama[i].x][tama[i].y]=0;
			tama[i].x--;
			stg[tama[i].x][tama[i].y]=3;
		}
	}

}

Re: インベーダーゲーム作成のアドバイス

Posted: 2014年5月01日(木) 17:14
by box
電気屋 さんが書きました:どうしても上手くいきません。
どのようにうまくいかないのか、具体的に示すことは可能ですか?
電気屋 さんが書きました:

コード:

	return x,y,flag;
	return x,y,flag;
この2つの文は、何を意図したものでしょうか。
構造体を返したいのだとすれば、意図どおりになっていません。
いずれも、flag「だけ」を返すようになっています。
また、仮に構造体を返したいのだとすれば、関数の型もそれに見合うように
修正する必要があります。int型ではなく。

Re: インベーダーゲーム作成のアドバイス

Posted: 2014年5月01日(木) 17:49
by box
電気屋 さんが書きました:

コード:

int enmove();
int enemove(int x,int y,int flag){
関数のプロトタイプ宣言と実体の名前とが食い違っています。
また、enemove(あるいはenmove)を呼び出している形跡がありません。
電気屋 さんが書きました:

コード:

int move(int,int,int);
int wall(int,int,int);
				move(tama[i].x,tama[i].y,tama[i].flag);
				wall(tama[i].x,tama[i].y,tama[i].flag);;
moveやwallの戻り値の型をintにしている意図はどこにありますか?
一般に、関数がvoid以外の戻り値を持つということは、
その戻り値を呼び出し側で使うからだと思うのです。
あえて使わないというケースはありますが、あくまで例外。

Re: インベーダーゲーム作成のアドバイス

Posted: 2014年5月02日(金) 16:32
by 電気屋
コメントありがとうございます。
言葉足らずで、申し訳ありませんでした。

現在、困っているところ、
・キーボード入力’z’ で「弾("||"=3)」を描画して壁(■.配列[1][ ])に到達したらflagを0にする。
この処理なのですが、キーボード入力’z’を連続して押すと画面上に"||"が残ることがあります。
("||"=3)が残らないようにするにはどのように書き換えればよいですか?

・描画位置が「自機(’凸’=2)」の2つ上に(一つ空白が空いて)出力されます。順番を変えたり値を変えたりしているのですが、どうしても自機の前に出力されていないと思います。
実機の前に描画するにはどこの処理にstg[chx-1][chy]=3と入れればよいですか。

アドバイスをください。よろしくお願いします




コード:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#define MAP 10
#define T_MAX 3
#define ENEMY 3
int chx;
int chy;
 
struct data {   /* 構造体の宣言 */
    int x;
    int y;
    int flag;
};

struct data tama[T_MAX];
struct data enemydata[ENEMY];		 
int rdm;
int stg[MAP][MAP]={0};
int i,j;
char st;
 
void init();
void display();
void Key();
void move();
void enemy();
void enemove();

int main(void){
	int time=0;
	init();
	while(1){		
        if(kbhit())Key();//キーボード入力
        if(time<5000)time++;//タイマー
   
        else {     
			move();
			//enemy();
			//enemove();
            display();
            time=0;
        }
        if(st==' ')break;
    }
    return 0;
}
 
void Key(){
    st=getch();
	stg[chx][chy]=0;
    switch (st){
        case 'K'://←
            if(stg[chx][chy-1] !=1)chy--;
            break;
        case 'H'://↑
            if(stg[chx-1][chy] !=1)chx--;
            break;
        case 'M'://→
            if(stg[chx][chy+1] !=1)chy++;
            break;
        case 'P'://↓
            if(stg[chx+1][chy] !=1)chx++;
            break;
        case 'z':
            for(i=0;i<T_MAX;i++){
                if(tama[i].flag == 0 ){
                    tama[i].x=chx-1;
                    tama[i].y=chy;
                    tama[i].flag=1;
                }
            }
            stg[chx-1][chy]=3;
            break;
    }
    stg[chx][chy]=2;
}
void init(){
    chx= MAP-2;
    chy=((MAP/2)+(MAP%2));
    srand((unsigned int) time(NULL));
    for(i=0;i<T_MAX;i++)tama[i].flag = 0;
    
    for(i=0;i<MAP;i++){
        for(j=0;j<MAP;j++){
            if(i==0 || i==MAP-1 || j==0 || j==MAP-1)stg[i][j]=1;
            else                                    stg[i][j]=0;
        }
    }
    stg[chx][chy]=2;
}
 
void display(){
    system("cls");
    for(i=0;i<MAP;i++){
        for(j=0;j<MAP;j++){
            if     (stg[i][j]==0)printf(" ");
            else if(stg[i][j]==1)printf("■");
            else if(stg[i][j]==2)printf("凸");
            else if(stg[i][j]==3)printf("||");
            else                 printf("G");
        }       
        printf("\n");
    }
    
}
 
void move(){
	for(i=0;i<T_MAX;i++){
		if(stg[tama[i].x-1][tama[i].y]==1){
        	tama[i].flag=0;
        	stg[tama[i].x][tama[i].y]=0;
		}
		       
    	if(tama[i].flag==1){
        	tama[i].x--;
        	if(stg[tama[i].x+1][tama[i].y]==3){
				stg[tama[i].x+1][tama[i].y]=0;
        	}
        	stg[tama[i].x][tama[i].y]=3;
   		
		}
		
	}
}
  
void enemy(){
	for( i=0; i < ENEMY ; i++){
		if(enemydata[i].flag == 0){
			rdm= (rand() % (MAP-2))+1;
			enemydata[i].y=rdm;
			enemydata[i].flag=1;
		}
	}
}

void enemove(){
	for( i=0; i < ENEMY ; i++){
		if(stg[enemydata[i].x+1][enemydata[i].y]==1){
			enemydata[i].flag=0;
			stg[enemydata[i].x][enemydata[i].y]=0;
		}
		if(enemydata[i].flag==1){
        	enemydata[i].x++;
        	if(stg[enemydata[i].x-1][enemydata[i].y]==4){
				stg[enemydata[i].x-1][enemydata[i].y]=0;
        	}
        	stg[enemydata[i].x][enemydata[i].y]=4;
		}
	}
}

Re: インベーダーゲーム作成のアドバイス

Posted: 2014年5月02日(金) 20:48
by softya(ソフト屋)
質問の第一目標はちゃんと関数化する事にあって、動く以前にちゃんとした関数の使い方を理解することが第一なのではないでしょうか?
その結果ちゃんと動くようになるというのが理想だと思うのです。

と言うことで、boxさんの回答から一番容易な選択をされたと思いますが、全部グローバル変数にするのは元々意図されたことに反していないでしょうか?
【訂正】 関数分けする前と大差の無いコードになっていると思いますが。 関数分けの前のコードには敵処理がありませんでした。
電気屋 さんが書きました:現在、困っているところ、
・キーボード入力’z’ で「弾("||"=3)」を描画して壁(■.配列[1][ ])に到達したらflagを0にする。
この処理なのですが、キーボード入力’z’を連続して押すと画面上に"||"が残ることがあります。
("||"=3)が残らないようにするにはどのように書き換えればよいですか?

・描画位置が「自機(’凸’=2)」の2つ上に(一つ空白が空いて)出力されます。順番を変えたり値を変えたりしているのですが、どうしても自機の前に出力されていないと思います。
実機の前に描画するにはどこの処理にstg[chx-1][chy]=3と入れればよいですか。
これは関数化前から同じ問題は無いのでしょうか?