迷路でプレイヤーと壁との当たり判定をお聞きしたいのですが・・・

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

迷路でプレイヤーと壁との当たり判定をお聞きしたいのですが・・・

#1

投稿記事 by azurewing » 14年前

はじめまして。
はじめて質問させていただきます。
Wlibというライブラリを使いながらC言語でvisual studio 2005,または2008で作成しているのですが、
プレイヤーと壁との当たり判定が上手くいきません。
Wlibを使っているのは先頭にW.が入っているもの、これではプレイヤーと配列で並べた壁の描画、ならびにパッドの入力を得るのに使われています。
壁との当たり判定をプレイヤーの向いている方向とプレイヤーの座標より16ずらしたところ壁があるのかどうかで判定しています。
しかしプレイヤーの左と上方向を入力したときの当たり判定がおかしく壁にぶつかる前に止まってしまいます。
ソースを乗せるので何か気付いた方は意見などもらえるとうれしいです。

コード:

//ヘッダーの読み込み
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "WlibDL/wlib_dl.h"
#include "WlibDL/wlib_link.h"
#include "WlibDL/wlibDL_macro.h"

#define GAME_START 1

//全体の大きさ
#define MAX_X 640
#define MAX_Y 480
#define MIN_X 0
#define MIN_Y 0


//壁の最大量
#define MAP_X 40
#define MAP_Y 30
//壁の大きさ
#define WALL_X 16
#define WALL_Y 16
//壁のある、なし、ゴール
#define WALL_ON 1
#define WALL_OFF 0
#define WALL_GOAL 2
//プレイヤーの向き
#define PL_NOT 0
#define PL_UP 1
#define PL_LEFT 2
#define PL_DOWN 3
#define PL_RIGHT 4
//歩くフラグのON,OFF
#define WALK_ON 1
#define WALK_OFF 0


//主にプレイヤーの構造体
typedef struct{
	int x,y;
	int sw;
	int spd;
	int direction;
	int walking_flug;
}CONTROL;

//X:40
//Y:30
//マップの配列データ入力
int wall[ MAP_Y ][ MAP_X ] = {
	{ 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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 },
	{ 0,1,0,1,0,0,1,1,0,1,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,1,0 },
	{ 0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,1,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,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,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,1,0,1,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,1,0 },
	{ 0,1,0,1,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,1,0 },
	{ 0,1,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,1,0 },
	{ 0,1,0,1,0,0,0,0,0,0,0,0,0,1,1,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,1,0,1,1,1,1,1,1,1,1,0,0,0,1,1,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,1,0,1,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,1,0 },
	{ 0,1,0,1,0,1,1,0,1,0,1,0,0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 },
	{ 0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 },
	{ 0,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 },
	{ 0,1,0,1,0,0,1,1,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,0,0,0,0,1,0 },
	{ 0,1,0,1,1,0,0,1,0,1,1,1,1,1,0,1,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 },
	{ 0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 },
	{ 0,1,0,0,0,1,0,1,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,0,0,1,0 },
	{ 0,1,1,1,0,1,1,1,1,1,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,0,0,1,0 },
	{ 0,1,0,0,0,0,0,0,0,1,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,0,0,1,0 },
	{ 0,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 },
	{ 0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0 },
	{ 0,1,0,1,0,1,0,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0 },
	{ 0,1,0,1,0,0,0,1,1,0,1,0,1,1,0,0,0,0,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0 },
	{ 0,1,0,1,1,1,0,0,0,0,1,0,1,1,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0 },
	{ 0,1,0,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0 },
	{ 0,1,0,1,0,0,0,0,0,0,1,1,1,1,0,1,1,0,1,0,1,1,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0 },
	{ 0,1,0,1,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,1,0 },
	{ 0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,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 },
};

//壁に突き当たったか判定して止める関数////////////////////////////////////////////////////////////////////////////////
int IsAbleToGo( CONTROL player ){																					//
	//上向きの方向キーが入力された時																				//
	//壁が進行方向にある場合歩くフラグを0にする																	//
	if( player.direction == PL_UP  ){																				//
		if( wall[ ( player.y / WALL_Y ) - 1 ][ player.x / WALL_X ] == WALL_ON )										//
		return 1;																									//
	}																												//
	//左向きの方向キーが入力された時																				//
	//壁が進行方向にある場合歩くフラグを0にする																	//
	else if( player.direction == PL_LEFT ){																			//
		if( wall[ player.y / WALL_Y  ][ ( player.x / WALL_X ) - 1] == WALL_ON )										//
			return 1;																								//
	}																												//
	//下向きの方向キーが入力された時																				//
	//壁が進行方向にある場合歩くフラグを0にする																	//
	else if( player.direction == PL_DOWN  ){																		//
		if( wall[ ( player.y / WALL_Y ) + 1 ][ player.x / WALL_X ] == WALL_ON )										//
		return 1;																									//
	}																												//
	//右向きの方向キーが入力された時																				//
	//壁が進行方向にある場合歩くフラグを0にする																	//
	else if( player.direction == PL_RIGHT  ){																		//
		if( wall[ player.y / WALL_Y  ][ ( player.x / WALL_X ) + 1] == WALL_ON )										//
		return 1;																									//
	}																												//
	return 0;																										//
}																													//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
//ここからスタート
int main(void)
{
	//変数の宣言//////////////////
	int  i , j;					//		
	PAD pad;					//
	CONTROL player;				//
	int count = 0;				//
	//////////////////////////////
	 
	
	
//プレイヤーデータ初期化
//・プレイヤーのXY座標
//・プレイヤーの方向キーは入力なし(0)
//・プレイヤーの歩くフラグはOFF
//////////////////////////////////////////	
	//プレイヤー座標は16×16の左上	//
	player.x = MIN_X + 64;				//
	player.y = MAX_Y - 16;				//
	player.direction = PL_NOT;			//
	player.spd = 4;						//
	player.sw = 0;						//
	player.walking_flug = WALK_OFF;		//
	//////////////////////////////////////

	///////////////////////////////////////////本ループ開始/////////////////////////////////////////////////////////////////////
	while( GAME_START ){
		
		//PADデータを取得/////////////
		pad = W.GetPadData( 0 );	//
		//////////////////////////////
		//壁がある部分に描画//////////////////////////////////////////////////////////////////////////////////////////////////////
		for( i = 0; i < MAP_Y ; i++){																							//
			for( j = 0; j < MAP_X ; j++){																						//
				//壁が存在するときの処理																						//
				if( wall[ i ][ j ] == WALL_ON){																					//
					//壁描画																									//
					W.DrawLine( j * WALL_X , i * WALL_Y ,( j + 1 ) * WALL_X,( i + 1 ) * WALL_Y, RGBto( 255,255,255 ), DW_FILL );//
				}																												//
					//ゴールポイントを描画																						//
				if( wall[ i ][ j ] == 2){																						//
					W.DrawLine( j * WALL_X , i * WALL_Y ,( j + 1 ) * WALL_X,( i + 1 ) * WALL_Y, RGBto( 255,0,0 ), DW_FILL );	//
				}																												//
			}																													//
		}																														//
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		//進む方向入力////////////////////////////////////////////////////
		//プレイヤーの座標と壁の大きさを割った余りがないとき			//
		if( !( player.x % WALL_X ) && !( player.y % WALL_Y ) )			//
		{																//
			//歩くフラグを立てる										//
			player.walking_flug = WALK_ON;								//
				//上の方向キーが入力された時							//
				if( pad.press & PAD_UP )								//
					//上向きフラグを立てる								//
					player.direction = PL_UP;							//
				//左の方向キーが入力された時							//
				if( pad.press & PAD_LEFT )								//
					//左向きフラグを立てる								//
					player.direction = PL_LEFT;							//
				//下の方向キーが入力された時							//
				if( pad.press & PAD_DOWN )								//
					//下向きフラグを立てる								//
					player.direction = PL_DOWN;							//
				//右の方向キーが入力された時							//
				if( pad.press & PAD_RIGHT )								//
					//右向きフラグを立てる								//
					player.direction = PL_RIGHT;						//
		}																//
		//////////////////////////////////////////////////////////////////
		
		//壁に当たっているか判定//////////////////////
		if( player.walking_flug == WALK_ON ){		//
			if( IsAbleToGo( player ) )				//
				player.walking_flug = WALK_OFF;		//
		}											//
		//////////////////////////////////////////////
		
		
		//それぞれの方向のスピード調整////////////////////////////////////////////////////////////////
		//プレイヤーの歩くフラグが立っている時														//	
		if( player.walking_flug == WALK_ON){														//
			//上へ移動																				//
			if( player.direction == PL_UP && !( player.y == MIN_Y )){								//
				player.y -= player.spd;																//
			}																						//
			//左へ移動																				//
			if( player.direction == PL_LEFT && !( player.x == MIN_X )){								//
				player.x -= player.spd;																//
			}																						//
			//下へ移動																				//
			if( player.direction == PL_DOWN && !( player.y + 16 == MAX_Y )){						//
				player.y += player.spd;																//
			}																						//
			//右へ移動																				//
			if( player.direction == PL_RIGHT && !(player.x + 16 == MAX_X)){							//
				player.x += player.spd;																//
			}																						//
		}																							//
//		else																						//
//			player.walking_flug = WALK_OFF;															//
		//////////////////////////////////////////////////////////////////////////////////////////////
		
		
		//プレイヤーを描く																			//
		W.DrawLine( player.x,player.y, player.x + 16, player.y + 16, RGBto( 0,255,255), DW_FILL );	//
																	
		
		
		W.RefreshScreen(0);
		W.Clear(0);
		DebPutHex(  player.x	, 420 , 240 ) ;
		DebPutHex(  player.walking_flug	, 400 , 250 ) ;
		
		count++;
	}
	
	return 0;
}

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

Re: 迷路でプレイヤーと壁との当たり判定をお聞きしたいのですが・・・

#2

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

上と左に移動するとき15ドットの隙間があっても移動できなくなります。
if( wall[ ( player.y / WALL_Y ) - 1 ][ player.x / WALL_X ] == WALL_ON )
if( wall[ player.y / WALL_Y ][ ( player.x / WALL_X ) - 1] == WALL_ON )
この条件が原因ですが、なぜなのかは実際に計算してみてください。
例えば(0,0)に壁がありキャラが(0,32)から上に移動しようとすると(0,28)で止まるはずです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

azuewing

Re: 迷路でプレイヤーと壁との当たり判定をお聞きしたいのですが・・・

#3

投稿記事 by azuewing » 14年前

プレイヤーの座標をwallに代入して16で割って配列の値にすると・・・・・・
上に壁があった場合で判定してしまったとき、プレイヤーを代入した配列のすぐ上で止まるためのフラグが立ち、
移動量分移動してすぐに止まってしまう、ということなのでしょうか?

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

Re: 迷路でプレイヤーと壁との当たり判定をお聞きしたいのですが・・・

#4

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

そうですね。
if( wall[ ( player.y / WALL_Y ) - 1 ][ player.x / WALL_X ] == WALL_ON )
だと(0,28)の座標の場合
wall[(28/16)-1][0/16]
ですので
wall[0][0]
と言う事になります。

この方法だとダメなので
if( wall[ (player.y-player.spd) / WALL_Y ][ player.x / WALL_X ] == WALL_ON )
じゃないでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

azurewing

Re: 迷路でプレイヤーと壁との当たり判定をお聞きしたいのですが・・・

#5

投稿記事 by azurewing » 14年前

移動するたび判定をくり返すようするんですね。
理解しました。
ありがとうございました!

閉鎖

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