コンソールアプリケーションに関して - 通行不可の壁

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

コンソールアプリケーションに関して - 通行不可の壁

#1

投稿記事 by 央真 » 14年前

質問させて頂きます。

コンソールアプリケーションでRPG(っぽいもの)を作成しているのですが、
通行不可の壁の作り方がわかりません。
(元のソースは某サイト様のものを参考とし、自分なりに改良させて頂きました)。

マップは二次元配列を利用しています。

MoveBlock関数で、二次元配列のマップを展開し、
プレイヤー(主人公)の座標(px,py)が、
二次元配列に対応するようにと自分なりにコードを書いたのですが、
なかなか難しくて、とりあえずマップ座標(0,0)の場とプレイヤー座標が一致した場合に、
通行不可と表示しようとしたのですが、
どうしてもマップ座標(1,1)の場所に表示されてしまいます。

現状の悩みは上記のような感じで、最終的には通行不可の壁を作りたいと思っています。

どなたかご教授頂けたら幸いです。

コード:

#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include "Console.h"

#define KEY_UP    0x48
#define KEY_DOWN  0x50
#define KEY_RIGHT 0x4d
#define KEY_LEFT  0x4b

#define MAP_SIZE_Y 20
#define MAP_SIZE_X 20

int i = 0, j = 0;

int px = 3, py = 4;

int map[100][100] = {
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},	
	{1,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,0,1},	
	{1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,1},	
	{1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1},	
	{1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,1},		
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
} ;

char *a = "@";//主人公
char *b = "#";//壁


void DrawMap()
{

	for ( j = 0; j < MAP_SIZE_Y; j++ )
	{
		for ( i = 0; i < MAP_SIZE_X; i++ )
		{
			if ( j == py && i == px ){
				printf(a);
				} else {
				switch ( map[j][i] ){
				default:printf(" "); break;
				case 1: printf(b); break;
				}
			}
		}
		printf("\n");
	}
}

void MoveBlock()
{
	for ( j = 0; j < MAP_SIZE_Y; j++ )
	{
		for ( i = 0; i < MAP_SIZE_X; i++ )
		{
			if( map[j][0] == py && map[0][i] == px ){
				if( j == 0 && i == 0 ){
				printf("通行不可");
				}
			}
		}
	}
}

void GetKey()
{
	switch ( getch() ){
		case KEY_UP:
			py--;
			break; //UP
		case KEY_DOWN:	
			py++; 
			break; //DOWN
		case KEY_LEFT:	
			px--; 
			break; //LEFT
		case KEY_RIGHT: 
			px++; 
			break;	//RIGHT
	}
}

void main()
{
	CConsole cnsl;

	cnsl.SetColor(H_GREEN, L_BLACK);

	while ( 1 )
	{
		system("cls");
		DrawMap();
		MoveBlock();
		GetKey();
	}
}

box
記事: 2002
登録日時: 15年前

Re: コンソールアプリケーションに関して - 通行不可の壁

#2

投稿記事 by box » 14年前

央真 さんが書きました:

コード:

	{
		system("cls");
		DrawMap();
		MoveBlock();
		GetKey();
	}
しろうとである私が口を出していいかどうかわかりませんが、
MoveBlock() の後で GetKey() ですか?

GetKey() でどの方向へ動くかを決めた後で、MoveBlock() でその方向へ動けるかどうかを判断する、のではなくて、ですか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

box
記事: 2002
登録日時: 15年前

Re: コンソールアプリケーションに関して - 通行不可の壁

#3

投稿記事 by box » 14年前

央真 さんが書きました: なかなか難しくて、とりあえずマップ座標(0,0)の場とプレイヤー座標が一致した場合に、
通行不可と表示しようとしたのですが、
どうしてもマップ座標(1,1)の場所に表示されてしまいます。

コード:

			if( map[j][0] == py && map[0][i] == px ){
				if( j == 0 && i == 0 ){
				printf("通行不可");
				}
			}
(0, 0) 以外のマップ座標とプレイヤー座標が一致した場合に「通行不可」と表示するようにしたら、
どうなりますか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

央真

Re: コンソールアプリケーションに関して - 通行不可の壁

#4

投稿記事 by 央真 » 14年前

お返事ありがとうございます。

そうですね。これは僕の間違いです。
GetKey()の後にMoveBlock()を書き直しました。
プログラミングに対する考え方がまだよくわかっていないようです。
なので、ゲーム作りでCの勉強をしていたんです。

コード:

 if( map[j][0] == py && map[0][i] == px ){
                if( j != 0 && i != 0 ){
                printf("通行不可");
                }
            } 
(0,0)以外とはつまりはこういう事なんでしょうか?
実行してみると、今度は座標(0,0)~(1,1)周辺にプレイヤー座標が来ると、
「通行不可」の文字が実行画面上に沢山出るようになってしまいました。

たぶん上記のコードが間違っているのでしょうが、自分にはどうすれば良いかわからず・・。
かれこれ数時間悪戦苦闘しています。
自分でコードを追加したものの、何か根本的な間違いをしているように思います。

壁「#」にプレイヤー「@」が接触したら、「通行不可」と表示させよう、というのが当面の課題です。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: コンソールアプリケーションに関して - 通行不可の壁

#5

投稿記事 by softya(ソフト屋) » 14年前

やりたい事からすると、移動キーが押されたらと言う条件で通過不可か可能か表示する必要があります。
なので、GetKey()で移動したフラグを戻り値で返す → 移動したならMoveBlock()でマップと当たり判定する
としないと行けないでしょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: コンソールアプリケーションに関して - 通行不可の壁

#6

投稿記事 by beatle » 14年前

コード:

            if( map[j][0] == py && map[0][i] == px ){
                if( j == 0 && i == 0 ){
                printf("通行不可");
                }
            }
思考を整理しましょう。以下 mapの「1」が壁で、「0」が通行可能な場所と仮定して話を進めます。
おそらく、次の1点だけ理解すればすんなりプログラムできるでしょう。
それは、プレイヤーが現在「壁」にいるのか「床」にいるのかの判断です。

ポイント: プレイヤー座標は(px,py)なので、map[py][px]でプレイヤーが「壁」と「床」どちらにいるか取得できる。

これが分かれば簡単で、プレイヤーが壁にいる場合に何か処理をするには、map[py][px] == 1のときに条件分岐すれば良いということになります。


以下、実際にプログラムの動作を追いかけつつ、何がおかしいかを考える道筋を示しました。
ただ、もしかしたら読むと混乱するので、隠してあります。長いですし。
► スポイラーを表示

央真

Re: コンソールアプリケーションに関して - 通行不可の壁

#7

投稿記事 by 央真 » 14年前

boxさん、 softyaさん、beatleさん、ありがとうございます。
それぞれの意見を参考にしコードを以下のように書き直した結果、
一応の完成をみました。
一応、というのはまだ曖昧な箇所があるからですが、満足な結果が得られたと思います。

コード:

int MoveBlock() //当たり判定を行う関数
{
	map[j][0] = py;
	map[0][i] = px;

	if( map[py][px] == 1 )
	{
		printf("通行不可");
		return 1;
	}
	else
	{
		return 0;
	}
}

void GetKey() //キー入力関数
{
	int flag = 0;

	switch ( getch() ){
		case KEY_UP:
			flag = MoveBlock(); //MoveBlock()の戻り値を変数flagに代入
			if( flag == 0 )     //変数flagに代入された戻り値が0のとき
				py--;           //プレイヤー座標を更新
			if( flag == 1 )		//変数flagに代入された戻り値が1のとき
				py++;			//プレイヤーは押し戻される
			break; //UP
		case KEY_DOWN:
			flag = MoveBlock(); //MoveBlock()の戻り値を変数flagに代入
			if( flag == 0 )     //変数flagに代入された戻り値が0のとき
				py++;			//プレイヤー座標を更新
			if( flag == 1 )		//変数flagに代入された戻り値が1のとき
				py--;			//プレイヤーは押し戻される
			break; //DOWN
		case KEY_LEFT:
			flag = MoveBlock(); //MoveBlock()の戻り値を変数flagに代入
			if( flag == 0 )     //変数flagに代入された戻り値が0のとき
				px--;			//プレイヤー座標を更新
			if( flag == 1 )		//変数flagに代入された戻り値が1のとき
				px++;			//プレイヤーは押し戻される
			break; //LEFT
		case KEY_RIGHT:
			flag = MoveBlock(); //MoveBlock()の戻り値を変数flagに代入
			if( flag == 0 )     //変数flagに代入された戻り値が0のとき
				px++;			//プレイヤー座標を更新
			if( flag == 1 )		//変数flagに代入された戻り値が1のとき
				px--;			//プレイヤーは押し戻される
			break;	//RIGHT
	}
}
また自分で試行錯誤してコードを書いていこうと思います。
皆様に感謝です。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: コンソールアプリケーションに関して - 通行不可の壁

#8

投稿記事 by softya(ソフト屋) » 14年前

今の方法だと通過不可地形に刺さるので仮に移動させて当たり判定をして、マップで当たったら移動を取り消したほうが良いと思います。

あと

コード:

    map[j][0] = py;
    map[0][i] = px;
はマップを書き換えているんで非常にマズイです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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