アクションゲームの当たり判定について

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

アクションゲームの当たり判定について

#1

投稿記事 by Bone » 5年前

アクションゲームにて、当たり判定を作っているのですがどうもうまくいきません
使っている画像の大きさが144*96のサイズなので、横に56移動させた位置から、32*32の当たり判定を3つ縦に並べて作っています。
またmove[]は0が上でそこから時計回りに3までのフラグになっており
coll_pos[]は、左上から時計回りに、位置を設定しています。
実行した場合、振動しているような状態になります。
また、あたいがずれる点があり、それは重力を画像の座標へ代入するときで、前後でprintfをとり確認しました
これを改善する場合どうすべきでしょうか?
c++とcはある程度できるようにはなりましたが、深くまではまだ理解していません。
関連があるとおもわれるコードを乗せます。
回答よろしくお願いします。
不備、状況がわからない等ございましたら、申し訳有りません。

コード:

//Collision.cpp
#include "AP_Collision.h"
Collision::Collision(){

}

void Collision::Bottom_Collision(Player &player,Maps &maps){
	//当たり判定位置生成
	for(int i = 0;i < 6; i++) coll_pos[i] = player.Point_Coll(i);
	player_pos = player.Point_Player();
	if(maps.checkObjct(coll_pos[3].x,coll_pos[3].y+32) == 1 || maps.checkObjct(coll_pos[4].x,coll_pos[4].y+32) == 1){
		player_pos.y = player_pos.y/32*32;
		player.MoveFlagsSet(false,2);
		player.SetFloatFlag(false);
	}else{
		player.MoveFlagsSet(true,2);
		player.SetFloatFlag(false);
	}
	player.PlayerPointSet(player_pos.x,player_pos.y);
}

コード:

#include "AP_Chara.h"
#include "stdio.h"

Player::Player(){
	//初期位置
	player_pos.x = 0;
	player_pos.y = 0;

	//初期あたり判定位置
	LColl_head.x = LColl_center.x = LColl_bottom.x = player_pos.x+56;
	LColl_head.y = RColl_head.y = player_pos.y;
	LColl_center.y = RColl_center.y = player_pos.y+32;
	LColl_bottom.y = RColl_bottom.y = player_pos.y+64;
	RColl_head.x = RColl_center.x = RColl_bottom.x = LColl_head.x+31;

	//グラフィック
	
	LoadDivGraph("Fighter_1.png",16,4,4,144,96,image) ;
	LoadDivGraph("Atack.png",16,4,4,144,96,Atack_image);

	//カウンタ初期化
	gravity_count=0;
	cnt=0;
	index=0;
	Atack_Part=0;

	//初期記憶
	for(int i=0;i<9;i++){
		px[i]=py[i]=-1;
	}

	//初期HP値
	hp=3;
	g=2;
	py[0]=player_pos.y;

	//機能変数初期値
	direct=true;
	jump=false;
	floating=false;
	move_flag=true;
	dead=false;
	gravity=true;

	for(int i=0; i < 4; i++){
		move[i] = true;
	}

}

void Player::draw(){
	//円の描画
	if(direct){
		if(gravity){
			if(Key[KEY_INPUT_LEFT]>0||Key[KEY_INPUT_RIGHT]>0)
				DrawTurnGraph(player_pos.x,player_pos.y,image[8+index],TRUE);
			if(Key[KEY_INPUT_LEFT]==0&&Key[KEY_INPUT_RIGHT]==0)
				DrawTurnGraph(player_pos.x,player_pos.y,image[index],TRUE);

		}else{
			if(Key[KEY_INPUT_LEFT]>0||Key[KEY_INPUT_RIGHT]>0)
				DrawRotaGraph(player_pos.x+72,player_pos.y+48,1.0,PI,image[8+index],TRUE,FALSE);
			if(Key[KEY_INPUT_LEFT]==0&&Key[KEY_INPUT_RIGHT]==0)
				DrawRotaGraph(player_pos.x+72,player_pos.y+48,1.0,PI,image[index],TRUE,FALSE);
		}

	}else{
		if(gravity){
			if(Key[KEY_INPUT_LEFT]>0||Key[KEY_INPUT_RIGHT]>0)
				DrawGraph(player_pos.x,player_pos.y,image[8+index],TRUE);
			if(Key[KEY_INPUT_LEFT]==0&&Key[KEY_INPUT_RIGHT]==0)
				DrawGraph(player_pos.x,player_pos.y,image[index],TRUE);

		}else{
			if(Key[KEY_INPUT_LEFT]>0||Key[KEY_INPUT_RIGHT]>0)
				DrawRotaGraph(player_pos.x+72,player_pos.y+48,1.0,PI,image[8+index],TRUE,TRUE);
			if(Key[KEY_INPUT_LEFT]==0&&Key[KEY_INPUT_RIGHT]==0)
				DrawRotaGraph(player_pos.x+72,player_pos.y+48,1.0,PI,image[index],TRUE,TRUE);

		}
	}

	DrawFormatString(10,10,GetColor(255,255,255),"x:%d,y:%d",player_pos.x,player_pos.y);
	DrawFormatString(10,25,GetColor(255,255,255),"HP:%d",hp);
	DrawFormatString(10,40,GetColor(255,255,255),"gravity:%d",gravity);
}

//操作関数
void Player::KeyInputFunc(){

	//移動
	if(Key[KEY_INPUT_LEFT]>0){
		if(move[3]) player_pos.x-=4;
		direct=false;
	}

	//移動
	if(Key[KEY_INPUT_RIGHT]>0){
		if(move[1]) player_pos.x+=4;
		direct=true;
	}

	//重力転換
	if(Key[KEY_INPUT_G]){
		if(gravity){
			if(gravity_count <= 0){
				gravity_count = 30;
				gravity=false;
			}
		}else{
			if(gravity_count <= 0){
				gravity_count = 30;
				gravity=true;
			}
		}
	}

	//ジャンプ
	if(Key[KEY_INPUT_SPACE]==1&&!floating){
		if(gravity){
			g=-15;
			floating = true;
		}else{
			g=15;
			floating = true;
		}
	}

	//インデックス
	if(Key[KEY_INPUT_LEFT]>0||Key[KEY_INPUT_RIGHT]>0){
		// ダッシュ時
		if(cnt%10==1){
			if(index == 3){ index  = 0;
			}else{          index += 1; }
		}
	}else{
		// 待機時
		if(cnt%15==1){
			if(index == 3){ index  = 0;
			}else{          index += 1; }
		}
	}
}


//マップ変更関数
void Player::AreaJump(int area,int px,int py){
	player_pos.x=px;
	player_pos.y=py;
}




//重力
void Player::Gravty_Updata(){
	//重力設定
	y_move=(player_pos.y-py[0])+g;

	//移動量制限
	if(y_move>31&&gravity){
		y_move=31;
	}else if(y_move<-31&&!gravity){
		y_move=-31;
	}

	//前回座標を記憶
	py[0]=player_pos.y; //ここで位置がずれる

	//反映
		player_pos.y+=y_move;		/*ここで値がずれる*/
	//gを戻す
	if(gravity){
		g=1;
	}else{
		g=-1;
	}

}



//フレーム更新
void Player::update(){
	Gravty_Updata();
	cnt+=1;
	gravity_count -= 1;
	//重力
	Gravty_Updata();
	//操作関数
	KeyInputFunc();
	PrintData();

	LColl_head.x = LColl_center.x = LColl_bottom.x = player_pos.x+56;
	LColl_head.y = RColl_head.y = player_pos.y;
	LColl_center.y = RColl_center.y = player_pos.y+32;
	LColl_bottom.y = RColl_bottom.y = player_pos.y+64;
	RColl_head.x = RColl_center.x = RColl_bottom.x = LColl_head.x+31;
}

bool Player::Gravity(){
	return gravity;
}

t_Pos Player::Point_Player(){
	return player_pos;
}

t_Pos Player::Point_Coll(int num){
	switch(num){
	case 0:
		return LColl_head;
		break;
	case 1:
		return RColl_head;
		break;
	case 2:
		return RColl_center;
		break;
	case 3:
		return RColl_bottom;
		break;
	case 4:
		return LColl_bottom;
		break;
	case 5:
		return LColl_center;
		break;
	}
	ErrorMesBox("エラーが発生しました(Chara.cpp/229行目)",END);
	return RColl_head;
}

void Player::PlayerPointSet(int x,int y){
	player_pos.x = x;
	player_pos.y = y;
}

void Player::MoveFlagsSet(bool flags,int num){
	if(num<4) move[num] = flags;
	return ;
}

void Player::SetFloatFlag(bool flag){
	floating = flag;
}

void Player::PrintData(){
	printf("-------------------------------------------------------\n");
	printf("x:%d y:%d\nGravity:%d direct:%d\n",player_pos.x,player_pos.y,gravity,direct);
	printf("MoveFlag [0] = %d,[1] = %d,[2] = %d,[3] = %d",move[0],move[1],move[2],move[3]);
}

コード:

#include "AP_Maps.h"

Maps::Maps(){
	for(int i=0;i<14;i++){
		for(int j=0;j<20;j++){
			maps[i][j]=0;
		}
	}
	for(int j=0;j<20;j++){
		maps[14][j]=1;
		maps[0][j]=2;
	}
	for(int i=0;i<14;i++){
		maps[i][ 0]=1;
		maps[i][19]=1;
	}
		LoadDivGraph("map.png",152,8,19,32,32,chips) ;
}
int Maps::checkPos_x(int mx){
	return mx/32;
}

int Maps::checkPos_y(int my){
	return my/32;
}

int Maps::checkObjct(int mx,int my){
	return maps[checkPos_y(my)][checkPos_x(mx)];
}

void Maps::draw(){
	for(int i=0;i<15;i++){
		for(int j=0;j<20;j++){
			if(maps[i][j]==1){
				DrawGraph(j*32,i*32,chips[9],TRUE);
			}else if(maps[i][j]==2){
				DrawRotaGraph(j*32+16,i*32+16,1.0,PI,chips[9],TRUE,FALSE);
			}
		}
	}
}

Bone

Re: アクションゲームの当たり判定について

#2

投稿記事 by Bone » 5年前

書き忘れが有りました
使用している言語はC++と一部Cです。
追加ライブラリとして、DXLibを使っています。

アバター
Tatu
記事: 440
登録日時: 8年前
住所: 北海道

Re: アクションゲームの当たり判定について

#3

投稿記事 by Tatu » 5年前

y_moveはプレイヤーのy方向の移動速度だと思いますが
プレイヤーの今の座標と前の座標の差から求めている理由は何でしょうか。
地面についた時、プレイヤーと地面の当たり判定でy_moveが0になったとしても
この計算で0でなくなってしまうのではないでしょうか。

Bone

Re: アクションゲームの当たり判定について

#4

投稿記事 by Bone » 5年前

Tatu さんが書きました:y_moveはプレイヤーのy方向の移動速度だと思いますが
プレイヤーの今の座標と前の座標の差から求めている理由は何でしょうか。
地面についた時、プレイヤーと地面の当たり判定でy_moveが0になったとしても
この計算で0でなくなってしまうのではないでしょうか。
+gをすることで、差を大きくして行き、重力加速を実現しようとしています
簡易アクション当たり判定の講座をみて、書かれてた言語からC++へ移行して見ました。

先ほど自分で一つ解決したものとして、GravtyUpdataが2つあったがために、座標が振動していました。
しかし、一つ消しましたが、当たり判定でy座標がずれてしまいます。
Takuさんの言ってる、その0にならない値が反映されて1ずれている模様ですが、その講座ではずれていません。(自分でじっこうしてもそうなりました。)

アバター
Tatu
記事: 440
登録日時: 8年前
住所: 北海道

Re: アクションゲームの当たり判定について

#5

投稿記事 by Tatu » 5年前

>簡易アクション当たり判定の講座
もし、この講座がWeb上のものでしたらURLを教えてくれませんか?

Bone

Re: アクションゲームの当たり判定について

#6

投稿記事 by Bone » 5年前

Tatu さんが書きました:>簡易アクション当たり判定の講座
もし、この講座がWeb上のものでしたらURLを教えてくれませんか?
こちらのサイトになります
http://d.hatena.ne.jp/t_tutiya/touch/20 ... 1386774368

アバター
Tatu
記事: 440
登録日時: 8年前
住所: 北海道

Re: アクションゲームの当たり判定について

#7

投稿記事 by Tatu » 5年前

その講座では

コード:

#床衝突判定
  if collision_tile(x   , y+31, @map) == 1 or 
     collision_tile(x+31, y+31, @map) == 1
    y = y/32*32
    jump_ok = true #地面に接地しているのでジャンプを許可する
  else
    jump_ok = false #地面に接地していないので、ジャンプは許可しない
  end
と書かれていますね。

当たり判定の部分を

コード:

if(maps.checkObjct(coll_pos[3].x,coll_pos[3].y+31) == 1 || maps.checkObjct(coll_pos[4].x,coll_pos[4].y+31) == 1){
とした場合はどうなりますか?



あと、移動と判定と描画の順序はどうなっていますか?

アバター
Tatu
記事: 440
登録日時: 8年前
住所: 北海道

Re: アクションゲームの当たり判定について

#8

投稿記事 by Tatu » 5年前

このような処理を考えます。
move_yの計算式はy-prev_y+f
prev_yにyを代入
yにmove_yを足す
地面の当たり判定としてy>0ならばy=0に変更する
描画

prev_y=-8,y=-8,f=2から開始した場合、どうなるでしょうか。

move_yを計算。move_y=2
prev_y,yを更新。prev_y=-8,y=-6
y=-6でy>0じゃないのでy=-6のまま
描画y=-6

move_yを計算。move_y=4
prev_y,yを更新。prev_y=-6,y=-2
y=-2でy>0じゃないのでy=-2のまま
描画y=-2

move_yを計算。move_y=6
prev_y,yを更新。prev_y=-2,y=4
y=4でy>0なのでy=0
描画y=0

move_yを計算。move_y=4
prev_y,yを更新。prev_y=0,y=4
y=4でy>0なのでy=0
描画y=0

move_yを計算。move_y=2
prev_y,yを更新。 prev_y=0,y=2
y=2でy>0なのでy=0
描画y=0

以下繰り返し。
この場合、move_yは0にはなりませんがyは0のままです。

Bone

Re: アクションゲームの当たり判定について

#9

投稿記事 by Bone » 5年前

Tatu さんが書きました:その講座では

コード:

#床衝突判定
  if collision_tile(x   , y+31, @map) == 1 or 
     collision_tile(x+31, y+31, @map) == 1
    y = y/32*32
    jump_ok = true #地面に接地しているのでジャンプを許可する
  else
    jump_ok = false #地面に接地していないので、ジャンプは許可しない
  end
と書かれていますね。

当たり判定の部分を

コード:

if(maps.checkObjct(coll_pos[3].x,coll_pos[3].y+31) == 1 || maps.checkObjct(coll_pos[4].x,coll_pos[4].y+31) == 1){
とした場合はどうなりますか?



あと、移動と判定と描画の順序はどうなっていますか?
すみません、先ほど改善した際に31に直しまして、その場合において1ずれました
順序は
判定→移動→描画です

アバター
Tatu
記事: 440
登録日時: 8年前
住所: 北海道

Re: アクションゲームの当たり判定について

#10

投稿記事 by Tatu » 5年前

では、元の講座ではどういう順番になっていますか?

Bone

Re: アクションゲームの当たり判定について

#11

投稿記事 by Bone » 5年前

Tatu さんが書きました:では、元の講座ではどういう順番になっていますか?
移動→判定→移動→判定となってます
ということは、処理順序のミスによってズレが生じているという解釈で大丈夫でしょうか?
つまりは、判定を先にしてしまっていることによって位置補正後にy+=y_moveが反映されるため、重力分だけたされてずれてしまっている
ということでしょうか?

アバター
Tatu
記事: 440
登録日時: 8年前
住所: 北海道

Re: アクションゲームの当たり判定について

#12

投稿記事 by Tatu » 5年前

そういうことですね。

Bone

Re: アクションゲームの当たり判定について

#13

投稿記事 by Bone » 5年前

Tatu さんが書きました:そういうことですね。
ありがとうございました!
現在、データが手元にないため、変更させてもらい、確認してから解決にさせていただきます!
Tatuさん、時間を割いて答えていただきありがとうございました!

Bone

Re: アクションゲームの当たり判定について

#14

投稿記事 by Bone » 5年前

帰宅したので、早速、変更してみたのですが、やはり1ずれているみたいです。
というのも、当たり判定とプレイヤー操作、描画の実行がControlというクラスで管轄しています。

コード:

#include "Control.h"

All_Control::All_Control(){
}

void All_Control::All_Updata(){
	apUpdateKeyBoard();
	player.update();
	collision.Bottom_Collision(player,maps);
	
}

void All_Control::All_Draw(){
	maps.draw();
	player.draw();
	
}
変更した場所は、

コード:

	apUpdateKeyBoard();
	collision.Bottom_Collision(player,maps);
  player.update();
から

コード:

	apUpdateKeyBoard();
	player.update();
	collision.Bottom_Collision(player,maps);
に変更しました
しかしながら、y座標はずれているようで・・・
確認のため

コード:

	printf("y:%d\n",player_pos.y);
	player_pos.y+=y_move;		/*ここで値がずれる*/
	printf("y:%d\n",player_pos.y);
と処理を書き、コンソールにて値を確認しましたが、やはり1ずれていました。
未熟なため、本当にわからなくなってきました。
もしよければ、引き続きお願い申し上げます。

アバター
Tatu
記事: 440
登録日時: 8年前
住所: 北海道

Re: アクションゲームの当たり判定について

#15

投稿記事 by Tatu » 5年前

player::drawを呼び出す時のplayer.pos_yの値はどうなのでしょうか?

player::PrintDataを呼び出す時のplayer.pos_yは
当たり判定を行う前の値なのでずれているはずです。

Bone

Re: アクションゲームの当たり判定について

#16

投稿記事 by Bone » 5年前

Tatu さんが書きました:player::drawを呼び出す時のplayer.pos_yの値はどうなのでしょうか?

player::PrintDataを呼び出す時のplayer.pos_yは
当たり判定を行う前の値なのでずれているはずです。
確認しました。
どうやらここはずれていないようで、調べてみると、coll_pos[].yがすべてずれているようです。
このあたり判定がplayer_pos依存かつ、コンストラクタ時、また、Player.updataの重力計算後に反映してるためずれているとわかりまして、新しく

コード:

void Player::reSetPosCollPoint(){
	LColl_head.x = LColl_center.x = LColl_bottom.x = player_pos.x+55;
	LColl_head.y = RColl_head.y = player_pos.y;
	LColl_center.y = RColl_center.y = player_pos.y+32;
	LColl_bottom.y = RColl_bottom.y = player_pos.y+64;
	RColl_head.x = RColl_center.x = RColl_bottom.x = LColl_head.x+31;
}
を追記しました
そして、当たり判定時に、

コード:

if(maps.checkObjct(coll_pos[3].x,coll_pos[3].y+31) == 1 || maps.checkObjct(coll_pos[4].x,coll_pos[4].y+31) == 1){
		player_pos.y=player_pos.y/32*32;
		player.PlayerPointSet(player_pos.x,player_pos.y); /*実際の値に反映*/
		player.reSetPosCollPoint(); /*当たり判定を再生成*/
		for(int i = 0;i < 6; i++) coll_pos[i] = player.Point_Coll(i); /*当たり判定を再習得*/
		player.MoveFlagsSet(false,2);
		player.SetFloatFlag(false);
	}else{
こうすることで正常に動かすことが出来ました。
もっと、スマートに出来るのでしょうけど、もっと成長してから、良い方法を考えようとおもいます。
このたびはほんとありがとうございました。
今後も質問させていただくかもしれませんが、そのときはよろしくお願いします!

閉鎖

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