ダンジョンゲーム 「敵が隠れられるブロック」

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

ダンジョンゲーム 「敵が隠れられるブロック」

#1

投稿記事 by あるちゃん » 9年前

たびたびご迷惑おかけします。
今回もどうかお知恵を拝借願いたくお願い申し上げます。

現在、文字だけで構成されたダンジョンゲームを作っていまして、
マップ上を敵が徘徊し、当たるとバトルに移行する仕組みになっています。
ただ、敵が急に現れるといった仕組みがあった方がオモシロいと、
移動してきた敵コマが隠れられるブロック『森』を
マップ上に作ろうと思いました。

  森森森
△ 森森←敵 (敵が森ブロックに入ると)

   ↓

  森森森  (森の中に姿が隠れて見えなくなる。)
△ 森森   ((森の方が優先的に描画される))

しかしいざ実装しようとしてみても

  森森森
△ 森森←敵 (敵が森ブロックに入ると)

   ↓

  森森森 
△ 森[敵]

森の上に敵が描画されてしまいます。

どうか森ブロックの方を敵より優先的に描画できる方法を教えていただけませんでしょうか?

ちなみにソースコードはこちらです
3つのファイルに分割おり「main.cpp」がマップ描画に関わる部分になります。
また、特にマップの表示に関わる部分は「main.cpp」の215行目からになります。
マップの「0」が何もない部分
    「1」が障害物
    「2」が問題の『森』ブロック になります。

また敵は「WF」=オオカミ
    「DG」=ドラゴン
としています。

↓ 「All.h」
 

コード:


/*--ヘッダ インクルード-----------------------------------------*/
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>

/*--定数---------------------------------------------------------*/

#define dx_max 16
#define dy_max 12

#define TEKI_MAX 4

/*--ゲーム状態遷移-----------------------------------------------*/

typedef enum Scene{
	S_TITLE,
	S_GAME,
	S_BATTLE,
	S_OVER,
	S_CLEAR,
	S_END
}scene;

/*--構造体型定義------------------------------------------------*/

typedef struct Model{
	char *n;
	int ux, uy;			//現座標
	int pre_x,pre_y;	//前座標
	int encount_flg;	//当たった敵の判定
	int event_flg;		//イベントフラグ
}model;


// battle.cppから

typedef struct Character
{
	int lp;		// 体力
	int str;	//攻撃力
	int def;	//防御力
	int speed;  //素早さ
	int state;	//コマンド状態
}character;


/*--関数プロトタイプ--------------------------------------------*/

int keyCtrl(model *);								//キー入力
void view_dungeon(model *, model *, int[][dx_max]);	//表示
int hitTest(model *, int[][dx_max],int);			//壁との当たり判定

void title(void);
void g_main(void);

void g_battle(void);

void g_over(void);
void g_clear(void);

void my_srand(int);	//シード値セット
long xor128(void);	//乱数生成

void e_Ctrl(model *);	//敵コントロール


//battle.cppから

void set_parameter();
int strdef();
void attack();
void attackofcharacter();
void firstattacker();
int isdead();
void isdeadmessage();
int battleMain();

/*--グローバル変数----------------------------------------------*/

extern int dungeon[dy_max][dx_max];

extern scene g_Sequence;

extern model init_jiki;
extern model jiki;

extern model init_teki[];
extern model teki[TEKI_MAX];

extern int seed;	//乱数のシード値

extern int e_flg;

↓ 「main.cpp」

コード:


/*--ヘッダ インクルード-----------------------------------------*/

#include"all.h"

/*--グローバル変数----------------------------------------------*/

int init_dungeon[dy_max][dx_max] = {
	//0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
	{ 1, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1},
	{ 1, 0, 2, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 1},
	{ 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 2, 2, 2, 1},
	{ 1, 0, 2, 2, 2, 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 1},
	{ 1, 0, 2, 0, 0, 2, 0, 2, 2, 0, 0, 2, 0, 2, 0, 1},
	{ 1, 0, 2, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 0, 1},
	{ 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1},
	{ 1, 0, 2, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 1},
	{ 1, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1},
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};

int dungeon[dy_max][dx_max];

scene g_Sequence = S_TITLE;

model init_jiki = { "jiki", 1,1,0,0,0};
model jiki;

model init_teki[] ={	//構造体の配列化
	{"Walf", 1,7,0,0,0,0},
	{"Walf", 3,5,0,0,0,0},
	{"Walf", 8,1,0,0,0,0},
	{"Dragon", 9,9,0,0,0,0},
};
model teki[TEKI_MAX];

int seed;	//乱数のシード値

int e_flg=0;
/*--エントリーポイント------------------------------------------*/
void main(void)
{
	for(;;){		//ゲームループ

		switch(g_Sequence){			//状態遷移
						case S_TITLE: title();
							break;

						case S_GAME: g_main();
							break;

						case S_BATTLE: g_battle();
							break;

						case S_OVER: g_over();
							break; 

						case S_CLEAR: g_clear();
							break;
						default: break;
						}
						//終了
						if(g_Sequence==S_END){												//if(g_Sequenceの == を = だけで記述したら、ゲームが始まった瞬間 S_END へと向かいました)
							printf("ゲームを終了します\n Please press any key. \n");
							getch();
							break;
						}
			}
}
/*--関数本体定義-------------------------------------------------*/

//タイトル画面

void title(void){
	int i,s_cnt = 0;

	system("cls");
	printf("TITLE\n");
	printf(" Push Any Key \n");

			//シード値カウント
			s_cnt++;
			if(s_cnt>256){s_cnt=0;}	//256越えたらゼロクリア

	if(kbhit()){
		//データ初期化
		my_srand(s_cnt);	//シード値セット

		jiki = init_jiki;	//自機初期化

		for(i=0; i<TEKI_MAX; i++){
			teki[i]=init_teki[i];	//敵の初期値を一括代入で初期化
		}//これ参考

		//ゲーム本体へ
		g_Sequence = S_GAME;
	}
}

void g_main(void){
	
	int btn=0;

	/*--入力-*/
	btn =keyCtrl(&jiki);				//player は model型の変数なので、参照には「&」をつける

	/*--処理--*/
	if(hitTest(&jiki, dungeon,1)){	//壁当たり判定
		//壁なら前座標に戻す
		jiki.ux = jiki.pre_x;
		jiki.uy = jiki.pre_y;
	}

	if(hitTest(&jiki, dungeon, 3)){
		teki->ux = teki->pre_x;
		teki->uy = teki->pre_y;
		jiki.encount_flg = 1;
		teki->encount_flg = 1;
		g_Sequence = S_BATTLE;
	}

	if(hitTest(&jiki, dungeon, 4)){
		teki->ux = teki->pre_x;
		teki->uy = teki->pre_y;
		jiki.encount_flg = 2;
		teki->encount_flg = 1;
		g_Sequence = S_BATTLE;
	}

	//敵が動き回る

	e_Ctrl(teki);

	//ゲームオーバー
	if(btn==2){g_Sequence = S_END;}		//ゲーム終了(btn==2はesc , keyCtrl()で紐づけ)
	
	/*--表示--*/
	view_dungeon(&jiki, teki, dungeon);

}

void g_battle(void){

	int i;
	
	system("cls");

	battleMain();

	printf("Push anykey");
	getch();

	jiki.ux = jiki.pre_x;
	jiki.uy = jiki.pre_y;

}

void g_over(void){
	system("cls");
	printf("GAME_OVER\n");
	printf("Push AnyKey");
	getch();

	g_Sequence = S_TITLE;	//タイトルへ
}

void g_clear(void){
	system("cls");
	printf("GAME_CLEAR\n ! congratulations ! \n Push anykey");
	getch();

	g_Sequence = S_TITLE;
}

//--------------------------------------------------------------------
//キー入力
int keyCtrl(model *us)
{
	int key;	//キー入力

	//前情報の取得
	us->pre_x=us->ux;
	us->pre_y=us->uy;

	//キー入力
	//if(kbhit()){
		key = getch();
		if(key == 56 && us->uy>0){us->uy--;}			//8↑
		if(key == 50 && us->uy<(dy_max-1)){us->uy++;}	//2↓
		if(key == 52 && us->ux>0){us->ux--;}			//4←
		if(key == 54 && us->ux<(dx_max-1)){us->ux++;}	//6→
		if(key == 27){return 2;}								//esc:終了

	//}
	return 0;
}

//当たり判定////////////////////////////////////////////////////

//壁との当たり判定
int hitTest(model *us, int d_dat[][dx_max], int id){
	if(d_dat[us->uy][us->ux]==id){
		return 1;	//当たっている
	}else{
		return 0;	//当たっていない
	}
}



//表示//////////////////////////////////////////////////////////

//マップ表示
void view_dungeon(model *usr, model *teki, int d_dat[][dx_max])
{
	int i, j, k;	//カウンタ用

	for(i=0;i<dy_max;i++){//y
		for(j=0;j<dx_max;j++){	//x
			dungeon[i][j] = init_dungeon[i][j];	//ダンジョンデータを初期化に

			for(k=0; k<TEKI_MAX; k++){
				if(j == (teki + k)->ux && i == (teki+k)->uy){
					if(*(teki+k)->n=='D'){dungeon[i][j] = 3;} //ドラゴンを書き込む
					if(*(teki+k)->n=='W'){dungeon[i][j] = 4;}	//オオカミの位置を書きこむ
																//(enemy+k)は「*」をつける前に()で囲むこと(kは配列を動かす参照にされている)※教科書p189
				}
			}
		}
	}

	system("cls");
	for(i=0; i<dy_max; i++){//y軸
		for(j=0; j<dx_max; j++){//x軸

			if(j == usr->ux && i == usr->uy && e_flg==0 ){printf("人");}
			else if(d_dat[i][j] == 0/* && e_flg==0*/){printf(" ");}//床
			else if(d_dat[i][j] == 1){printf("山");}//山
			else if(d_dat[i][j] == 2){printf("森");}//森
			else if(d_dat[i][j] == 3){printf("DR");}//ドラゴン
			else if((d_dat[i][j] == 4)&&(d_dat[i][j] != 2)){printf("WF");}//オオカミ

			//else if(d_dat[i][j] == 2 || d_dat[i][j] || d_dat[i][j] == 4){printf("森");}  
			}
		printf("\n");//改行
	}
}
//乱数/////////////////////////////////////////////////////////////

void my_srand(int s)
{
	seed = s;
}

long xor128(void)
{
	long t;
	static long x=123456789, y=362436069, z=521288629,w;
	w^= (long)seed*1812433253;

	t=(x^(x<<11));
	x=y;y=z;z=w;
	return( w=(w^(w>>19))^(t^(t>>8)) );
}

//敵コントロール///////////////////////////////////////////////////
void e_Ctrl(model *en)
{
	int k, mov_flg;

	for(k=0; k<TEKI_MAX; k++){
		//前座標の取得
		(en+k)->pre_x = (en+k)->ux;
		(en+k)->pre_y = (en+k)->uy;

		mov_flg = xor128()%4;	//0-3

		switch(mov_flg){
		case 0: //↑
			(en+k)->uy--;
			break;
		case 1: //↓
			(en+k)->uy++;
			break;
		case 2:	//←
			(en+k)->ux--;
			break;
		case 3: //→
			(en+k)->ux++;
			break;
		}
		//更新座標が壁に当たっていたら戻す
		if(hitTest((en+k), init_dungeon, 1))
		{
			(en+k)->ux = (en+k)->pre_x;
			(en+k)->uy = (en+k)->pre_y;
		}

		//
		if((en+k)->ux<1){(en+k)->ux=1;}
		if((en+k)->ux>15){(en+k)->ux=15;}
		if((en+k)->uy<1){(en+k)->uy=1;}
		if((en+k)->uy>12){(en+k)->uy=12;}

	}
}
↓ 「battle.cpp」

コード:


#include"all.h"

/*
typedef struct
{
	int lp;		// 体力
	int str;	//攻撃力
	int def;	//防御力
	int speed;  //素早さ
	int state;	//コマンド状態
}character;
*/

void set_parameter(character* param, int lp, int str, int def, int speed, int state)
{
	param->lp = lp;
	param->str = str;
	param->def = def;
	param->speed = speed;
	param->state = 0;
}

//プレイヤーの攻撃力より敵の防御力が低いときにダメージ

int strdef(int player_str, int enemy_def)
{
	if(player_str < enemy_def)
	{
		return 0;
	}else{
		return(player_str - enemy_def);
	}
}


//ダメージ処理 プレイヤー→敵

void attack(character* player, character* enemy)
{
	if(player->state == 0)
	{
		enemy->lp -= strdef(player->str, enemy->def);
	}else{
		//防御時
		enemy->lp -= strdef(player->str,(enemy->def*2));
	}
}

void attackofcharacter(character* attacker, character* defender, int command)
{
	if(command % 2 == 0)
	{
		attacker->state = 0;

		attack(attacker, defender);
	}

	if(command % 2 == 1)
	{
		attacker->state = 1;
	}
}

void firstattacker(character* attacker, character* defender, int command)
{
	//自分の素早さ > 相手の素早さのとき

	if(attacker->speed > defender->speed)
	{
		printf("あなたの先攻\n");

		attackofcharacter(attacker, defender, command);

		attackofcharacter(defender, attacker, rand());

	
	}else{

		printf("敵の先攻\n");

		attackofcharacter(defender, attacker, rand());

		attackofcharacter(attacker, defender, command);


	}
}

//死亡かどうかの判定

int isdead(int lp)

{

	if(lp < 1)

	{

		return 1;
	
	}else{

		return 0;

	}

}

//死亡時のメッセージの表示

void isdeadmessage(character player, character enemy)

{
	//プレイヤーの死亡判定
	if(isdead(player.lp) == 1)
	
	{

		printf("あなたはヤラレタ\n");

	}

	//敵の死亡判定

	if(isdead(enemy.lp) == 1)

	{

		printf("敵をやっつけた!\n");

	}

}


int battleMain()

{
	character player;

	character enemy;

	int command = 0;

	set_parameter(&player, 100, 30, 15, 30, 0);
	
	int i;
	
	system("cls");

	switch(jiki.encount_flg){
	case 1:
		printf("ボスの『ドラゴン』が現れた!\n");
		getch();
		printf("こいつを倒せば終わりだ!!\n");
		break;
	case 2:
		printf("『オオカミ』が現れた!\n");
		break;
	}


	switch(jiki.encount_flg){
			{
		case 1: set_parameter(&enemy, 150, 30, 15, 20, 0);
			break;

		case 2: set_parameter(&enemy, 60, 30, 15, 40, 0);
			break;
		default: break;
			}
		}

	
	while(1)
	{
		if(isdead(player.lp) == 1 || isdead(enemy.lp) == 1)
		{
			isdeadmessage(player, enemy);
			break;
		}	


		printf("プレイヤーの残り体力: 『 %d 』, 敵の残り体力:『 %d 』\n", player.lp, enemy.lp);


		scanf("%d", &command);

		firstattacker(&player, &enemy,command);

		if(player.lp<1){g_Sequence = S_OVER; break;}

	
		if(enemy.lp<1){

			switch(jiki.encount_flg){

			case 1: g_Sequence = S_CLEAR;
				break;

			case 2: g_Sequence = S_GAME;
				break;
			}

			for(i=0; i<TEKI_MAX; i++)
			{
				if(teki[i].encount_flg=1){teki[i] = init_teki[i];}
				//if((teki[i].ux==jiki.ux)&&(teki[i].uy==jiki.uy)){teki[i]=init_teki[i];}
			}
		}
	}

	return 1;
}


Poco
記事: 161
登録日時: 14年前

Re: ダンジョンゲーム 「敵が隠れられるブロック」

#2

投稿記事 by Poco » 9年前

あるちゃん さんが書きました:   森森森
△ 森森←敵 (敵が森ブロックに入ると)

   ↓

  森森森  (森の中に姿が隠れて見えなくなる。)
△ 森森   ((森の方が優先的に描画される))

しかしいざ実装しようとしてみても

  森森森
△ 森森←敵 (敵が森ブロックに入ると)

   ↓

  森森森 
△ 森[敵]

森の上に敵が描画されてしまいます。

コード:

(snip)
//マップ表示
void view_dungeon(model *usr, model *teki, int d_dat[][dx_max])
{
	int i, j, k;	//カウンタ用

	for(i=0;i<dy_max;i++){//y
		for(j=0;j<dx_max;j++){	//x
			dungeon[i][j] = init_dungeon[i][j];	//ダンジョンデータを初期化に

			for(k=0; k<TEKI_MAX; k++){
				if(j == (teki + k)->ux && i == (teki+k)->uy){
					if(*(teki+k)->n=='D'){dungeon[i][j] = 3;} //ドラゴンを書き込む
					if(*(teki+k)->n=='W'){dungeon[i][j] = 4;}	//オオカミの位置を書きこむ
																//(enemy+k)は「*」をつける前に()で囲むこと(kは配列を動かす参照にされている)※教科書p189
				}
			}
		}
	}
(snip)

「ドラゴンを書き込む」「オオカミの位置を書きこむ」際に、dungeon[j]が森なら森のままにしてはどうでしょう?

あるちゃん

Re: ダンジョンゲーム 「敵が隠れられるブロック」

#3

投稿記事 by あるちゃん » 9年前

Poco様。ご指摘ありがとうございます。

以下のように、マップ上の森(2)が描かれていなければ、敵を描画しないという風に処理を書き替えましたところ、
敵よりも「森」の方を優先して書きこまれるようになりました。

コード:

	for(k=0; k<TEKI_MAX; k++){
				if(j == (teki + k)->ux && i == (teki+k)->uy){
					if((*(teki+k)->n=='D') && (dungeon[i][j] != 2)){dungeon[i][j] = 3;} //ドラゴンを書き込む
					if((*(teki+k)->n=='W') && (dungeon[i][j] != 2)){dungeon[i][j] = 4;}	//オオカミの位置を書きこむ
																//(enemy+k)は「*」をつける前に()で囲むこと(kは配列を動かす参照にされている)
				}
しかしながら、「3」、または「4」と書きこまれたところ = 自機の座標 → バトルに突入
という処理をしていましたので、
「3」「4」と書き込まれなくなったことで、敵とエンカウントすることが出来なくなってしまいました。

そこで純粋に自機と敵の座標が合えばバトルに突入する関数 encountHit(); を作りましたが、
なかなか苦戦しています。^^;

Poco
記事: 161
登録日時: 14年前

Re: ダンジョンゲーム 「敵が隠れられるブロック」

#4

投稿記事 by Poco » 9年前

あるちゃん さんが書きました: しかしながら、「3」、または「4」と書きこまれたところ = 自機の座標 → バトルに突入
という処理をしていましたので、「3」「4」と書き込まれなくなったことで、敵とエンカウントすることが出来なくなってしまいました。

そこで純粋に自機と敵の座標が合えばバトルに突入する関数 encountHit(); を作りましたが、
なかなか苦戦しています。^^;
小手先の対処法ですが、負の値を隠れている状態としてみてはどうでしょうか?

表示するドラゴン→3
森に隠れたドラゴン→-3

こうすればdungeon[j]の絶対値を判定することで、現状のバトル突入判定ロジックが使えるんじゃないでしょうか?

あるちゃん

Re: ダンジョンゲーム 「敵が隠れられるブロック」

#5

投稿記事 by あるちゃん » 9年前

長らく返信できず大変申し訳ありません。

現在、何とか無事に敵キャラが「森」の中に隠れてくれるようになりました。
マップをすべて「森」で埋め尽くしても、エンカウントしてくれます。

まだ作っている途中なので、これから更に問題が出るかもですが、
ご指摘いただけたことで色々工夫ができ、良い結果へと繋がったと思っております。

ご丁寧なご指摘をいただきありがとうございました。
m(_ _)m

至らない点もございましたが、
よろしければ、また困った時にご指南いただけますよう、よろしくお願いします。


↓ 一応、現在のマップ表示に関わるソースコードです。

コード:


int init_dungeon[dy_max][dx_max]={
						{1,1,1,1,1},
						{1,6,6,6,1},
						{1,6,6,6,1},
						{1,6,6,6,1},
						{1,1,1,1,1},
					};

int dungeon[dy_max][dx_max];

--<中略>--

void viewDungeon(model_p *us, model_e *en, int dungeon[][dx_max])
{
	int i,j,k;

	for(i=0; i<dy_max; i++){
		for(j=0; j<dx_max; j++){
			dungeon[i][j]=init_dungeon[i][j];
			if(j==us->px && i==us->py){dungeon[i][j]=2;}	//自機の座標を「2」に書き換える
			for(k=0; k<TEKI_MAX; k++){
				if(j==(en+k)->ex && i==(en+k)->ey){
				if(((en+k)->type==3)&&(dungeon[i][j]!=6)){dungeon[i][j]=5;}
				if(((en+k)->type==2)&&(dungeon[i][j]!=6)){dungeon[i][j]=4;}
				if(((en+k)->type==1)&&(dungeon[i][j]!=6)){dungeon[i][j]=3;}
				}
			}
		}
	}
	system("cls");

	printf("残り体力 %d", player.hp);
	printf("\n");

	for(i=0; i<dy_max; i++){
		for(j=0; j<dx_max; j++){
			if(dungeon[i][j]==0){printf(" ");}
			if(dungeon[i][j]==1){printf("山");}  //「山」障害物
			if(dungeon[i][j]==2){printf("人");}  //「人」プレイヤー
			if(dungeon[i][j]==3){printf("龍");}  //「ドラゴン」ボス
			if(dungeon[i][j]==4){printf("WF");} //「ウルフ」狼(敵キャラ)
			if(dungeon[i][j]==5){printf("賊");}  //「盗賊」(敵キャラ)
			if(dungeon[i][j]==6){printf("森");}  //「森」敵キャラの隠れる場所。 
                                                                                       敵が突然飛び出すことがオモシロさを増すと思い、外したくなかった
		}
		printf("\n");
	}
}


閉鎖

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