キャラが壁にハマってしまう

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
keito940
記事: 105
登録日時: 7年前

キャラが壁にハマってしまう

#1

投稿記事 by keito940 » 7年前

前回、ジャンプがうまくいかない件で質問したものです。今度は壁にぶつかると壁にハマって、動けなくなってしまいます。どうやら、(自分では実装したつもりなのですが)左右の衝突判定がうまく実装されていないことに原因にあるようです。コードは以下のとおりです。(画像は自分で用意してくださいね)
ちなみに、前回での質問における2ドット浮くという現象は解決済みです。また、地上の衝突判定自体は完成しています。

コード:

#include "dxlib.h"
#define SCREEN_WIDTH (320)
#define SCREEN_HEIGHT (240)
#define STAGE_WIDTH (320)
#define STAGE_HEIGHT (240)
#define CHIP_SIZE (16)
#define MAP_WIDTH (STAGE_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (STAGE_HEIGHT/CHIP_SIZE)

float PlayerX = 24.0F, PlayerY = 215.0F, DropPower = 0.0F, Gravity;
char dir, JumpFlag, DashFlag, AirFlag, DashTrigger, HitFlagX, HitFlagY;
int GetChipParam(float X, float Y);
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY);
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY);
int PlayerHandle, MapChipHandle[2], JumpCount, Time, Input, EdgeInput, charX, charY, cameraX = 0, cameraY = 0, viewx, viewy;
int Key[256];
int gpUpdateKey() {
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++) {
		if (tmpKey[i] != 0) {
			Key[i]++;
		}
		else {
			Key[i] = 0;
		}
	}
	return 0;
}
char MapData[MAP_HEIGHT][MAP_WIDTH] =
{
	0,0,0,0,0, 0,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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
};

//マップチップ確認
int GetChipParam(float X, float Y)
{
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;

	return MapData[y][x];
}
//マップの当たり判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (GetChipParam(X, Y) == 1) {
		float blx, bty, brx, bby;
		//壁衝突確認
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;//左辺の当たり判定
		brx = (float)((int)afX / CHIP_SIZE + 1)*CHIP_SIZE;//右辺の当たり判定

		bty = (float)((int)afY / CHIP_SIZE)*CHIP_SIZE;//上辺の当たり判定
		bby = (float)((int)afY / CHIP_SIZE + 1)*CHIP_SIZE;//下辺の当たり判定
		//上辺に当たったら3を返す
		if (*MoveY > 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bty - Y - 1.0F;
			return 3;
		}
		//下辺に当たっていたら4を返す
		if (*MoveY < 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bby - Y + 1.0F;
			return 4;
		}
		if (*MoveX > 0.0F) {
			*MoveY = 0.0F;
			*MoveX = blx - X - 1.0F;
			return 1;
		}
		if (*MoveX < 0.0F) {
			*MoveY = 0.0F;
			*MoveX = brx - X + 1.0F;
			return 2;
		}
		return 4;
	}
	return 0;
}
//当たり判定チェック
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY) {
	float Dummy = 0.0F;
	float hsize;
	hsize = Size*0.5F;
	//上下移動成分をチェック
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F; *HitFlagY = TRUE;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F; *HitFlagY = TRUE;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//問題がないのなら移動成分を加算する
		*Y += MoveY;
	}
	//左右移動成分、以下同順
	{
		if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1) *HitFlagX = TRUE;
		if (MapHitCheck(*X + hsize, *Y + hsize, &MoveX, &Dummy) == 2) *HitFlagX = TRUE;
		if (MapHitCheck(*X - hsize, *Y - hsize, &MoveX, &Dummy) == 1) *HitFlagX = TRUE;
		if (MapHitCheck(*X + hsize, *Y - hsize, &MoveX, &Dummy) == 2) *HitFlagX = TRUE;
		*X += MoveX;
	}
	//ヒットフラグが付いたら、壁にハマるのを防止してからフラグをオフにする。
	if (*HitFlagX == TRUE) {
		//左の場合
		if (MoveX<0 && MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1 && MapHitCheck(*X - hsize, *Y - hsize, &MoveX, &Dummy) == 1) {
			*X += 1.0F;
			HitFlagX = FALSE;
		}
		//右の場合
		else if (MoveX>0 && MapHitCheck(*X + hsize, *Y - hsize, &MoveX, &Dummy) == 2 && MapHitCheck(*X + hsize, *Y + hsize, &MoveX, &Dummy) == 2) {
			*X -= 1.0F;
			HitFlagX = FALSE;
		}
	}
	{
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F + 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F + 1.0F) == 0) {
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else if (*HitFlagY = TRUE) {
			*Y -= 1.0F;
			*HitFlagY = FALSE;
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}
int DrawChar() {
	if (dir == TRUE) {
		DrawRotaGraph((int)PlayerX, (int)PlayerY + 2, 1.0, 0.0, PlayerHandle, TRUE, FALSE);
	}
	else {
		DrawRotaGraph((int)PlayerX, (int)PlayerY + 2, 1.0, 0, PlayerHandle, TRUE, TRUE);
	}
	return 0;
}
//マップの描画
int DrawMap() {
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
					DrawGraph(j * CHIP_SIZE, i*CHIP_SIZE, MapChipHandle[1], TRUE);
				}
			}
		}
	} return 0;
}
//カメラの確認
int CameraCheck() {
	//プレイヤーの位置チェック
	charX = (int)PlayerX, charY = (int)PlayerY;
	//カメラの位置チェック
	cameraX = charX - SCREEN_WIDTH / 2, cameraY = charY - SCREEN_WIDTH / 2;
	//横のカメラを動かす
	if (cameraX < 0)cameraX = 0;
	if (cameraX >(STAGE_WIDTH - SCREEN_WIDTH))cameraX = (STAGE_WIDTH - SCREEN_WIDTH);
	//縦のカメラを動かす
	if (cameraY < 0) cameraY = 0;
	if (cameraY >(STAGE_HEIGHT - SCREEN_HEIGHT))cameraY = (STAGE_HEIGHT - SCREEN_HEIGHT);
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE), SetGraphMode(320, 240, 32);
	if (DxLib_Init() == -1) { return -1; };
	SetDrawScreen(DX_SCREEN_BACK), Input = 0, Time = GetNowCount();//カウント値を更新する
	PlayerHandle = LoadGraph("テスト用.png"), LoadDivGraph("マップチップ.bmp", 2, 2, 1, 16, 16, MapChipHandle);
	dir = TRUE, DashFlag = FALSE, HitFlagX = TRUE, HitFlagY = FALSE;
	return 0;
}
int main(void) {
	//マップの描画
	DrawMap();
	//カウント値を更新する
	Time = GetNowCount();
	//フレームを管理する
	while (GetNowCount() - Time < 1000 / 60) { Sleep(1); }
	//入力状態を更新する
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		//チョン押しを確認する
		EdgeInput = i & ~Input;
		Input = i;
	}
	//ダッシュトリガー確認
	if ((Input&PAD_INPUT_1) == 0) {
		DashFlag = FALSE;
	}
	if (JumpCount >= 2) {
		JumpFlag = TRUE;
	}
	//移動処理
	{
		float MoveX, MoveY;
		MoveX = 0.0F;
		MoveY = 0.0F;
		//左に移動
		if ((Input&PAD_INPUT_LEFT) != 0) {
			dir = FALSE;
			MoveX -= 5.0F;
		}
		//右に移動
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			dir = TRUE;
			MoveX += 5.0F;
		}
		//左ラン
		if ((Input&PAD_INPUT_LEFT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = FALSE;
			DashFlag = TRUE;
			MoveX -= 5.25F;
		}
			//右ラン
		if ((Input&PAD_INPUT_RIGHT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = TRUE;
			DashFlag = TRUE;
			MoveX += 5.25F;
		}
		//ダッシュボタン
		if ((EdgeInput&PAD_INPUT_3) != 0) {
			int DashTimer = GetNowCount();

		}
		//ジャンプ処理
		if ((EdgeInput&PAD_INPUT_2) != 0 && JumpFlag == FALSE) {
			//ジャンプできる状態にする
			DropPower = 0;
			//ジャンプ回数を増やす
			JumpCount += 1;
			//ジャンプする
			DropPower -= 9.5F;
			//ジャンプするときの重力を決める
			Gravity = 0.5F;
		}
		if ((EdgeInput&PAD_INPUT_2) != 0 && DashFlag == TRUE && JumpFlag == FALSE) {
			DashFlag = TRUE;
			DropPower = 0;
			JumpCount += 1;
			DropPower -= 12.0F;
			Gravity = 0.5F;
		}
		//カメラのチェック
		CameraCheck();
		//落下処理
		DropPower += Gravity;
		//落下速度を移動量に追加する
		MoveY = DropPower;
		//当たり判定に基づく移動を行う
		MoveChecker(&PlayerX, &PlayerY, &DropPower, MoveX, MoveY, CHIP_SIZE, &JumpFlag, &AirFlag, &HitFlagX, &HitFlagY);
	}
	DrawChar();
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	init();//初期化処理
        //メインプログラム
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
		main();
	}
	//DXライブラリを終了する
	DxLib_End();
	return 0;
}
最後に編集したユーザー keito940 on 2017年1月30日(月) 19:44 [ 編集 8 回目 ]

Math

Re: キャラが壁にハマってしまう

#2

投稿記事 by Math » 7年前

プログラムが整理されてなくて分からない。問題点を絞って半分以下にしないと他人には理解不能だしコメントがすくなすぎます。作った自分がわからなくなっているのだから参考にしたサイトを提示して下さい。(2つが混ざっている様なきがする)

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#3

投稿記事 by keito940 » 7年前

Math さんが書きました:プログラムが整理されてなくて分からない。問題点を絞って半分以下にしないと他人には理解不能だしコメントがすくなすぎます。
自分で整理整頓したつもりなのですが…。やっぱ整理されてなかったんですか…。
Math さんが書きました:作った自分がわからなくなっているのだから参考にしたサイトを提示して下さい。(2つが混ざっている様なきがする)
http://hsp.tv/play/pforum.php?mode=all&num=58323
http://freestyle.nvo.jp/archives/1121
この2つだと思います。
追記:NO1のコメントを多くしてみました。

Math

Re: キャラが壁にハマってしまう

#4

投稿記事 by Math » 7年前

HSP3.4のProgramはWindows10のファイル管理に使っています。jQuery(JavaScript)(HTML5とともに)はこれからスマホ系のVS2015の主力になると思うのですが。(ホームページも自分はVSで作っています。)これからはVSもxaml等HTML系の言語が中心になるでしょう。でもC言語のロジックを追うのには向いてない気がします。C言語のソースを単純にしてみましょう。
http://csi.nisinippon.com/hsp.png

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#5

投稿記事 by keito940 » 7年前

これでも単純にしたつもりなんですけどね…。やっぱり僕のコードは難しいですか…。
とにかく、めり込み防止のアルゴリズムは以下のとおりです。どうすれば僕の想定した動作になるのかを教えて下さい。

コード:

{
             if(壁にヒットしたら) 衝突フラグをオンにする
}
if(衝突フラグがオンで){
             if(左に移動していたら){
                          めり込み防止のために右に返してから
                          衝突フラグをオフにする
             }
              else if(右に移動していたら){
        めり込み防止のために左に返してから
        衝突フラグをオフにする
               }

Math

Re: キャラが壁にハマってしまう

#6

投稿記事 by Math » 7年前

ゆっくりバグを作らないようにやってるのだけどコメントがないと何をやってるのか考えないと。全体にプログラムと同じくらいコメントがないと見ただけけでわからないですよ

コード:

///-----------------------------------------------------------------------
//2017/01/31
///----------------------------------------------------------------------- [#include]
#include "dxlib.h"
///----------------------------------------------------------------------- [#define]
#define SCREEN_WIDTH (320)        //--幅
#define SCREEN_HEIGHT (240)      //---高
#define STAGE_WIDTH (320)       //--ステージ幅
#define STAGE_HEIGHT (240)     //---ステージ幅
#define CHIP_SIZE (16)                        //--CHIP幅
#define MAP_WIDTH (STAGE_WIDTH/CHIP_SIZE)    //---MAP幅
#define MAP_HEIGHT (STAGE_HEIGHT/CHIP_SIZE) //----MAP高
///----------------------------------------------------------------------- [変数宣言]
float PlayerX = 24.0F, PlayerY = 215.0F, DropPower = 0.0F, Gravity;
char dir, JumpFlag, DashFlag, AirFlag, DashTrigger, HitFlagX, HitFlagY; int Key[256];
char MapData[MAP_HEIGHT][MAP_WIDTH] =/////////////////////////////////////
{
    0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,//MapData[][]の初期化
    1,0,0,0,0, 0,0,0,0,0, 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,1,
    1,0,0,0,0, 0,0,0,0,0, 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,1,
 
    1,0,0,0,0, 0,0,0,0,0, 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,1,
    1,0,0,0,0, 0,0,0,0,0, 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,1,
    1,0,0,0,0, 0,0,0,0,0, 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,1,
    1,0,0,0,0, 0,0,0,0,0, 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,1,
    1,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,
};////////////////////////////////////////////////////////////////////////////
///--------------------------------------------------------------------------- [関数プロトタイプ]
int GetChipParam(float X, float Y);////////////////////////////////////////////
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY);
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY);/////////////////
int PlayerHandle, MapChipHandle[2], JumpCount, Time, Input, EdgeInput,charX,charY,cameraX=0,cameraY=0,viewx,viewy;
///--------------------------------------------------------------------------- [gpUpdateKey=キー入力関数]
int gpUpdateKey() { char tmpKey[256];/////////////////////////////////////
    GetHitKeyStateAll(tmpKey);for (int i = 0; i < 256; i++) {
        if (tmpKey[i] != 0) { Key[i]++; }else{ Key[i] = 0; } } return 0; }

///---------------------------------------------------------------------------- [GetChipParam]マップチップ確認
int GetChipParam(float X, float Y)
{int x, y; x = (int)X / CHIP_SIZE; y = (int)Y / CHIP_SIZE;if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;
     return MapData[y][x]; }
///---------------------------------------------------------------------------- []マップの当たり判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) { float afX, afY;
    afX = X + *MoveX; afY = Y + *MoveY;
     if (GetChipParam(X, Y) == 1) {
        float blx, bty, brx, bby;
        //-----------------------------------------------------------------[壁衝突確認]
        blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;//左辺の当たり判定
        brx = (float)((int)afX / CHIP_SIZE + 1)*CHIP_SIZE;//右辺の当たり判定
 
        bty = (float)((int)afY / CHIP_SIZE)*CHIP_SIZE;//上辺の当たり判定
        bby = (float)((int)afY / CHIP_SIZE + 1)*CHIP_SIZE;//下辺の当たり判定
        //-----------------------------------------------------------------[上辺に当たったら3を返す]
        if (*MoveY > 0.0F) {
            *MoveX = 0.0F;
            *MoveY = bty - Y - 1.0F;
            return 3;
        }
        //-----------------------------------------------------------------[辺に当たっていたら4を返す]
        if (*MoveY < 0.0F) {
            *MoveX = 0.0F;
            *MoveY = bby - Y + 1.0F;
            return 4;
        }
        if (*MoveX > 0.0F) {
            *MoveY = 0.0F;
            *MoveX = blx - X - 1.0F;
            return 1;
        }
        if (*MoveX < 0.0F) {
            *MoveY = 0.0F;
            *MoveX = brx - X + 1.0F;
            return 2;
        }
        return 4;
    }   return 0; }
//-------------------------------------------------------------------------[当たり判定チェック]
/*
if(壁にヒットしたら) *HitFlagXをTRUEにする;
if(*HitFlagXがTRUEなら){
           if (左に移動していて、左の壁にヒットしているのなら){
                  めり込み防止の為キャラを右に返してから;
                  *HitFlagX をFALSEにする;
           }
           else if (右に移動していて、右の壁にいるのなら){
                   めり込み防止の為キャラを左に返してから;
                   *HitFlag を FALSEにする;
           }
*/
	int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY) {
    float Dummy = 0.0F;
    float hsize;
    hsize = Size*0.5F;
    {printf("--------------------上下移動成分をチェック\t");
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3){ *DropPower = 0.0F; *HitFlagY = TRUE;}///<<<=====###
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY) == 3){ *DropPower = 0.0F; *HitFlagY = TRUE;}///<<<=====###
        
		if (MapHitCheck(*X - hsize, *Y - hsize, &Dummy, &MoveY) == 4){ *DropPower = -1.0F; }//左上
		if (MapHitCheck(*X + hsize, *Y - hsize, &Dummy, &MoveY) == 4){ *DropPower = -1.0F; }//右上
        
        *Y += MoveY;  } printf("-------問題がないのなら移動成分を加算する\n");
    {printf("--------------------------左右移動成分、以下同順\t");
        if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1) *HitFlagX = TRUE;
        if (MapHitCheck(*X + hsize, *Y + hsize, &MoveX, &Dummy) == 2) *HitFlagX = TRUE;
        if (MapHitCheck(*X - hsize, *Y - hsize, &MoveX, &Dummy) == 1) *HitFlagX = TRUE;
        if (MapHitCheck(*X + hsize, *Y - hsize, &MoveX, &Dummy) == 2) *HitFlagX = TRUE;
        *X += MoveX; }
    
    if (*HitFlagX == TRUE) {//----------ヒットフラグが付いたら、壁にハマるのを防止してからフラグをオフにする。
        
        if(*X<1&&MapHitCheck(*X-hsize,*Y+hsize,&MoveX,&Dummy)==1&&MapHitCheck(*X-hsize,*Y-hsize,&MoveX,&Dummy)==1){//左の場合
            *X += 8.0F; HitFlagX = FALSE; }
        else if(*X>1&&MapHitCheck(*X+hsize,*Y-hsize,&MoveX,&Dummy)==2&&MapHitCheck(*X+hsize,*Y+hsize,&MoveX,&Dummy)==2){//右の場合
            *X -= 8.0F;  HitFlagX = FALSE; } }
    {
        //空中にいるなら、空中にいるとみなす
        if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F + 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F + 1.0F) == 0) {
            *AirFlag = TRUE;
        }
        //もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
        else if (*HitFlagY = TRUE) {
            *Y -= 1.0F;
            *HitFlagY = FALSE;
            *AirFlag = FALSE;
            JumpCount = 0;
            Gravity = 0;
            *JumpFlag = FALSE;
        }
        return 0;
    }
}
int DrawChar() {//------------------------------------------------------------------------------------------[DrawChar]
    if (dir == TRUE) { DrawRotaGraph((int)PlayerX, (int)PlayerY + 2, 1.0, 0.0, PlayerHandle, TRUE, FALSE); }
    else { DrawRotaGraph((int)PlayerX, (int)PlayerY + 2, 1.0, 0, PlayerHandle, TRUE, TRUE); }return 0; }
int DrawMap() {//-------------------------------------------------------------------------------------------[マップの描画]
    { int i, j;for (i = 0; i < MAP_HEIGHT; i++) { for (j = 0; j < MAP_WIDTH; j++) {
                if (MapData[i][j] == 1) { DrawGraph(j * CHIP_SIZE, i*CHIP_SIZE, MapChipHandle[1], TRUE); }  } } } return 0; }
int CameraCheck() {//---------------------------------------------------------------------------------------[カメラの確認]

    //プレイヤーの位置チェック
    charX = (int)PlayerX, charY = (int)PlayerY;
    //カメラの位置チェック
    cameraX = charX - SCREEN_WIDTH / 2, cameraY = charY - SCREEN_WIDTH / 2;
    //横のカメラを動かす
    if (cameraX < 0)cameraX = 0;
    if (cameraX >(STAGE_WIDTH - SCREEN_WIDTH))cameraX = (STAGE_WIDTH - SCREEN_WIDTH);
    //縦のカメラを動かす
    if (cameraY < 0) cameraY = 0;
    if (cameraY >(STAGE_HEIGHT - SCREEN_HEIGHT))cameraY = (STAGE_HEIGHT - SCREEN_HEIGHT);
    return 0;
}

int main(void) {printf("②main()--->\t");
    SetFontSize(8);
    while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
        DrawMap();system("cls");printf("③Time=%d\t",Time);
        //カウント値を更新する
        Time = GetNowCount();printf("③Time=%d\t",Time);
        //フレームを管理する
        while (GetNowCount() - Time < 1000 / 60) { Sleep(1); }
        //入力状態を更新する
        {
            int i;
            i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
            //チョン押しを確認する
            EdgeInput = i & ~Input;
            Input = i;
        }
        //ダッシュトリガー確認
        if ((Input&PAD_INPUT_1) == 0) {
            DashFlag = FALSE;
        }
        if (JumpCount >= 2) {
            JumpFlag = TRUE;
        }
        //移動処理
        {
            float MoveX, MoveY;
            MoveX = 0.0F;
            MoveY = 0.0F;
            //左に移動
            if ((Input&PAD_INPUT_LEFT) != 0) {
                dir = FALSE;
                MoveX -= 5.0F;
            }
            //右に移動
            if ((Input&PAD_INPUT_RIGHT) != 0) {
                dir = TRUE;
                MoveX += 5.0F;
            }
            printf("左ラン\t");
            if ((Input&PAD_INPUT_LEFT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
                dir = FALSE;
                DashFlag = TRUE;
                MoveX -= 5.25F;
            }
            printf("右ラン\t");
            if ((Input&PAD_INPUT_RIGHT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
                dir = TRUE;
                DashFlag = TRUE;
                MoveX += 5.25F;
            }
            printf("ダッシュボタン\t");
            if ((EdgeInput&PAD_INPUT_3) != 0) {
                int DashTimer = GetNowCount();
 
            }
            printf("ジャンプ処理\t");
            if ((EdgeInput&PAD_INPUT_2) != 0 && JumpFlag == FALSE) {
                //ジャンプできる状態にする
                DropPower = 0;
                printf("ジャンプ回数を増やす\t");            JumpCount += 1;
                printf("ジャンプする\t");                    DropPower -= 9.5F;
                printf("ジャンプするときの重力を決める\t");  Gravity = 0.5F;
            }
            if ((EdgeInput&PAD_INPUT_2) != 0 && DashFlag == TRUE && JumpFlag == FALSE) {
                DashFlag = TRUE;
                DropPower = 0;
                JumpCount += 1;
                DropPower -= 12.0F;
                Gravity = 0.5F;
            }
            printf("カメラのチェック\t");            CameraCheck();
            printf("落下処理[重力加速]\t");          DropPower += Gravity;
            printf("落下速度を移動量に追加する\t");  MoveY = DropPower;
            printf("当たり判定に基づく移動を行う\t");
            MoveChecker(&PlayerX, &PlayerY, &DropPower, MoveX, MoveY, CHIP_SIZE, &JumpFlag, &AirFlag, &HitFlagX, &HitFlagY);
        }
		DrawChar(); } }//------------------------------------------------------ [DrawChar()]
 int init(void) {/////////////////////////////////////////////////////////////// [init]
    ChangeWindowMode(TRUE), SetGraphMode(320, 240, 32);printf("①init()--->\t");
	if (DxLib_Init() == -1) { exit(-1); }///--------------------------return -1; };<<<=====###
    SetDrawScreen(DX_SCREEN_BACK), Input = 0, Time = GetNowCount();//----------------------[カウント値を更新する]
    PlayerHandle = LoadGraph("テスト用.png"), LoadDivGraph("マップチップ.bmp", 2, 2, 1, 16, 16, MapChipHandle);
    dir = TRUE, DashFlag = FALSE, HitFlagX = TRUE, HitFlagY = FALSE; return 0;
}///--------------------------------------------------------------------------- [エントリーポイント]
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    AllocConsole();FILE* out=0;freopen_s( &out, "CON", "w", stdout );
    init();                                          //初期化処理
    main();                                         //メインプログラム
    DxLib_End();fclose(out);FreeConsole();return 0;//DXライブラリを終了する
}//////////////////////////////////////////////////////////////////////////////

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: キャラが壁にハマってしまう

#7

投稿記事 by ISLe » 7年前

オフトピック
読みやすいとは言えなくても、内容が分かりにくいとまでは思わないけれど、わたしは。

あたり判定に条件を加えるのはよろしくない。
押し戻したあともめり込んでいる状態が解消されないと移動できなくなるから。
そういう質問だからそういう理由で起きてるのだろうと予測してコードを読んでみる。

壁に当たってるときに押し戻す量が1.0f固定になってる。
これは圧倒的に足りていないのではないだろうか。

そこを直しても、浮動小数点数だから、計算上は足りてても誤差でハマる可能性が残る。

あたり判定はもっとシンプルであるべきと思う。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#8

投稿記事 by keito940 » 7年前

ISLe さんが書きました: あたり判定に条件を加えるのはよろしくない。
押し戻したあともめり込んでいる状態が解消されないと移動できなくなるから。
そういう質問だからそういう理由で起きてるのだろうと予測してコードを読んでみる。
なるほど、めり込み判定をなんとかしろというわけですか。そういや、そうかもしれませんね…。
壁に当たってるときに押し戻す量が1.0f固定になってる。
これは圧倒的に足りていないのではないだろうか。
そこを直しても、浮動小数点数だから、計算上は足りてても誤差でハマる可能性が残る。

まずは、めり込んでいる状態を解決してくださいと。
ということは、直前の移動フレームを実装すればいいわけですね。
どうして今まで気づかなかったのだろうか…。
最後に編集したユーザー keito940 on 2017年1月31日(火) 19:10 [ 編集 1 回目 ]

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: キャラが壁にハマってしまう

#9

投稿記事 by みけCAT » 7年前

No: 1のコードの148行目
keito940 さんが書きました:

コード:

		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else if (*HitFlagY = TRUE) {
において、if文の中で比較ではなく代入を行い、条件式が常に真になっています。
これは意図した仕様ですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#10

投稿記事 by keito940 » 7年前

みけCAT さんが書きました:No: 1のコードの148行目
keito940 さんが書きました:

コード:

		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else if (*HitFlagY = TRUE) {
において、if文の中で比較ではなく代入を行い、条件式が常に真になっています。
これは意図した仕様ですか?
そういえばそうかもしれませんが、今書いているコードではそれは使っていません。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#11

投稿記事 by keito940 » 7年前

そんな皆さんの声援を受け、頑張って自力で壁衝突の処理を作りました。でも、壁に衝突するとキャラが空中浮遊をしたり、何回か壁に移動すると壁にやはりはまってしまいます。そして壁に移動しようとするとブルブル震えてしまいます。(今気づいたことなのですが)しかも、着地すると一瞬だけ埋まって、何事もなかったかのように地面に上がってしまいます。どうすればいいのでしょうか?

コード:

#include "dxlib.h"
#define SCREEN_WIDTH (320)
#define SCREEN_HEIGHT (240)
#define STAGE_WIDTH (320)
#define STAGE_HEIGHT (240)
#define CHIP_SIZE (16)
#define MAP_WIDTH (STAGE_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (STAGE_HEIGHT/CHIP_SIZE)

float PlayerX = 25.0F, PlayerY = 216.0F, DropPower = 0.0F, Gravity;
char dir, JumpFlag, DashFlag, AirFlag, DashTrigger, HitFlagX, HitFlagY;
int GetChipParam(float X, float Y);
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY);
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY);
int PlayerHandle, MapChipHandle[2], JumpCount, Time, Input, EdgeInput, charX, charY, cameraX = 0, cameraY = 0, viewx, viewy;
int Key[256];
int gpUpdateKey() {
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++) {
		if (tmpKey[i] != 0) {
			Key[i]++;
		}
		else {
			Key[i] = 0;
		}
	}
	return 0;
}
char MapData[MAP_HEIGHT][MAP_WIDTH] =
{
	0,0,0,0,0, 0,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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
};

//マップチップ確認
int GetChipParam(float X, float Y)
{
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;

	return MapData[y][x];
}
//マップの当たり判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (GetChipParam(X, Y) == 1) {
		float blx, bty, brx, bby;
		//壁衝突確認
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;//左辺の当たり判定
		brx = (float)((int)afX / CHIP_SIZE + 1)*CHIP_SIZE;//右辺の当たり判定

		bty = (float)((int)afY / CHIP_SIZE)*CHIP_SIZE;//上辺の当たり判定
		bby = (float)((int)afY / CHIP_SIZE + 1)*CHIP_SIZE;//下辺の当たり判定
		//上辺に当たったら3を返す
		if (*MoveY > 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bty - Y - 1.0F;
			return 3;
		}
		//下辺に当たっていたら4を返す
		if (*MoveY < 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bby - Y + 1.0F;
			return 4;
		}
		if (*MoveX > 0.0F) {
			*MoveY = 0.0F;
			*MoveX = blx - X - 1.0F;
			return 1;
		}
		if (*MoveX < 0.0F) {
			*MoveY = 0.0F;
			*MoveX = brx - X + 1.0F;
			return 2;
		}
		return 4;
	}
	return 0;
}
//当たり判定チェック
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY) {
	float Dummy = 0.0F;
	float hsize;
	float new_x = *X;//次フレームのX座標
	float new_y = *Y;//次フレームのY座標

	hsize = Size*0.5F;
	//上下移動成分をチェック
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F; *HitFlagY = TRUE;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F; *HitFlagY = TRUE;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//問題がないのなら移動成分を加算する
		new_y += MoveY;
	}
	//左右移動成分、以下同順
	{
		//左の場合
		if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1 && MapHitCheck(*X - hsize, *Y - hsize, &MoveX, &Dummy) == 1) {
			*X -= 1.5F;
			MoveX = 0.0F;
		}
		//右の場合
		if (MapHitCheck(*X + hsize, *Y - hsize, &MoveX, &Dummy) == 2 && MapHitCheck(*X + hsize, *Y + hsize, &MoveX, &Dummy) == 2) {
			*X += 1.5F;
			MoveX = 0.0F;
		}
		//問題がないのなら移動成分を加算する
		new_x += MoveX;
	}
	//問題ないのなら、X座標を更新する
	*X = new_x;
	{
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F + 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F + 1.0F) == 0) {
			*Y = new_y;//座標更新
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else if (*HitFlagY = TRUE) {
			new_y -= (int)1;
			*Y = new_y;
			*HitFlagY = FALSE;
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}
int DrawChar() {
	if (dir == TRUE) {
		DrawRotaGraph((int)PlayerX, (int)PlayerY, 1.0, 0.0, PlayerHandle, TRUE, FALSE);
	}
	else {
		DrawRotaGraph((int)PlayerX, (int)PlayerY, 1.0, 0, PlayerHandle, TRUE, TRUE);
	}
	return 0;
}
//マップの描画
int DrawMap() {
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
					DrawGraph(j * CHIP_SIZE, i*CHIP_SIZE, MapChipHandle[1], TRUE);
				}
			}
		}
	} return 0;
}
//カメラの確認
int CameraCheck() {
	//プレイヤーの位置チェック
	charX = (int)PlayerX, charY = (int)PlayerY;
	//カメラの位置チェック
	cameraX = charX - SCREEN_WIDTH / 2, cameraY = charY - SCREEN_WIDTH / 2;
	//横のカメラを動かす
	if (cameraX < 0)cameraX = 0;
	if (cameraX >(STAGE_WIDTH - SCREEN_WIDTH))cameraX = (STAGE_WIDTH - SCREEN_WIDTH);
	//縦のカメラを動かす
	if (cameraY < 0) cameraY = 0;
	if (cameraY >(STAGE_HEIGHT - SCREEN_HEIGHT))cameraY = (STAGE_HEIGHT - SCREEN_HEIGHT);
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE), SetGraphMode(320, 240, 32);
	if (DxLib_Init() == -1) { return -1; };
	SetDrawScreen(DX_SCREEN_BACK), Input = 0, Time = GetNowCount();//カウント値を更新する
	PlayerHandle = LoadGraph("テスト用.png"), LoadDivGraph("マップチップ.bmp", 2, 2, 1, 16, 16, MapChipHandle);
	dir = TRUE, DashFlag = FALSE, HitFlagX = FALSE, HitFlagY = FALSE;
	return 0;
}
int main(void) {
	//マップの描画
	DrawMap();
	//カウント値を更新する
	Time = GetNowCount();
	//フレームを管理する
	while (GetNowCount() - Time < 1000 / 60) { Sleep(1); }
	//入力状態を更新する
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		//チョン押しを確認する
		EdgeInput = i & ~Input;
		Input = i;
	}
	//ダッシュトリガー確認
	if ((Input&PAD_INPUT_1) == 0) {
		DashFlag = FALSE;
	}
	if (JumpCount >= 2) {
		JumpFlag = TRUE;
	}
	//移動処理
	{
		float MoveX, MoveY;
		MoveX = 0.0F;
		MoveY = 0.0F;
		//左に移動
		if ((Input&PAD_INPUT_LEFT) != 0) {
			dir = FALSE;
			MoveX -= 5.0F;
		}
		//右に移動
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			dir = TRUE;
			MoveX += 5.0F;
		}
		//左ラン
		if ((Input&PAD_INPUT_LEFT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = FALSE;
			DashFlag = TRUE;
			MoveX -= 5.25F;
		}
			//右ラン
		if ((Input&PAD_INPUT_RIGHT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = TRUE;
			DashFlag = TRUE;
			MoveX += 5.25F;
		}
		//ダッシュボタン
		if ((EdgeInput&PAD_INPUT_3) != 0) {
			int DashTimer = GetNowCount();

		}
		//ジャンプ処理
		if ((EdgeInput&PAD_INPUT_2) != 0 && JumpFlag == FALSE) {
			//ジャンプできる状態にする
			DropPower = 0;
			//ジャンプ回数を増やす
			JumpCount += 1;
			//ジャンプする
			DropPower -= 9.5F;
			//ジャンプするときの重力を決める
			Gravity = 0.5F;
		}
		if ((EdgeInput&PAD_INPUT_2) != 0 && DashFlag == TRUE && JumpFlag == FALSE) {
			DashFlag = TRUE;
			DropPower = 0;
			JumpCount += 1;
			DropPower -= 12.0F;
			Gravity = 0.5F;
		}
		//カメラのチェック
		CameraCheck();
		//落下処理
		DropPower += Gravity;
		//落下速度を移動量に追加する
		MoveY = DropPower;
		//当たり判定に基づく移動を行う
		MoveChecker(&PlayerX, &PlayerY, &DropPower, MoveX, MoveY, CHIP_SIZE, &JumpFlag, &AirFlag, &HitFlagX, &HitFlagY);
	}
	DrawChar();
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	init();//初期化処理
	//メインプログラム
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
		main();
	}
	//DXライブラリを終了する
	DxLib_End();
	return 0;
}

Math

Re: キャラが壁にハマってしまう

#12

投稿記事 by Math » 7年前

114行など
if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F; *HitFlagY = TRUE;

if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) {
   *DropPower = 0.0F;

*HitFlagY = TRUE;
と等価なので { } を省くときは注意が必要でしょう。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: キャラが壁にハマってしまう

#13

投稿記事 by みけCAT » 7年前

keito940 さんが書きました:
みけCAT さんが書きました:No: 1のコードの148行目
keito940 さんが書きました:

コード:

		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else if (*HitFlagY = TRUE) {
において、if文の中で比較ではなく代入を行い、条件式が常に真になっています。
これは意図した仕様ですか?
そういえばそうかもしれませんが、今書いているコードではそれは使っていません。
NO: 11のコードの148行目にも同様のif文の中での代入処理がありますね。
「それ」とは何ですか?
「それは使っていません」とはどういうことですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: キャラが壁にハマってしまう

#14

投稿記事 by みけCAT » 7年前

Math さんが書きました:114行など
if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F; *HitFlagY = TRUE;

if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) {
   *DropPower = 0.0F;

*HitFlagY = TRUE;
と等価なので { } を省くときは注意が必要でしょう。
コンマ演算子を使って

コード:

if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
と書くと、

コード:

if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) {
	*DropPower = 0.0F;
	*HitFlagY = TRUE;
}
と等価になります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Math

Re: キャラが壁にハマってしまう

#15

投稿記事 by Math » 7年前

よくある論争http://bashalog.c-brains.jp/09/08/05-004630.phpですがまた一手加わりましたか。短いサンプルは別として”Bug"らないためには{}は省略すべきではないと思いますが。
(VBはVS2015で C#の責任者がVBを担当してほんの”2000万行”ほどで”C#ライクなVisual Basicに”かわったそうですが....「Bugをださないのは大変でしょう...」(ただしVBのコードで書いたそうですが)

アバター
usao
記事: 1889
登録日時: 11年前

Re: キャラが壁にハマってしまう

#16

投稿記事 by usao » 7年前

オフトピック
書きました → 変な動きをしてます → どうすればいいでしょうか

問題が起こった際,ざっくりと以下の2ステップ
 (1)どうしてそうなってしまうのか原因を究明する
 (2)問題を解消する方法を考える
が必要になるのだとして…

あなたはそのどちらの作業をも他人に投げているように見える.

(1)の側すらご自身で行わない理由があるのでしょうか?

そんなことはない,自身でもデバッグしている,ということであれば,
問題点を"見た目の現象"として曖昧に書いて丸投げ的に質問するよりも
デバッグ作業の結果得られている知見を書く等した方が
良い{欲しい,有用な,ピンポイントな,…}回答を得られやすいのではないかと思うが.
例えば,
 「この変数値の挙動は本来こうあって欲しいのだが,
  座標XXXにキャラクタが達した際に,この箇所で変な値に変わってしまうようだ.
  しかし何故そんな値に変化するのかがわからない」
とか,具体的に言えばどうか.

#コードが読み難いとか纏まってないとか言われる理由も,結局はそういうところにあると思う.

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#17

投稿記事 by keito940 » 7年前

みけCAT さんが書きました:No: 1のコードの148行目
NO: 11のコードの148行目にも同様のif文の中での代入処理がありますね。
言われてみればそうですね…。代入処理を修正したコードを貼っときます。

コード:

#include "dxlib.h"
#define SCREEN_WIDTH (320)
#define SCREEN_HEIGHT (240)
#define STAGE_WIDTH (320)
#define STAGE_HEIGHT (240)
#define CHIP_SIZE (16)
#define MAP_WIDTH (STAGE_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (STAGE_HEIGHT/CHIP_SIZE)

float PlayerX = 25.0F, PlayerY = 216.0F, DropPower = 0.0F, Gravity;
char dir, JumpFlag, DashFlag, AirFlag, DashTrigger, HitFlagX, HitFlagY;
int GetChipParam(float X, float Y);
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY);
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY);
int PlayerHandle, MapChipHandle[2], JumpCount, Time, Input, EdgeInput, charX, charY, cameraX = 0, cameraY = 0, viewx, viewy;
int Key[256];
int gpUpdateKey() {
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++) {
		if (tmpKey[i] != 0) {
			Key[i]++;
		}
		else {
			Key[i] = 0;
		}
	}
	return 0;
}
char MapData[MAP_HEIGHT][MAP_WIDTH] =
{
	0,0,0,0,0, 0,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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
};

//マップチップ確認
int GetChipParam(float X, float Y)
{
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;

	return MapData[y][x];
}
//マップの当たり判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (GetChipParam(X, Y) == 1) {
		float blx, bty, brx, bby;
		//壁衝突確認
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;//左辺の当たり判定
		brx = (float)((int)afX / CHIP_SIZE + 1)*CHIP_SIZE;//右辺の当たり判定

		bty = (float)((int)afY / CHIP_SIZE)*CHIP_SIZE;//上辺の当たり判定
		bby = (float)((int)afY / CHIP_SIZE + 1)*CHIP_SIZE;//下辺の当たり判定
		//上辺に当たったら3を返す
		if (*MoveY > 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bty - Y - 1.0F;
			return 3;
		}
		//下辺に当たっていたら4を返す
		if (*MoveY < 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bby - Y + 1.0F;
			return 4;
		}
		if (*MoveX > 0.0F) {
			*MoveY = 0.0F;
			*MoveX = blx - X - 1.0F;
			return 1;
		}
		if (*MoveX < 0.0F) {
			*MoveY = 0.0F;
			*MoveX = brx - X + 1.0F;
			return 2;
		}
		return 4;
	}
	return 0;
}
//当たり判定チェック
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY) {
	float Dummy = 0.0F;
	float hsize;
	float new_x = *X;//次フレームのX座標
	float new_y = *Y;//次フレームのY座標

	hsize = Size*0.5F;
	//上下移動成分をチェック
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//問題がないのなら移動成分を加算する
		new_y += MoveY;
	}
	//左右移動成分、以下同順
	{
		//左の場合
		if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1 && MapHitCheck(*X - hsize, *Y - hsize, &MoveX, &Dummy) == 1) {
			*X -= 1.5F;
			MoveX = 0.0F;
		}
		//右の場合
		if (MapHitCheck(*X + hsize, *Y - hsize, &MoveX, &Dummy) == 2 && MapHitCheck(*X + hsize, *Y + hsize, &MoveX, &Dummy) == 2) {
			*X += 1.5F;
			MoveX = 0.0F;
		}
		//問題がないのなら移動成分を加算する
		new_x += MoveX;
	}
	//問題ないのなら、X座標を更新する
	*X = new_x;
	{
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F + 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F + 1.0F) == 0) {
			*Y = new_y;//座標更新
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else {
			new_y -= (int)1;
			*Y = new_y;
			*HitFlagY = FALSE;
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}
int DrawChar() {
	if (dir == TRUE) {
		DrawRotaGraph((int)PlayerX, (int)PlayerY, 1.0, 0.0, PlayerHandle, TRUE, FALSE);
	}
	else {
		DrawRotaGraph((int)PlayerX, (int)PlayerY, 1.0, 0, PlayerHandle, TRUE, TRUE);
	}
	return 0;
}
//マップの描画
int DrawMap() {
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
					DrawGraph(j * CHIP_SIZE, i*CHIP_SIZE, MapChipHandle[1], TRUE);
				}
			}
		}
	} return 0;
}
//カメラの確認
int CameraCheck() {
	//プレイヤーの位置チェック
	charX = (int)PlayerX, charY = (int)PlayerY;
	//カメラの位置チェック
	cameraX = charX - SCREEN_WIDTH / 2, cameraY = charY - SCREEN_WIDTH / 2;
	//横のカメラを動かす
	if (cameraX < 0)cameraX = 0;
	if (cameraX >(STAGE_WIDTH - SCREEN_WIDTH))cameraX = (STAGE_WIDTH - SCREEN_WIDTH);
	//縦のカメラを動かす
	if (cameraY < 0) cameraY = 0;
	if (cameraY >(STAGE_HEIGHT - SCREEN_HEIGHT))cameraY = (STAGE_HEIGHT - SCREEN_HEIGHT);
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE), SetGraphMode(320, 240, 32);
	if (DxLib_Init() == -1) { return -1; };
	SetDrawScreen(DX_SCREEN_BACK), Input = 0, Time = GetNowCount();//カウント値を更新する
	PlayerHandle = LoadGraph("テスト用.png"), LoadDivGraph("マップチップ.bmp", 2, 2, 1, 16, 16, MapChipHandle);
	dir = TRUE, DashFlag = FALSE, HitFlagX = FALSE, HitFlagY = FALSE;
	return 0;
}
int main(void) {
	//マップの描画
	DrawMap();
	//カウント値を更新する
	Time = GetNowCount();
	//フレームを管理する
	while (GetNowCount() - Time < 1000 / 60) { Sleep(1); }
	//入力状態を更新する
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		//チョン押しを確認する
		EdgeInput = i & ~Input;
		Input = i;
	}
	//ダッシュトリガー確認
	if ((Input&PAD_INPUT_1) == 0) {
		DashFlag = FALSE;
	}
	if (JumpCount >= 2) {
		JumpFlag = TRUE;
	}
	//移動処理
	{
		float MoveX, MoveY;
		MoveX = 0.0F;
		MoveY = 0.0F;
		//左に移動
		if ((Input&PAD_INPUT_LEFT) != 0) {
			dir = FALSE;
			MoveX -= 5.0F;
		}
		//右に移動
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			dir = TRUE;
			MoveX += 5.0F;
		}
		//左ラン
		if ((Input&PAD_INPUT_LEFT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = FALSE;
			DashFlag = TRUE;
			MoveX -= 5.25F;
		}
			//右ラン
		if ((Input&PAD_INPUT_RIGHT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = TRUE;
			DashFlag = TRUE;
			MoveX += 5.25F;
		}
		//ダッシュボタン
		if ((EdgeInput&PAD_INPUT_3) != 0) {
			int DashTimer = GetNowCount();

		}
		//ジャンプ処理
		if ((EdgeInput&PAD_INPUT_2) != 0 && JumpFlag == FALSE) {
			//ジャンプできる状態にする
			DropPower = 0;
			//ジャンプ回数を増やす
			JumpCount += 1;
			//ジャンプする
			DropPower -= 9.5F;
			//ジャンプするときの重力を決める
			Gravity = 0.5F;
		}
		if ((EdgeInput&PAD_INPUT_2) != 0 && DashFlag == TRUE && JumpFlag == FALSE) {
			DashFlag = TRUE;
			DropPower = 0;
			JumpCount += 1;
			DropPower -= 12.0F;
			Gravity = 0.5F;
		}
		//カメラのチェック
		CameraCheck();
		//落下処理
		DropPower += Gravity;
		//落下速度を移動量に追加する
		MoveY = DropPower;
		//当たり判定に基づく移動を行う
		MoveChecker(&PlayerX, &PlayerY, &DropPower, MoveX, MoveY, CHIP_SIZE, &JumpFlag, &AirFlag, &HitFlagX, &HitFlagY);
	}
	DrawChar();
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	init();//初期化処理
	//メインプログラム
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
		main();
	}
	//DXライブラリを終了する
	DxLib_End();
	return 0;
}
「それ」とは何ですか?
「それは使っていません」とはどういうことですか?
さきほどあなたが挙げていためり込み防止のアルゴリズムを廃棄して、新しくめり込み防止のアルゴリズムを作りましたよ、という意味です。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#18

投稿記事 by keito940 » 7年前

usao さんが書きました:
オフトピック
書きました → 変な動きをしてます → どうすればいいでしょうか

問題が起こった際,ざっくりと以下の2ステップ
 (1)どうしてそうなってしまうのか原因を究明する
 (2)問題を解消する方法を考える
が必要になるのだとして…

あなたはそのどちらの作業をも他人に投げているように見える.

(1)の側すらご自身で行わない理由があるのでしょうか?

そんなことはない,自身でもデバッグしている,ということであれば,
問題点を"見た目の現象"として曖昧に書いて丸投げ的に質問するよりも
デバッグ作業の結果得られている知見を書く等した方が
良い{欲しい,有用な,ピンポイントな,…}回答を得られやすいのではないかと思うが.
例えば,
 「この変数値の挙動は本来こうあって欲しいのだが,
  座標XXXにキャラクタが達した際に,この箇所で変な値に変わってしまうようだ.
  しかし何故そんな値に変化するのかがわからない」
とか,具体的に言えばどうか.

#コードが読み難いとか纏まってないとか言われる理由も,結局はそういうところにあると思う.
やっぱりデバッグは必要ですよ、ってことですね…。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#19

投稿記事 by keito940 » 7年前

usaoさんに言われて、ようやくデバッグしてみてわかったことなんですが、着地したときに一瞬だけ埋もれてしまうのは着地のときに一瞬だけY座標が地面へ行ってしまうことにあるんですね…。
で、本題になるのですが、どうやら壁に衝突すると、空中に浮いてしまうのは、原因は壁に衝突するときに、X座標が移動するのと同時に、Y座標も同時に動いてしまうことにあるようです。どうしたら、Y座標を動かさずに壁に衝突できるのでしょうか…。

コード:

#include "dxlib.h"
#define SCREEN_WIDTH (320)
#define SCREEN_HEIGHT (240)
#define STAGE_WIDTH (320)
#define STAGE_HEIGHT (240)
#define CHIP_SIZE (16)
#define MAP_WIDTH (STAGE_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (STAGE_HEIGHT/CHIP_SIZE)

float PlayerX = 25.0F, PlayerY = 216.0F, DropPower = 0.0F, Gravity;
char dir, JumpFlag, DashFlag, AirFlag, DashTrigger, HitFlagX, HitFlagY;
int GetChipParam(float X, float Y);
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY);
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY);
int PlayerHandle, MapChipHandle[2], JumpCount, Time, Input, EdgeInput, charX, charY, cameraX = 0, cameraY = 0, viewx, viewy;
int Key[256];
int gpUpdateKey() {
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++) {
		if (tmpKey[i] != 0) {
			Key[i]++;
		}
		else {
			Key[i] = 0;
		}
	}
	return 0;
}
char MapData[MAP_HEIGHT][MAP_WIDTH] =
{
	0,0,0,0,0, 0,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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
};

//マップチップ確認
int GetChipParam(float X, float Y)
{
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;

	return MapData[y][x];
}
//マップの当たり判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (GetChipParam(X, Y) == 1) {
		float blx, bty, brx, bby;
		//壁衝突確認
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;//左辺の当たり判定
		brx = (float)((int)afX / CHIP_SIZE + 1)*CHIP_SIZE;//右辺の当たり判定

		bty = (float)((int)afY / CHIP_SIZE)*CHIP_SIZE;//上辺の当たり判定
		bby = (float)((int)afY / CHIP_SIZE + 1)*CHIP_SIZE;//下辺の当たり判定
		//上辺に当たったら3を返す
		if (*MoveY > 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bty - Y - 1.0F;
			return 3;
		}
		//下辺に当たっていたら4を返す
		if (*MoveY < 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bby - Y + 1.0F;
			return 4;
		}
		if (*MoveX > 0.0F) {
			*MoveY = 0.0F;
			*MoveX = blx - X - 1.0F;
			return 1;
		}
		if (*MoveX < 0.0F) {
			*MoveY = 0.0F;
			*MoveX = brx - X + 1.0F;
			return 2;
		}
		return 4;
	}
	return 0;
}
//当たり判定チェック
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY) {
	float Dummy = 0.0F;
	float hsize;
	float new_x = *X;//次フレームのX座標
	float new_y = *Y;//次フレームのY座標

	hsize = Size*0.5F;
	//上下移動成分をチェック
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//問題がないのなら移動成分を加算する
		new_y += MoveY;
	}
	//左右移動成分、以下同順
	{
		//左の場合
		if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1 && MapHitCheck(*X - hsize, *Y - hsize, &MoveX, &Dummy) == 1) {
			*X -= 1.5F;
			MoveX = 0.0F;
		}
		//右の場合
		if (MapHitCheck(*X + hsize, *Y - hsize, &MoveX, &Dummy) == 2 && MapHitCheck(*X + hsize, *Y + hsize, &MoveX, &Dummy) == 2) {
			*X += 1.5F;
			MoveX = 0.0F;
		}
		//問題がないのなら移動成分を加算する
		new_x += MoveX;
	}
	//問題ないのなら、X座標を更新する
	*X = new_x;
	{
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F + 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F + 1.0F) == 0) {
			*Y = new_y;//座標更新
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else {
			new_y -= (int)1;
			*Y = new_y;
			*HitFlagY = FALSE;
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}
int DrawChar() {
	if (dir == TRUE) {
		DrawRotaGraph((int)PlayerX, (int)PlayerY, 1.0, 0.0, PlayerHandle, TRUE, FALSE);
	}
	else {
		DrawRotaGraph((int)PlayerX, (int)PlayerY, 1.0, 0, PlayerHandle, TRUE, TRUE);
	}
	return 0;
}
//マップの描画
int DrawMap() {
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
					DrawGraph(j * CHIP_SIZE, i*CHIP_SIZE, MapChipHandle[1], TRUE);
				}
			}
		}
	} return 0;
}
//カメラの確認
int CameraCheck() {
	//プレイヤーの位置チェック
	charX = (int)PlayerX, charY = (int)PlayerY;
	//カメラの位置チェック
	cameraX = charX - SCREEN_WIDTH / 2, cameraY = charY - SCREEN_WIDTH / 2;
	//横のカメラを動かす
	if (cameraX < 0)cameraX = 0;
	if (cameraX >(STAGE_WIDTH - SCREEN_WIDTH))cameraX = (STAGE_WIDTH - SCREEN_WIDTH);
	//縦のカメラを動かす
	if (cameraY < 0) cameraY = 0;
	if (cameraY >(STAGE_HEIGHT - SCREEN_HEIGHT))cameraY = (STAGE_HEIGHT - SCREEN_HEIGHT);
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE), SetGraphMode(320, 240, 32); printf("初期化しています…。\t");
	if (DxLib_Init() == -1) { return -1; };
	SetDrawScreen(DX_SCREEN_BACK), Input = 0, Time = GetNowCount();//カウント値を更新する
	PlayerHandle = LoadGraph("テスト用.png"), LoadDivGraph("マップチップ.bmp", 2, 2, 1, 16, 16, MapChipHandle);
	dir = TRUE, DashFlag = FALSE, HitFlagX = FALSE, HitFlagY = FALSE;
	return 0;
}
int main(void) {
	//マップの描画
	DrawMap();system("cls");printf("Time=%d\t",Time);
	//カウント値を更新する
	Time = GetNowCount();printf("Time=%d\t",Time);
	printf("現在のX座標=%d 現在のY座標=%d",(int)PlayerX,(int)PlayerY);
	//フレームを管理する
	while (GetNowCount() - Time < 1000 / 60) { Sleep(1); }
	//入力状態を更新する
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		//チョン押しを確認する
		EdgeInput = i & ~Input;
		Input = i;
	}
	//ダッシュトリガー確認
	if ((Input&PAD_INPUT_1) == 0) {
		DashFlag = FALSE;
	}
	if (JumpCount >= 2) {
		JumpFlag = TRUE;
	}
	//移動処理
	{
		float MoveX, MoveY;
		MoveX = 0.0F;
		MoveY = 0.0F;
		//左に移動
		if ((Input&PAD_INPUT_LEFT) != 0) {
			dir = FALSE;
			MoveX -= 5.0F;
		}
		//右に移動
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			dir = TRUE;
			MoveX += 5.0F;
		}
		//左ラン
		if ((Input&PAD_INPUT_LEFT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = FALSE;
			DashFlag = TRUE;
			MoveX -= 5.25F;
		}
			//右ラン
		if ((Input&PAD_INPUT_RIGHT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = TRUE;
			DashFlag = TRUE;
			MoveX += 5.25F;
		}
		//ダッシュボタン
		if ((EdgeInput&PAD_INPUT_3) != 0) {
			int DashTimer = GetNowCount();

		}
		//ジャンプ処理
		if ((EdgeInput&PAD_INPUT_2) != 0 && JumpFlag == FALSE) {
			//ジャンプできる状態にする
			DropPower = 0;
			//ジャンプ回数を増やす
			JumpCount += 1;
			//ジャンプする
			DropPower -= 9.5F;
			//ジャンプするときの重力を決める
			Gravity = 0.5F;
		}
		if ((EdgeInput&PAD_INPUT_2) != 0 && DashFlag == TRUE && JumpFlag == FALSE) {
			DashFlag = TRUE;
			DropPower = 0;
			JumpCount += 1;
			DropPower -= 12.0F;
			Gravity = 0.5F;
		}
		//カメラのチェック
		CameraCheck();
		//落下処理
		DropPower += Gravity;
		//落下速度を移動量に追加する
		MoveY = DropPower;
		//当たり判定に基づく移動を行う
		MoveChecker(&PlayerX, &PlayerY, &DropPower, MoveX, MoveY, CHIP_SIZE, &JumpFlag, &AirFlag, &HitFlagX, &HitFlagY);
	}
	DrawChar();
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	AllocConsole();FILE* out=0;freopen_s(&out,"CON","w",stdout);//デバッグ用コンソール
	init();//初期化処理
	//メインプログラム
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
		main();
	}
	//DXライブラリを終了する
	DxLib_End();fclose(out);FreeConsole();
	return 0;
}

Math

Re: キャラが壁にハマってしまう

#20

投稿記事 by Math » 7年前

「特になにもないです」..http://dixq.net/forum/viewtopic.php?f=3&t=18777

コード:

#include "dxlib.h"
#define SCREEN_WIDTH (320)
#define SCREEN_HEIGHT (240)
#define STAGE_WIDTH (320)
#define STAGE_HEIGHT (240)
#define CHIP_SIZE (16)
#define MAP_WIDTH (STAGE_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (STAGE_HEIGHT/CHIP_SIZE)

float PlayerX = 25.0F, PlayerY = 216.0F, DropPower = 0.0F, Gravity;
char dir, JumpFlag, DashFlag, AirFlag, DashTrigger, HitFlagX, HitFlagY;
int GetChipParam(float X, float Y);
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY);
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY);
int PlayerHandle, MapChipHandle[2], JumpCount, Time, Input, EdgeInput, charX, charY, cameraX = 0, cameraY = 0, viewx, viewy;
int Key[256];
//---iro-ne-ⅱ>/////////////////////////////////////////////////////////////////////////////////////
void draw(int, int, int, char*);
HANDLE Stdout; int color = 14; int tamaX[16], tamaY[16]; int ind = 0;
void draw(int x, int y, int col, char* c) {//座標x,yに文字列を出力
	COORD coord; coord.X = x; coord.Y = y; SetConsoleTextAttribute(Stdout, col | 8);
	SetConsoleCursorPosition(Stdout, coord); printf(c);
}//<
int gpUpdateKey() {
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; i++) {
		if (tmpKey[i] != 0) {
			Key[i]++;
		}
		else {
			Key[i] = 0;
		}
	}
	return 0;
}
char MapData[MAP_HEIGHT][MAP_WIDTH] =
{
	0,0,0,0,0, 0,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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
};

//マップチップ確認
int GetChipParam(float X, float Y)
{
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;

	return MapData[y][x];
}
//マップの当たり判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (GetChipParam(X, Y) == 1) {
		float blx, bty, brx, bby;
		//壁衝突確認
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;//左辺の当たり判定
		brx = (float)((int)afX / CHIP_SIZE + 1)*CHIP_SIZE;//右辺の当たり判定

		bty = (float)((int)afY / CHIP_SIZE)*CHIP_SIZE;//上辺の当たり判定
		bby = (float)((int)afY / CHIP_SIZE + 1)*CHIP_SIZE;//下辺の当たり判定
														  //上辺に当たったら3を返す
		if (*MoveY > 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bty - Y - 1.0F;
			return 3;
		}
		//下辺に当たっていたら4を返す
		if (*MoveY < 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bby - Y + 1.0F;
			return 4;
		}
		if (*MoveX > 0.0F) {
			*MoveY = 0.0F;
			*MoveX = blx - X - 1.0F;
			return 1;
		}
		if (*MoveX < 0.0F) {
			*MoveY = 0.0F;
			*MoveX = brx - X + 1.0F;
			return 2;
		}
		return 4;
	}
	return 0;
}
//当たり判定チェック
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY) {
	float Dummy = 0.0F;
	float hsize;
	float new_x = *X;//次フレームのX座標
	float new_y = *Y;//次フレームのY座標

	hsize = Size*0.5F;
	//上下移動成分をチェック
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//問題がないのなら移動成分を加算する
		new_y += MoveY;
	}
	//左右移動成分、以下同順
	{
		//左の場合
		if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1 && MapHitCheck(*X - hsize, *Y - hsize, &MoveX, &Dummy) == 1) {
			*X -= 1.5F;
			MoveX = 0.0F;
		}
		//右の場合
		if (MapHitCheck(*X + hsize, *Y - hsize, &MoveX, &Dummy) == 2 && MapHitCheck(*X + hsize, *Y + hsize, &MoveX, &Dummy) == 2) {
			*X += 1.5F;
			MoveX = 0.0F;
		}
		//問題がないのなら移動成分を加算する
		new_x += MoveX;
	}
	//問題ないのなら、X座標を更新する
	*X = new_x;
	{
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F + 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F + 1.0F) == 0) {
			*Y = new_y;//座標更新
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else {
			new_y -= (int)1;
			*Y = new_y;
			*HitFlagY = FALSE;
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}
int DrawChar() {
	if (dir == TRUE) {
		DrawRotaGraph((int)PlayerX, (int)PlayerY, 1.0, 0.0, PlayerHandle, TRUE, FALSE);
	}
	else {
		DrawRotaGraph((int)PlayerX, (int)PlayerY, 1.0, 0, PlayerHandle, TRUE, TRUE);
	}
	return 0;
}
//マップの描画
int DrawMap() {
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
					DrawGraph(j * CHIP_SIZE, i*CHIP_SIZE, MapChipHandle[1], TRUE);
				}
			}
		}
	} return 0;
}
//カメラの確認
int CameraCheck() {
	//プレイヤーの位置チェック
	charX = (int)PlayerX, charY = (int)PlayerY;
	//カメラの位置チェック
	cameraX = charX - SCREEN_WIDTH / 2, cameraY = charY - SCREEN_WIDTH / 2;
	//横のカメラを動かす
	if (cameraX < 0)cameraX = 0;
	if (cameraX >(STAGE_WIDTH - SCREEN_WIDTH))cameraX = (STAGE_WIDTH - SCREEN_WIDTH);
	//縦のカメラを動かす
	if (cameraY < 0) cameraY = 0;
	if (cameraY >(STAGE_HEIGHT - SCREEN_HEIGHT))cameraY = (STAGE_HEIGHT - SCREEN_HEIGHT);
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE), SetGraphMode(320, 240, 32); printf("初期化しています…。\t");
	if (DxLib_Init() == -1) { return -1; };
	SetDrawScreen(DX_SCREEN_BACK), Input = 0, Time = GetNowCount();//カウント値を更新する
	PlayerHandle = LoadGraph("テスト用.png"), LoadDivGraph("マップチップ.bmp", 2, 2, 1, 16, 16, MapChipHandle);
	dir = TRUE, DashFlag = FALSE, HitFlagX = FALSE, HitFlagY = FALSE;
	return 0;
}
///float PlayerX = 25.0F, PlayerY = 216.0F, DropPower = 0.0F, Gravity;/////////////////////////////
///char dir, JumpFlag, DashFlag, AirFlag, DashTrigger, HitFlagX, HitFlagY;/////////////////////////
int Globals_Monitor(void){ ///---iro-ne-ⅱ>
    for (ind = 0; ind < 16; ind++) {color = (rand() % 10) + 2; tamaX[ind] = rand() % 64;
        tamaY[ind] = rand() % 20; draw(tamaX[ind], tamaY[ind], color, "@");}draw(0, 3, color, ">");//<
    printf("現在のX座標=%d 現在のY座標=%d\n\n", (int)PlayerX, (int)PlayerY);draw(0, 5, color, ">");
    printf("DropPower=[%8.3f]---Gravity = [%8.3f]",DropPower,Gravity);      draw(0, 7, color, ">");
    printf("dir=[%d]---JumpFlag = [%d]", dir, JumpFlag);                    draw(0, 9, color, ">");
    printf("DashFlag=[%d]---AirFlag = [%d]", DashFlag, AirFlag);            draw(0,11, color, ">");
    printf("DashTrigger=[%d]", DashTrigger);                                draw(0,13, color, ">");
    printf("HitFlagX=[%d]---HitFlagY = [%d]", HitFlagX, HitFlagY);
    Beep(440, 5); Beep(494, 5); Beep(554, 5); Sleep(1);//---iro-ne-ⅱ>
    return 0;
}
int main(void) {
	//マップの描画
	DrawMap(); system("cls");/////////////////////////////////////////////////////////////////////////
	//カウント値を更新する
	Time = GetNowCount(); printf("Time=%d\n\n", Time);////////////////////////////////////////////////
	//printf("現在のX座標=%d 現在のY座標=%d\n\n", (int)PlayerX, (int)PlayerY);
	//フレームを管理する
	while (GetNowCount() - Time < 1000 / 60) { Sleep(1); }
	//入力状態を更新する
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		//チョン押しを確認する
		EdgeInput = i & ~Input;
		Input = i;
	}
	//ダッシュトリガー確認
	if ((Input&PAD_INPUT_1) == 0) {
		DashFlag = FALSE;
	}
	if (JumpCount >= 2) {
		JumpFlag = TRUE;
	}
	//移動処理
	{
		float MoveX, MoveY;
		MoveX = 0.0F;
		MoveY = 0.0F;
		//左に移動
		if ((Input&PAD_INPUT_LEFT) != 0) {
			dir = FALSE;
			MoveX -= 5.0F;
		}
		//右に移動
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			dir = TRUE;
			MoveX += 5.0F;
		}
		//左ラン
		if ((Input&PAD_INPUT_LEFT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = FALSE;
			DashFlag = TRUE;
			MoveX -= 5.25F;
		}
		//右ラン
		if ((Input&PAD_INPUT_RIGHT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = TRUE;
			DashFlag = TRUE;
			MoveX += 5.25F;
		}
		//ダッシュボタン
		if ((EdgeInput&PAD_INPUT_3) != 0) {
			int DashTimer = GetNowCount();

		}
		//ジャンプ処理
		if ((EdgeInput&PAD_INPUT_2) != 0 && JumpFlag == FALSE) {
			//ジャンプできる状態にする
			DropPower = 0;
			//ジャンプ回数を増やす
			JumpCount += 1;
			//ジャンプする
			DropPower -= 9.5F;
			//ジャンプするときの重力を決める
			Gravity = 0.5F;
		}
		if ((EdgeInput&PAD_INPUT_2) != 0 && DashFlag == TRUE && JumpFlag == FALSE) {
			DashFlag = TRUE;
			DropPower = 0;
			JumpCount += 1;
			DropPower -= 12.0F;
			Gravity = 0.5F;
		}
		//カメラのチェック
		CameraCheck();
		//落下処理
		DropPower += Gravity;
		//落下速度を移動量に追加する
		MoveY = DropPower;
		//当たり判定に基づく移動を行う
		MoveChecker(&PlayerX, &PlayerY, &DropPower, MoveX, MoveY, CHIP_SIZE, &JumpFlag, &AirFlag, &HitFlagX, &HitFlagY);
	}
	DrawChar(); Globals_Monitor();////////////////////////////////////////////////////////////////////
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	AllocConsole(); FILE* out = 0; freopen_s(&out, "CON", "w", stdout);Stdout=GetStdHandle(STD_OUTPUT_HANDLE);//デバッグ用コンソール
	init();//初期化処理
		   //メインプログラム
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
		main();
	}
	//DXライブラリを終了する
	DxLib_End(); fclose(out); FreeConsole();
	return 0;
}

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#21

投稿記事 by keito940 » 7年前

え~、左右の当たり判定がうまくいかない原因がようやくわかりました。どうやら当たり判定チェックか、マップの当たり判定のどちらかの不具合であって、
地面や上のブロックの分も勝手に補正してしまうことにあるようです。当たり判定チェックとマップの当たり判定のどの部分をいじれば、X座標だけを補正できるのでしょうか?その回答をお待ちしています。

コード:

//マップの当たり判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (GetChipParam(X, Y) == 1) {
		float blx, bty, brx, bby;
		//壁衝突確認
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;//左辺の当たり判定
		brx = (float)((int)afX / CHIP_SIZE + 1)*CHIP_SIZE;//右辺の当たり判定

		bty = (float)((int)afY / CHIP_SIZE)*CHIP_SIZE;//上辺の当たり判定
		bby = (float)((int)afY / CHIP_SIZE + 1)*CHIP_SIZE;//下辺の当たり判定
		//上辺に当たったら3を返す
		if (*MoveY > 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bty - Y - 1.0F;
			return 3;
		}
		//下辺に当たっていたら4を返す
		if (*MoveY < 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bby - Y + 1.0F;
			return 4;
		}
		if (*MoveX > 0.0F) {
			*MoveY = 0.0F;
			*MoveX = blx - X - 1.0F;
			return 1;
		}
		if (*MoveX < 0.0F) {
			*MoveY = 0.0F;
			*MoveX = brx - X + 1.0F;
			return 2;
		}
		return 4;
	}
	return 0;
}
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY) {
	float Dummy = 0.0F;
	float hsize;

	hsize = Size*0.5F;
	//上下移動成分をチェック
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize+1.0F, &Dummy, &MoveY) == 4) *DropPower = 1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize+1.0F, &Dummy, &MoveY) == 4) *DropPower = 1.0F;
		//問題がないのなら移動成分を加算する
		*Y += MoveY;
	}
	//左右移動成分をチェック

	{//左右移動成分をチェック
	{
		//左の場合
		if (MapHitCheck(*X - hsize+1.0F, *Y + hsize, &MoveX, &Dummy) == 1 && MapHitCheck(*X - hsize+1.0F, *Y - hsize, &MoveX, &Dummy) == 1 && GetChipParam(*X - Size*0.5F + 1.0F,Dummy) == 0 ) {
			*X -= 2.0F;
			*Y -= 1.0F;
			*DropPower = 0.0F;
		}
		//右の場合
		if (MapHitCheck(*X + hsize-1.0F, *Y - hsize, &MoveX, &Dummy) == 2 && MapHitCheck(*X + hsize-1.0F, *Y + hsize, &MoveX, &Dummy) == 2 && GetChipParam(*X - Size*0.5F - 1.0F, Dummy) == 0) {
			*X += 2.0F;
			*Y -= 1.0F;
			*DropPower = 0.0F;
		}
		//問題がないのなら移動成分を加算する
		*X += MoveX;
	}
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F - 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F - 1.0F) == 0) {
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else {
			*Y -= (int)1;
			*HitFlagY = FALSE;
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0.0F;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}
追記:コードを少し変えて、一応当たり判定になるようにみました。…のですが、やはりそこにも、不具合があり、壁に埋まってしまったり、地面に埋まったりしてしまいます…。どうしたら、そうならないのでしょうか…。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: キャラが壁にハマってしまう

#22

投稿記事 by ISLe » 7年前

keito940 さんが書きました:
ISLe さんが書きました: あたり判定に条件を加えるのはよろしくない。
押し戻したあともめり込んでいる状態が解消されないと移動できなくなるから。
そういう質問だからそういう理由で起きてるのだろうと予測してコードを読んでみる。
なるほど、めり込み判定をなんとかしろというわけですか。そういや、そうかもしれませんね…。
keito940 さんが書きました:まずは、めり込んでいる状態を解決してくださいと。
ということは、直前の移動フレームを実装すればいいわけですね。
どうして今まで気づかなかったのだろうか…。
そういうことではないです。
シンプルであるべきと書いたのは、考え方や手順についてです。
キャラが移動して壁にめり込むのを補正するのではなく、ただ壁にめり込んでいるのを補正するだけでいいんです。

1. まず左右にめり込んでいるか判定して、すぐに補正する
2. 次に上下にめり込んでいるか判定して、すぐに補正する
3. 最後に地面に接しているか判定して、地面に立っているかどうかフラグを設定する
という方法がもっとも汎用的ではないかと思います。

汎用的というのは、例えば、壁が動いたり、何もないところに壁が現れたり、床が消えたり、といったギミックをあとから追加しても、そのまま対応できる方法ということです。

左右と上下の判定を分けず、めり込んだ位置で上下の判定をしてしまうと、めり込んだ途端ぴょんと垂直に弾かれるような現象が発生したりします。
No.21に書かれていることはそのようなことではないでしょうか。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#23

投稿記事 by keito940 » 7年前

左右と上下の判定を分けず、めり込んだ位置で上下の判定をしてしまうと、めり込んだ途端ぴょんと垂直に弾かれるような現象が発生したりします。
No.21に書かれていることはそのようなことではないでしょうか。
言われてみれば…
ISLe さんが書きました: シンプルであるべきと書いたのは、考え方や手順についてです。
キャラが移動して壁にめり込むのを補正するのではなく、ただ壁にめり込んでいるのを補正するだけでいいんです。

1. まず左右にめり込んでいるか判定して、すぐに補正する
2. 次に上下にめり込んでいるか判定して、すぐに補正する
3. 最後に地面に接しているか判定して、地面に立っているかどうかフラグを設定する
という方法がもっとも汎用的ではないかと思います。

汎用的というのは、例えば、壁が動いたり、何もないところに壁が現れたり、床が消えたり、といったギミックをあとから追加しても、そのまま対応できる方法ということです。
こういうことでしょうかね…。押し出し処理についてもなんとなくわかってきたような感じなんですが…。
やはり不具合があるそうです。どこがおかしいか教えてください。それも違うのなら具体的なコードを出してください。

コード:

//当たり判定チェック
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY) {
	float Dummy = 0.0F;
	float hsize;

	hsize = Size*0.5F;
	//上下移動成分をチェック
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//問題がないのなら移動成分を加算する
		*Y += MoveY;
	}
    // 後に左右移動成分だけでチェック
    {
        //左下
		MapHitCheck(*X - hsize - 1.0F, *Y + hsize, &MoveX, &Dummy);
        //右下
		MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy);
        //左上
		MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy);
        //右上
		MapHitCheck(*X + hsize + 1.0F, *Y - hsize, &MoveX, &Dummy);
        //問題がないのなら移動成分を加算する
        *X += MoveX ;
    }
	//押し出し処理
	{
		//左の押し出し処理
		if (MoveX > 0) {
			//左下と左上がめり込んでいたら(つまり右壁にめり込んでいる)
			if (MapHitCheck(*X - hsize - 1.0F, *Y + hsize, &MoveX, &Dummy) == 1 && MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy) == 1) {
				//右へ押し返す
				*X += 1.0F;
			}
			//左下と右下がめり込んでいたら
			if (MapHitCheck(*X - hsize - 1.0F, *Y - hsize, &Dummy, &MoveY) == 3 && MapHitCheck(*X + hsize + 1.0F, *Y + hsize, &Dummy, &MoveY) == 3) {
				//上へ押し返す
				*Y -= 1.0F;
			}
		}
		//右の押し出し処理、以下同様
		else {
			if (MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy) == 2 && MapHitCheck(*X + hsize + 1.0F, *Y - hsize, &MoveX, &Dummy) == 2) {
				*X -= 1.0F;
			}
			if (MapHitCheck(*X - hsize - 1.0F, *Y - hsize, &Dummy, &MoveY) == 3 && MapHitCheck(*X + hsize + 1.0F, *Y + hsize, &Dummy, &MoveY) == 3) {
				*Y -= 1.0F;
			}
		}
	}
	{
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F - 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F - 1.0F) == 0) {
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else {
			*Y -= (int)1;
			*HitFlagY = FALSE;
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0.0F;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#24

投稿記事 by keito940 » 7年前

ソースコードを更新しました。

コード:

//当たり判定チェック
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY) {
	float Dummy = 0.0F;
	float hsize;

	hsize = Size*0.5F;
	//上下移動成分をチェック
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//問題がないのなら移動成分を加算する
		*Y += MoveY;
	}
    // 後に左右移動成分だけでチェック
    {
        //左下
		MapHitCheck(*X - hsize - 1.0F, *Y + hsize, &MoveX, &Dummy);
        //右下
		MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy);
        //左上
		MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy);
        //右上
		MapHitCheck(*X + hsize + 1.0F, *Y - hsize, &MoveX, &Dummy);
        //問題がないのなら移動成分を加算する
        *X += MoveX ;
    }
	//押し出し処理
	{
		//左の押し出し処理
		if (MoveX > 0) {
			//左下と左上がめり込んでいたら(つまり右壁にめり込んでいる)
			if (MapHitCheck(*X - hsize - 1.0F, *Y + hsize, &MoveX, &Dummy) == 1 && MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy) == 1 && GetChipParam(*X - hsize + 1.0F, Dummy) == 0) {
				//右へ押し返す
				MoveX += 5.0F;
			}
			//左下と右下がめり込んでいたら(地面にめり込んでいる)
			if (MapHitCheck(*X - hsize - 1.0F, *Y - hsize, &MoveX, &Dummy) == 3 && MapHitCheck(*X + hsize + 1.0F, *Y + hsize, &Dummy, &MoveY) == 3 && GetChipParam(*X - hsize + 1.0F, Dummy) == 0) {
				//上へ押し返す
				MoveY -= 1.0F;
			}
			//左下と左上と右下がめり込んでいたら(左上の壁にめり込んでいる)
			//if(MapHitCheck(*X-hsize-1.0F,*Y-hsize,&MoveX,&Dummy))いま書き込み中
		}
		//右の押し出し処理、以下同様
		else {
			if (MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy) == 2 && MapHitCheck(*X + hsize + 1.0F, *Y - hsize, &MoveX, &Dummy) == 2) {
				MoveX -= 5.0F;
			}
			if (MapHitCheck(*X - hsize - 1.0F, *Y - hsize, &MoveX, &Dummy) == 3 && MapHitCheck(*X + hsize + 1.0F, *Y + hsize, &MoveX, &Dummy) == 3) {
				MoveY -= 1.0F;
			}
		}
	}
	{
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F - 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F - 1.0F) == 0) {
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else {
			*Y -= (int)1;
			*HitFlagY = FALSE;
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0.0F;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#25

投稿記事 by keito940 » 7年前

どうやら当たり判定のGetChipParamにも不具合らしきものがあったようです。

コード:

//当たり判定チェック
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY) {
	float Dummy = 0.0F;
	float hsize;

	hsize = Size*0.5F;
	//上下移動成分をチェック
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//問題がないのなら移動成分を加算する
		*Y += MoveY;
	}
    // 後に左右移動成分だけでチェック
    {
        //左下
		MapHitCheck(*X - hsize - 1.0F, *Y + hsize, &MoveX, &Dummy);
        //右下
		MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy);
        //左上
		MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy);
        //右上
		MapHitCheck(*X + hsize + 1.0F, *Y - hsize, &MoveX, &Dummy);
        //問題がないのなら移動成分を加算する
        *X += MoveX ;
    }
	//押し出し処理
	{
		//左の押し出し処理
		if (MoveX > 0) {
			//左下と左上がめり込んでいたら(つまり右壁にめり込んでいる)
			if (MapHitCheck(*X - hsize - 1.0F, *Y + hsize, &MoveX, &Dummy) == 1 && MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy) == 1 && GetChipParam(*X - hsize + 1.0F, Dummy) != 0) {
				//右へ押し返す
				*X += 5.0F;
				MoveX = 0.0F;
			}
			//左下と右下がめり込んでいたら(地面にめり込んでいる)
			if (MapHitCheck(*X - hsize - 1.0F, *Y - hsize, &Dummy, &*Y) == 3 && MapHitCheck(*X + hsize + 1.0F, *Y + hsize, &Dummy, &*Y) == 3 && GetChipParam(*X - hsize + 1.0F, Dummy) != 0) {
				//上へ押し返す
				*Y -= 1.0F;
			}
			//左下と左上と右下がめり込んでいたら(左上の壁にめり込んでいる)
			//if(MapHitCheck(*X-hsize-1.0F,*Y-hsize,&MoveX,&Dummy)==1&&MapHitCheck(*X-hsize-1.0F,&MoveX,&Dummy)==1&&MapHitCheck())いま書き込み中
			//右下へ押し返す
		}
		//右の押し出し処理、以下同様
		else {
			if (MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy) == 2 && MapHitCheck(*X + hsize + 1.0F, *Y - hsize, &MoveX, &Dummy) == 2 && GetChipParam(*X - hsize - 1.0F, Dummy) != 0) {
				*X -= 5.0F;
				MoveX = 0.0F;
			}
			if (MapHitCheck(*X - hsize - 1.0F, *Y - hsize, &Dummy, &*Y) == 3 && MapHitCheck(*X + hsize + 1.0F, *Y + hsize, &Dummy, &*Y) == 3 && GetChipParam(*X - hsize - 1.0F, Dummy) != 0) {
				*Y -= 1.0F;
			}
		}
	}
	{
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F - 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F - 1.0F) == 0) {
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else {
			*Y -= (int)1;
			*HitFlagY = FALSE;
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0.0F;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}

cattail
記事: 75
登録日時: 10年前

Re: キャラが壁にハマってしまう

#26

投稿記事 by cattail » 7年前

「めり込んでいない時の位置」をリアルタイムで保存しておくといいですよ。
めり込んだら、その位置に戻すだけでいいです。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#27

投稿記事 by keito940 » 7年前

ええっ!?そうだったんですか!?でも、やっぱりめり込みが起こってしまうようです…。何かが間違っているのですが、どこが間違っているのでしょうか…。
後々(アクションゲームでは)重要となるかもしれないので直前のフレームを実装してみました。まあ、これが解決すれば当分は大丈夫でしょうかね…?

コード:

int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY, float Size, char *JumpFlag, char *AirFlag, char *HitFlagX, char *HitFlagY) {
	float Dummy = 0.0F;
	float hsize;
	//直前のフレームを保存する
	float Prev_X = *X;
	float Prev_Y = *Y;
	hsize = Size*0.5F;
	//上下移動成分をチェック
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize, &Dummy, &MoveY) == 3) *DropPower = 0.0F, *HitFlagY = TRUE;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) *DropPower = -1.0F;
		//フレームを更新する
		Prev_Y = MoveY+*Y;
		//問題がないのなら移動成分を加算する
		*Y += MoveY;
	}
    // 後に左右移動成分だけでチェック
    {
        //左下
		MapHitCheck(*X - hsize - 1.0F, *Y + hsize, &MoveX, &Dummy);
        //右下
		MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy);
        //左上
		MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy);
        //右上
		MapHitCheck(*X + hsize + 1.0F, *Y - hsize, &MoveX, &Dummy);
		//フレームを更新する
		Prev_X = MoveX+*X;
        //問題がないのなら移動成分を加算する
        *X += MoveX;
    }
	//押し出し処理
	float SaveX,SaveY;
	SaveX = 0.0F;
	SaveY = 0.0F;
	if (GetChipParam(*X - Size*0.5F + 1.0F, Dummy) == 0 || GetChipParam(*X + Size*0.5F - 1.0F, Dummy) == 0) {
		//めり込んでいないときの座標を保存
		SaveX = Prev_X;
		SaveY = Prev_Y;
	}
	else {
		//めり込んだら座標を書き換える
		*X = SaveX;
		*Y = SaveY;
	}
	{
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(Prev_X - Size*0.5F, Prev_Y + Size*0.5F - 1.0F) == 0 && GetChipParam(Prev_X + Size*0.5F, Prev_Y + Size*0.5F - 1.0F) == 0) {
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else {
			*Y = SaveY;
			*HitFlagY = FALSE;
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0.0F;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}

cattail
記事: 75
登録日時: 10年前

Re: キャラが壁にハマってしまう

#28

投稿記事 by cattail » 7年前

僕の場合ですが、
描画してから衝突を調査してはいけませんよ。
描画する前に仮想座標で衝突を調査して大丈夫なら描画します。

例えばキーで移動する場合、
キーが押される前にxyz座標をold_keyに確保します。ここでは衝突していませんね。
キーが押されたら移動先xyz座標を仮想座標として衝突調査を行います。
衝突していたら、old_keyに戻して描画します。
xだけが衝突していてもxyz全てを戻すことが必要です。

一旦衝突させたままにしてしまうと、衝突していない座標を探すのが難しくなります。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#29

投稿記事 by keito940 » 7年前

cattailさん、あなたのアドバイスは実に頼りになるのですが、当のコードの方はうまく行っていません。(地面に埋まってしまったり、右にしか動けない状態になったりします。)具体的にどう書けば、ちゃんとした当たり判定になるのでしょうか?教えてください。

コード:

//マップの当たり判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (GetChipParam(X, Y) == 1) {
		float blx, bty, brx, bby;
		//壁衝突確認
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;//左辺の当たり判定
		brx = (float)((int)afX / CHIP_SIZE + 1)*CHIP_SIZE;//右辺の当たり判定

		bty = (float)((int)afY / CHIP_SIZE)*CHIP_SIZE;//上辺の当たり判定
		bby = (float)((int)afY / CHIP_SIZE + 1)*CHIP_SIZE - 1.0F;//下辺の当たり判定
		//上辺に当たったら3を返す
		if (*MoveY > 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bty - Y - 1.0F;
			return 3;
		}
		//下辺に当たっていたら4を返す
		if (*MoveY < 0.0F) {
			*MoveX = 0.0F;
			*MoveY = bby - Y + 1.0F;
			return 4;
		}
		//左辺にあたっていたら1を返す
		if (*MoveX > 0.0F) {
			*MoveY = 0.0F;
			*MoveX = blx - X - 1.0F;
			return 1;
		}
		//右辺にあたっていたら2を返す
		if (*MoveX < 0.0F) {
			*MoveY = 0.0F;
			*MoveX = brx - X + 1.0F;
			return 2;
		}
		return 4;
	}
	return 0;
}
//当たり判定チェック
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY,float *SaveX, float *SaveY, float Size, char *JumpFlag, char *AirFlag) {
	float Dummy = 0.0F;
	float hsize;
	//直前のフレームを保存する
	float Prev_X = *X;
	float Prev_Y = *Y;
	hsize = Size*0.5F;
	//上下移動成分をチェックし、めり込んでいたらそれを修正する
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize - 1.0F, &Dummy, &MoveY) == 3) *X = *SaveX, *Y = *SaveY, *DropPower = 0.0F;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize - 1.0F, &Dummy, &MoveY) == 3) *X = *SaveX, *Y = *SaveY, *DropPower = 0.0F;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) *X = *SaveX, *Y = *SaveY, *DropPower = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) *X = *SaveX, *Y = *SaveY, *DropPower = -1.0F;
		//フレームを更新する
		Prev_Y = MoveY+*Y;
		//問題がないのなら移動成分を加算する
		*Y += MoveY;
	}
    // 後に左右移動成分だけでチェック
    {
        //左下
		if(MapHitCheck(*X - hsize - 1.0F, *Y + hsize, &MoveX, &Dummy)==1)*X = *SaveX, *Y = *SaveY;
        //右下
		if(MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy)==2)*X = *SaveX, *Y = *SaveY;
        //左上
		if(MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy)==1)*X = *SaveX, *Y = *SaveY;
        //右上
		if(MapHitCheck(*X + hsize + 1.0F, *Y - hsize, &MoveX, &Dummy)==2)*X = *SaveX, *Y = *SaveY;
		//フレームを更新する
		Prev_X = MoveX+*X;
        //問題がないのなら移動成分を加算する
        *X += MoveX;
    }
	{
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F - 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F - 1.0F) == 0) {
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else {
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0.0F;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}
メインプログラム

コード:

int main(void) {
	//マップの描画
	DrawMap(); system("cls");
	//カウント値を更新する
	Time = GetNowCount(); printf("Time=%d\n\n", Time);
	while (GetNowCount() - Time < 1000 / 60) { Sleep(1); }
	//入力状態を更新する
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		//チョン押しを確認する
		EdgeInput = i & ~Input;
		Input = i;
	}
	//ダッシュトリガー確認
	if ((Input&PAD_INPUT_1) == 0) {
		DashFlag = FALSE;
	}
	if (JumpCount >= 2) {
		JumpFlag = TRUE;
	}
	//移動処理
	{
		float MoveX, MoveY;
		float SaveX, SaveY;
		MoveX = 0.0F;
		MoveY = 0.0F;
		//キーが押される前の座標
		SaveX = PlayerX;
		SaveY = PlayerY;
		//左に移動
		if ((Input&PAD_INPUT_LEFT) != 0) {
			dir = FALSE;
			MoveX -= 5.0F;
		}
		//右に移動
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			dir = TRUE;
			MoveX += 5.0F;
		}
		//左ラン
		if ((Input&PAD_INPUT_LEFT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = FALSE;
			DashFlag = TRUE;
			MoveX -= 5.25F;
		}
		//右ラン
		if ((Input&PAD_INPUT_RIGHT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
			dir = TRUE;
			DashFlag = TRUE;
			MoveX += 5.25F;
		}
		//ダッシュボタン
		if ((EdgeInput&PAD_INPUT_3) != 0) {
			int DashTimer = GetNowCount();

		}
		//ジャンプ処理
		if ((EdgeInput&PAD_INPUT_2) != 0 && JumpFlag == FALSE) {
			//ジャンプできる状態にする
			DropPower = 0;
			//ジャンプ回数を増やす
			JumpCount += 1;
			//ジャンプする
			DropPower -= 9.5F;
			//ジャンプするときに重力を決める(空中浮遊防止の為)
			Gravity = 0.5F;
		}
		if ((EdgeInput&PAD_INPUT_2) != 0 && DashFlag == TRUE && JumpFlag == FALSE) {
			DashFlag = TRUE;
			DropPower = 0;
			JumpCount += 1;
			DropPower -= 12.0F;
			Gravity = 0.5F;
		}
		//カメラのチェック
		CameraCheck();
		//落下処理
		DropPower += Gravity;
		//落下速度を移動量に追加する
		MoveY = DropPower;
		//当たり判定に基づく移動を行う
		MoveChecker(&PlayerX, &PlayerY, &DropPower, MoveX, MoveY, &SaveX, &SaveY, CHIP_SIZE, &JumpFlag, &AirFlag);
	}
	DrawChar(); Globals_Monitor();////////////////////////////////////////////////////////////////////
}

cattail
記事: 75
登録日時: 10年前

Re: キャラが壁にハマってしまう

#30

投稿記事 by cattail » 7年前

//キーが押される前の座標
SaveX = PlayerX;
SaveY = PlayerY;

ここにMoveCheckerを入れて動くようにしたらいいのではないですか?

//左に移動
if ((Input&PAD_INPUT_LEFT) != 0) {

間違っていたらごめんなさいね。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#31

投稿記事 by keito940 » 7年前

しかし、今度は、キャラが中央にとどまったままのようです。

cattail
記事: 75
登録日時: 10年前

Re: キャラが壁にハマってしまう

#32

投稿記事 by cattail » 7年前

//キーが押される前の座標
SaveX = PlayerX;
SaveY = PlayerY;

if(MoveChecker() == 衝突している){
以下移動ルーチンには行かずreturn;
}

//左に移動
if ((Input&PAD_INPUT_LEFT) != 0) {

としたら、どうでしょうか?

すみませんがMoveChecker内などは自分で変更してね。
また、分かりやすくするために、
右方向だけのプログラムに変更してみてください。
衝突したら「衝突した!」と画面に出して下さい。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#33

投稿記事 by keito940 » 7年前

やっぱり中央にとどまったままのようです。しかも、内部処理上では落下したままなので困っています。
当たり判定

コード:

//当たり判定チェック
int MoveChecker(float *X, float *Y, float *DropPower, float MoveX, float MoveY,float *SaveX, float *SaveY, float Size, char *JumpFlag, char *AirFlag) {
	float Dummy = 0.0F;
	float hsize;
	//直前のフレームを保存する
	float Prev_X = *X;
	float Prev_Y = *Y;
	hsize = Size*0.5F;
	//上下移動成分をチェックし、めり込んでいたらそれを修正する
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize - 1.0F, &Dummy, &MoveY) == 3) return 1;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize - 1.0F, &Dummy, &MoveY) == 3) return 1;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) return 2;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize + 1.0F, &Dummy, &MoveY) == 4) return 2;
		//フレームを更新する
		Prev_Y = MoveY+*Y;
		//問題がないのなら移動成分を加算する
		*Y += MoveY;
	}
    // 後に左右移動成分だけでチェック
    {
        //左下
		if(MapHitCheck(*X - hsize - 1.0F, *Y + hsize, &MoveX, &Dummy)==1) return 3;
        //右下
		if(MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy)==2) return 3;
        //左上
		if(MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy)==1) return 3;
        //右上
		if(MapHitCheck(*X + hsize + 1.0F, *Y - hsize, &MoveX, &Dummy)==2) return 3;
		//フレームを更新する
		Prev_X = MoveX+*X;
        //問題がないのなら移動成分を加算する
        *X += MoveX;
    }
	{
		//空中にいるなら、空中にいるとみなす
		if (GetChipParam(*X - Size*0.5F, *Y + Size*0.5F - 1.0F) == 0 && GetChipParam(*X + Size*0.5F, *Y + Size*0.5F - 1.0F) == 0) {
			*AirFlag = TRUE;
		}
		//もし足場に着地したら埋まりこみを防止してからジャンプ回数をリセットする
		else {
			*AirFlag = FALSE;
			JumpCount = 0;
			Gravity = 0.0F;
			*JumpFlag = FALSE;
		}
		return 0;
	}
}
メインプログラム

コード:

	//移動処理
	{
		float MoveX, MoveY;
		float SaveX, SaveY;
		MoveX = 0.0F;
		MoveY = 0.0F;
		//キーが押される前の座標
		SaveX = PlayerX;
		SaveY = PlayerY;
		//当たり判定をチェックし、そこで
		if (MoveChecker(&PlayerX, &PlayerY, &DropPower, MoveX, MoveY, &SaveX, &SaveY, CHIP_SIZE, &JumpFlag, &AirFlag) == 1) {
			PlayerX = SaveX;
			PlayerY = SaveY;
			DropPower = 0.0F;
		}
		else if (MoveChecker(&PlayerX, &PlayerY, &DropPower, MoveX, MoveY, &SaveX, &SaveY, CHIP_SIZE, &JumpFlag, &AirFlag) == 2){
			PlayerX = SaveX;
			PlayerY = SaveY;
		}
		else if (MoveChecker(&PlayerX, &PlayerY, &DropPower, MoveX, MoveY, &SaveX, &SaveY, CHIP_SIZE, &JumpFlag, &AirFlag) == 3) {
			PlayerX = SaveX;
			PlayerY = SaveY;
			printf("衝突なう。");
		}
		else {
			//左に移動
			/*if ((Input&PAD_INPUT_LEFT) != 0) {
				dir = FALSE;
				MoveX -= 5.0F;
			}*/
			//右に移動
			if ((Input&PAD_INPUT_RIGHT) != 0) {
				dir = TRUE;
				MoveX += 5.0F;
			}
			//左ラン
			/*if ((Input&PAD_INPUT_LEFT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
				dir = FALSE;
				DashFlag = TRUE;
				MoveX -= 5.25F;
			}*/
			//右ラン
			if ((Input&PAD_INPUT_RIGHT) != 0 && (Input&PAD_INPUT_1) != 0 && JumpFlag == FALSE) {
				dir = TRUE;
				DashFlag = TRUE;
				MoveX += 5.25F;
			}
			//ダッシュボタン
			if ((EdgeInput&PAD_INPUT_3) != 0) {
				int DashTimer = GetNowCount();
			}
			//ジャンプ処理
			if ((EdgeInput&PAD_INPUT_2) != 0 && JumpFlag == FALSE) {
				//ジャンプできる状態にする
				DropPower = 0;
				//ジャンプ回数を増やす
				JumpCount += 1;
				//ジャンプする
				DropPower -= 9.5F;
				//ジャンプするときに重力を決める(空中浮遊防止の為)
				Gravity = 0.5F;
			}
			if ((EdgeInput&PAD_INPUT_2) != 0 && DashFlag == TRUE && JumpFlag == FALSE) {
				DashFlag = TRUE;
				DropPower = 0;
				JumpCount += 1;
				DropPower -= 12.0F;
				Gravity = 0.5F;
			}
		}

cattail
記事: 75
登録日時: 10年前

Re: キャラが壁にハマってしまう

#34

投稿記事 by cattail » 7年前

>内部処理上では落下したままなので
内部処理上で、衝突判定をして下さい。
ようやく見えてきましたね。

内部処理上と公開されているプログラムが別になっているのは好ましくありません。
今あなたが制作しているプログラムは一旦棚上げして、
四角い部屋にキャラクターを置き、右に移動させ、壁に当たったら、止まる。
こんなプログラムをいちから作ってみてはいかがでしょう?
それを、今回のプログラムに生かすのです。
どうでしょうか?

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#35

投稿記事 by keito940 » 7年前

了解しました。
今作っているところです。
追記:最終的には四方の衝突判定を作るわけですよね?

cattail
記事: 75
登録日時: 10年前

Re: キャラが壁にハマってしまう

#36

投稿記事 by cattail » 7年前

ごめんなさい。
もう、返事は来ないと思っていたんですよ。
keito940さん、ほんとにやる気ですか?
その道は険しいですよ。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#37

投稿記事 by keito940 » 7年前

cattail さんが書きました: ほんとにやる気ですか?その道は険しいですよ。
cattailさん、そのつもりです!!この場面で何か困ったことがあったのなら、質問をしますので!!

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#38

投稿記事 by keito940 » 7年前

衝突のプログラムを組み始めたのはいいのですが、DXライブラリが初期化と同時に勝手に終了して衝突プログラムに入りません。
どういうことなんでしょうか…。(かんたんなミスかもしれませんが…)

コード:

//衝突のテストプログラム
//アクションゲームのテストシステムを作る前に、
//めり込み防止のアルゴリズムを初心者なりに作らざるをえない。
//Create 2017/02/10
#include "DxLib.h"

#define SCREEN_WIDTH (320)		//画面の横幅
#define SCREEN_HEIGHT (240)		//画面の縦幅
#define CHIP_SIZE (16)			//チップのサイズ
#define MAP_WIDTH (SCREEN_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (SCREEN_HEIGHT/CHIP_SIZE)
HANDLE Stdout;

char MapData[MAP_HEIGHT][MAP_WIDTH]
{
	0,0,0,0,0, 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,0,0,0, 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,0,0,0, 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,0,0,0, 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,0,0,0, 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,0,0,0, 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,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,
};

float PlayerX, PlayerY;
float SaveX, SaveY;
float MoveX, MoveY;

int Input, EdgeInput;
int FreamStartTime;
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY);
int CharMove(float *X, float *Y, float MoveX, float MoveY, float Size);
int MapChipParam(int X, int Y);

int MapChipParam(int X, int Y) {
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;
	
	return 0;
}
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (MapChipParam(X, Y) == 1) {
		float blx;
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;
		if (*MoveX > 0.0F) {
			//移動量を補正する
			*MoveX = blx - X - 1.0F;
			//右の壁に当たったと判定する
			return 1;
		}
		return 4;
	}
	return 0;
}
int CharMove(float *X, float *Y, float MoveX, float MoveY, float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F;
	{
		if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1) return 1;
		if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1) return 1;
		*X = MoveX;
	}
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE),SetGraphMode(320,240,32),printf("初期化しています…"); 
	if (DxLib_Init() == -1) { return -1; }
	PlayerX = 0.0F, PlayerY = 214.0F, MoveX = 0.0F, MoveY = 0.0F;
	Input = 0, EdgeInput = 0;
	return 0;
}
int main(void) {
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
		SaveX = PlayerX;
		SaveY = PlayerY;
	if (CharMove(&PlayerX, &PlayerY, MoveX, MoveY, CHIP_SIZE) == 1) {
		PlayerX = SaveX;
		PlayerY = SaveY;
		printf("衝突しました。");
		}
	else if (CharMove(&PlayerX, &PlayerY, MoveX, MoveY, CHIP_SIZE) == 0) {
		{
			//今はただ右に行きます!
			if ((Input&PAD_INPUT_RIGHT) != 0) MoveX += 5.0F;
		}
	}
	//マップ描画
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
				DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	AllocConsole(); FILE* out = 0; freopen_s(&out, "CON", "w", stdout); Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
	init();
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen == 0) {
		main();
	}
	DxLib_End(); fclose(out); FreeConsole();
	return 0;
}

Math

Re: キャラが壁にハマってしまう

#39

投稿記事 by Math » 7年前

ClearDrawScreen に()が抜けてる

コード:

//    while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 ){printf("Loop begin…\t");
    while(ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen == 0) {printf("Loop begin…\t");
       main();

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#40

投稿記事 by keito940 » 7年前

頑張って衝突プログラムのコードを書いています。添付した画像のようになって、メインループ開始と出たまま動きません。どういうことなんでしょうか?
コードは以下のとおりです。

コード:

//衝突のテストプログラム
//アクションゲームのテストシステムを作る前に、
//めり込み防止のアルゴリズムを初心者なりに作らざるをえない。
//Create 2017/02/10
#include "DxLib.h"

#define SCREEN_WIDTH (320)		//画面の横幅
#define SCREEN_HEIGHT (240)		//画面の縦幅
#define CHIP_SIZE (16)			//チップのサイズ
#define MAP_WIDTH (SCREEN_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (SCREEN_HEIGHT/CHIP_SIZE)
HANDLE Stdout;

char MapData[MAP_HEIGHT][MAP_WIDTH]
{
	0,0,0,0,0, 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,0,0,0, 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,0,0,0, 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,0,0,0, 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,0,0,0, 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,0,0,0, 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,0,0,0, 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,
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
};

float PlayerX, PlayerY;
float SaveX, SaveY;
float MoveX, MoveY;

int Input, EdgeInput;
int FreamStartTime;
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY);
int CharMove(float *X, float *Y, float MoveX, float MoveY, float Size);
int MapChipParam(float X, float Y);

int MapChipParam(float X, float Y) {
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;
	
	return MapData[y][x];
}
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (MapChipParam(X, Y) == 1) {
		float blx;
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;
		if (*MoveX > 0.0F) {
			//移動量を補正する
			*MoveX = blx - X - 1.0F;
			//右の壁に当たったと判定する
			return 1;
		}
		return 4;
	}
	return 0;
}
int CharMove(float *X, float *Y, float MoveX, float MoveY, float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F;
	{
		if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1) return 1;
		if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1) return 1;
		*X += MoveX;
	}
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE),SetGraphMode(320,240,32),printf("初期化しています…"); 
	if (DxLib_Init() == -1) { return -1; }
	PlayerX = 8.0F, PlayerY = 214.0F, MoveX = 0.0F, MoveY = 0.0F;
	Input = 0, EdgeInput = 0;
	return 0;
}
int main(void) {
	system("cls");
	printf("メインループ開始");
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	SaveX = PlayerX;
	SaveY = PlayerY;
	int i = CharMove(&PlayerX, &PlayerY, MoveX, MoveY, CHIP_SIZE);
	if (i == 1) {
		PlayerX = SaveX;
		PlayerY = SaveY;
		printf("\n衝突しました。");
		}
	else if (i = 0) {
		{
			//今はただ右に行きます!
			if ((Input&PAD_INPUT_RIGHT) != 0) MoveX += 5.0F;
		}
	}
	//マップ描画
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
				DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	AllocConsole(); FILE* out = 0; freopen_s(&out, "CON", "w", stdout); Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
	init();
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		main();
	}
	DxLib_End(); fclose(out); FreeConsole();
	return 0;
}
添付ファイル
質問用.PNG
質問用.PNG (1011 バイト) 閲覧数: 22154 回

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: キャラが壁にハマってしまう

#41

投稿記事 by みけCAT » 7年前

109行目のif文の条件式が代入式になっており、常に偽です。
このような単純なミスを早期発見するため、コンパイラの警告レベルを最大にすることをおすすめします。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#42

投稿記事 by keito940 » 7年前

どうやって、コンパイラの警告レベルを最大にするのですか?
Visual Studio 2015の場合を教えて下さい。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: キャラが壁にハマってしまう

#43

投稿記事 by みけCAT » 7年前

Visual Studio 2015はインストールしてないのでわかりませんが、
プロジェクトのプロパティを開いて「警告レベル」を「レベル 4」にする…みたいな感じだと思います。

C++のコードレビューで使いたい、コードの品質を向上させる3つの方法 - 小さい頃はエラ呼吸
GESブログ VisualStudioを少しでも使いこなそう~ビルドの構成編~その2
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)


Math

Re: キャラが壁にハマってしまう

#45

投稿記事 by Math » 7年前

>Visual Studio 2015はインストールしてないのでわかりませんが
Win32関連はVS2008と殆んど同じですよ。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#46

投稿記事 by keito940 » 7年前

おかげさまで無事に解決しましたが、今度はマップがコードのようにならず、No.40の画像のようになってしまいます。
どうやれば解決できるのしょうか?アクションゲームのコードでは、普通にコード通りになってました。

コード:

//衝突のテストプログラム
//アクションゲームのテストシステムを作る前に、
//めり込み防止のアルゴリズムを初心者なりに作らざるをえない。
//Create 2017/02/10
#include "DxLib.h"

#define SCREEN_WIDTH (320)		//画面の横幅
#define SCREEN_HEIGHT (240)		//画面の縦幅
#define CHIP_SIZE (16)			//チップのサイズ
#define MAP_WIDTH (SCREEN_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (SCREEN_HEIGHT/CHIP_SIZE)
HANDLE Stdout;

char MapData[MAP_HEIGHT][MAP_WIDTH]
{
	0,0,0,0,0, 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,0,0,0, 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,0,0,0, 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,0,0,0, 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,0,0,0, 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,0,0,0, 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,0,0,0, 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,
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
};

float PlayerX, PlayerY;
float SaveX, SaveY;
float MoveX, MoveY;

int Input, EdgeInput;
int FreamStartTime;
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY);
int CharMove(float *X, float *Y, float MoveX, float MoveY, float Size);
int MapChipParam(float X, float Y);

int MapChipParam(float X, float Y) {
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;
	
	return MapData[y][x];
}
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (MapChipParam(X, Y) == 1) {
		float blx;
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;
		if (*MoveX > 0.0F) {
			//移動量を補正する
			*MoveX = blx - X - 1.0F;
			//右の壁に当たったと判定する
			return 1;
		}
		return 4;
	}
	return 0;
}
int CharMove(float *X, float *Y, float MoveX, float MoveY, float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F;
	{
		if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1) return 1;
		if (MapHitCheck(*X - hsize, *Y + hsize, &MoveX, &Dummy) == 1) return 1;
		*X += MoveX;
	}
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE),SetGraphMode(320,240,32),printf("初期化しています…"); 
	if (DxLib_Init() == -1) { return -1; }
	PlayerX = 8.0F, PlayerY = 214.0F, MoveX = 0.0F, MoveY = 0.0F;
	Input = 0, EdgeInput = 0;
	return 0;
}
int main(void) {
	system("cls");
	printf("メインループ開始");
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	SaveX = PlayerX;
	SaveY = PlayerY;
	int i = CharMove(&PlayerX, &PlayerY, MoveX, MoveY, CHIP_SIZE);
	if (i != 0) {
		PlayerX = SaveX;
		PlayerY = SaveY;
		printf("\n衝突しました。");
		}
	else{
		{
			//今はただ右に行きます!
			if ((Input&PAD_INPUT_RIGHT) != 0) MoveX += 5.0F;
		}
	}
	//マップ描画
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
				DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	AllocConsole(); FILE* out = 0; freopen_s(&out, "CON", "w", stdout); Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
	init();
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		main();
	}
	DxLib_End(); fclose(out); FreeConsole();
	return 0;
}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: キャラが壁にハマってしまう

#47

投稿記事 by みけCAT » 7年前

keito940 さんが書きました:おかげさまで無事に解決しましたが、今度はマップがコードのようにならず、No.40の画像のようになってしまいます。
どうやれば解決できるのしょうか?
デバッグをすればいいでしょう。
少しは自分で考える気ありますか?
マップの表示がおかしいのだから、まずはマップの表示をしている部分をチェックしましょう。 (もちろん問題は他の部分にあるかもしれませんが)

↓自分で考える気が無いのであれば、BASE64デコードして読んでください。
► スポイラーを表示
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Math

Re: キャラが壁にハマってしまう

#48

投稿記事 by Math » 7年前

頑張れ!VS2015で
”DrawBox”があいまいです

とでますよ!DrawBoxの定義は!

Math

Re: キャラが壁にハマってしまう

#49

投稿記事 by Math » 7年前

予想だけどこの辺りは大丈夫?

コード:

	printf("マップ描画\n\n");
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
					DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

cattail
記事: 75
登録日時: 10年前

Re: キャラが壁にハマってしまう

#50

投稿記事 by cattail » 7年前

わー、たくさんの方に助けられて良かったね。
がんばって下さい!
応援していますよ。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#51

投稿記事 by keito940 » 7年前

右の当たり判定はなんとか完成させ、右へ動かすということはできました。…ですが、左の当たり判定を入れた途端にめりこんでしまいます。
それを回避しようとして、else if文を使って見たのですが、右で衝突して左に行こうとするとめり込んでしまう上に壁の中でしか動けなくなってしまいます。
今現在の当たり判定のアルゴリズム

コード:

int CharMove(float *X, float *Y, float MoveX, float MoveY, float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F;
	{
		if (MapHitCheck(*X + hsize + 5.0F, *Y - hsize, &MoveX, &Dummy) == 1) return 1;
		if (MapHitCheck(*X - hsize - 5.0F, *Y - hsize, &MoveX, &Dummy) == 2) return 2;
		if (MapHitCheck(*X + hsize + 5.0F, *Y + hsize, &MoveX, &Dummy) == 1) return 1;
		if (MapHitCheck(*X - hsize - 5.0F, *Y - hsize, &MoveX, &Dummy) == 2) return 2;
		*X += MoveX;
	}
	return 0;
}
問題のコードです

コード:

int main(void) {
	FreamStartTime = GetNowCount();
	while (GetNowCount() - FreamStartTime < 1000 / 60) { Sleep(1); }
	system("cls");
	printf("メインループ開始");
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	SaveX = PlayerX;
	SaveY = PlayerY;
	int i = CharMove(&PlayerX, &PlayerY, MoveX, MoveY, CHIP_SIZE);
	if (i == 1) {
		MoveX = 0.0F;
		MoveY = 0.0F;
		PlayerX = SaveX + 1.0F;
		PlayerY = SaveY;
		printf("\n衝突しました。");
		}
	else if (i == 2) {
		MoveX = 0.0F;
		MoveY = 0.0F;
		PlayerX = SaveX - 1.0F;
		PlayerY = SaveY;
	}
	else if (i == 0){
	{
		MoveX = 0.0F;
		MoveY = 0.0F;

		//今はただ右に行きます!
		if ((Input&PAD_INPUT_RIGHT) != 0) MoveX += 5.0F;
		if ((Input&PAD_INPUT_LEFT) != 0) MoveX -= 5.0F;
		}
	}
追記:ちゃんとコード通りに表示してくれるようになりました。

アバター
usao
記事: 1889
登録日時: 11年前

Re: キャラが壁にハマってしまう

#52

投稿記事 by usao » 7年前

オフトピック
一旦,問題を簡単にして原理確認する(?)ことになったようですが…
だったら,せっかくだからとことん簡単に書いてみてはどうでしょう.
右移動と左移動とで最初から同じ関数にまとめようとしてうまくいっていない感じなのであれば,
とりあえずまとめることは一旦忘れて,最初は全く別々に書いてみたらどうでしょう.
(コードを纏めるようなことについては,{間違っていた点,改善方法,…}が明らかになってから,後からやればいいのでは.)

コード:

//キャラクタの右移動処理
//(*pX,Y)から右にMoveRightだけ進めるかどうかを調べて,
//・進めるならば,*pX を *pX + MoveRight に更新する.
//・MoveRightだけ移動するのが壁的に無理な場合は,壁ぎりぎりまで進んだ位置に *pX を更新する
//処理結果として, *pXの値を更新した場合は1を,値が変化しなかった場合は0を返す.
int MoveCharToRight( float *pX, float Y, float MoveRight, float Size )
{
  ...
  //MapHitCheck()という既存関数も一旦忘れて,ここに右方向に必要な判定をダイレクトに書く
}

//キャラクタの左移動処理
int MoveCharToLeft( float *pX, float Y, float MoveLeft, float Size )
{
  ...
}
とか.

cattail
記事: 75
登録日時: 10年前

Re: キャラが壁にハマってしまう

#53

投稿記事 by cattail » 7年前

だいぶ良くなってきたようですね!
おかしな部分がある時、簡略化は必須ですよ。
usaoさんの言う右だけ左だけのルーチンにすると分かってくるかもです。
頭の理論でずーっと考えてないで、なんでもすぐにやってみる!
僕はそれが一番良かったです。
トライアンドエラーを何百回何千回と繰り返しました。
きっとできる。なんでも、そういうことだと思います。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#54

投稿記事 by keito940 » 7年前

コードを分離したら効率よく左右の当たり判定ができましたが、ジャンプができない上に地面に少し埋まりこんでから「着地しました。」と出ます。
どうすればいいんでしょうか?
当たり判定アルゴリズム

コード:

int MoveCharRight(float *X, float Y, float *MoveX, float Size) {
	float blx;
	float afX = *X + *MoveX;
	blx = (float)((int)afX / Size)*Size;
	//すすめるなら、更新する
	if (MapChipParam(afX + *MoveX , Y) == 0) {
		*X = afX;
		return 1;
	}
	//進めないのなら、ギリギリまで戻す
	else {
		*MoveX = blx - *X - 1.0F;
		return 0;
	}
}
int MoveCharLeft(float *X, float Y, float *MoveX, float Size) {
	float brx;
	float afX = *X + *MoveX;
	brx = (float)((int)afX / Size + 1)*Size;
	if (MapChipParam(afX + *MoveX - 1.0F, Y) == 0) {
		*X = afX;
		return 1;
	}
	else {
		*MoveX = brx - *X + 1.0F;
		return 0;
	}
}
int JumpAndDrop(float *X, float *Y, float *MoveY, char *JumpFlag, float *G, float *Drop, float Size) {
	float bby;
	float afY = *Y + *MoveY;
	bby = (float)((int)afY / Size + 1)*Size;
	if (MapChipParam(*X, afY + 5.0F) == 0) {
		*Y = afY;
	}
	else {
		*MoveY = bby - *Y + 1.0F;
	}
	//着地判定
	{
		float hsize;
		hsize = Size * 0.5F;
		if (MapChipParam(*X - hsize, *Y + hsize - 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F) == 0) {
			*JumpFlag = TRUE;
			return 1;
		}
		else {
			*G = 0.0F;
			*Drop = 0.0F;
			*JumpFlag = FALSE;
			return 0;
		}
	}
}

メインプログラム

コード:

	
		{
			MoveX = 0.0F;
			MoveY = 0.0F;
			//左右移動は完了した。だが、問題は上下移動だ…。
			if ((Input&PAD_INPUT_RIGHT) != 0) {
				MoveX += 5.0F;
				int i = MoveCharRight(&PlayerX, PlayerY, &MoveX, CHIP_SIZE);
				if (i == 0) {
					printf("\n衝突しました。");
				}
			}
			if ((Input&PAD_INPUT_LEFT) != 0) {
				MoveX -= 5.0F;
				int i = MoveCharLeft(&PlayerX, PlayerY, &MoveX, CHIP_SIZE);
				if (i == 0) {
					printf("\n衝突しました。");
				}
			}
			if (JumpFlag = FALSE && (EdgeInput&PAD_INPUT_1) != 0){
				DropPower = -9.5F;
				JumpFlag = TRUE;
			}
			Grav = 0.5F;
			DropPower += Grav;
			MoveY = DropPower;
			int i = JumpAndDrop(&PlayerX, &PlayerY, &MoveY, &JumpFlag, &Grav, &DropPower, CHIP_SIZE);
			if (i == 0) {
				Grav = 0.0F;
				printf("\n\n着地しています。");
			}
		}
追記:申し遅れました。usaoさんありがとうございます。
最後に編集したユーザー keito940 on 2017年2月14日(火) 16:52 [ 編集 1 回目 ]

cattail
記事: 75
登録日時: 10年前

Re: キャラが壁にハマってしまう

#55

投稿記事 by cattail » 7年前

>コードを分離したら効率よく左右の当たり判定ができました
まずはusaoさんに「ありがとうございます」と言ってはいかがですか?
これは大切なことですよ。

>ジャンプができない上に地面に少し埋まりこんでから「着地しました。」と出ます。
ジャンプしてないのになぜ地面に埋まりこむのでしょう?

いえいえ、そこではありませんね。
ジャンプのプログラムの前に、
上に移動して、ぶつかったら止まる、
下に移動して、ぶつかったら止まる、をやってみてはどうでしょう?

アバター
usao
記事: 1889
登録日時: 11年前

Re: キャラが壁にハマってしまう

#56

投稿記事 by usao » 7年前

オフトピック
>まずはusaoさんに「ありがとうございます」と言ってはいかがですか?

個人的には割とどうでもいいけども,掲示板的には大切なこと…かな.



うーん,
「コードを見せるから誰かなんとかしてくれ」というスタイル(?)なのだとしても,
コードと共に,

・何をするものなのか(役割は何?)
・入力は何で,出力は何か (各引数は何なのか)
・出力としてどのような場合にはどうなるのか(エラーが有り得るのであればその場合にどうなるのか)
・戻り値は何を返すのか?(値を返す場合,何を示す値なのか?)
・…
といった事柄についての情報(コードの意図等)を添えた方が,何かしら話が円滑に進みやすいのではないでしょうか.


・ノーヒントで他者のコードを見て問題点をズバッと答えられるハイレベルな人
・他者のコードをどうにかして実際に動かしてまで無償デバッグ作業をしてくれる人

だけに回答者を限定する手段としては有効かとは思いますが,
そういった有力な協力者の方々にとっても,何かしらヒントがあればより取り組みやすいのではないかと想像します.

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#57

投稿記事 by keito940 » 7年前

申し遅れました。usaoさんありがとうございます!
どうやら、着地判定が地面に付く前に発動する上に、着地後も地面に埋まってしまいます。
どこがおかしいのでしょうか?()の部分であることは確かです。

コード:

//右の移動アルゴリズム
int MoveCharRight(float *X, float Y, float *MoveX, float Size) {
	float blx;
	float afX = *X + *MoveX;
	blx = (float)((int)afX / Size)*Size;
	//すすめるなら、更新する
	if (MapChipParam(afX + *MoveX , Y) == 0) {
		*X = afX;
		return 1;
	}
	//進めないのなら、ギリギリまで戻して0を返す
	else {
		*MoveX = blx - *X - 1.0F;
		return 0;
	}
}
//左の移動アルゴリズム、以下同様
int MoveCharLeft(float *X, float Y, float *MoveX, float Size) {
	float brx;
	float afX = *X + *MoveX;
	brx = (float)((int)afX / Size + 1)*Size;
	if (MapChipParam(afX + *MoveX - 1.0F, Y) == 0) {
		*X = afX;
		return 1;
	}
	else {
		*MoveX = brx - *X + 1.0F;
		return 0;
	}
}
//下の移動アルゴリズム(着地判定がおかしいです。)
int MoveCharDown(float X, float *Y, float *Drop,float *MoveY, float Size) {
	float bby;
	float afY = *Y + *MoveY;
	bby = (float)((int)afY / Size + 1)*Size;
	if (MapChipParam(X, afY + *MoveY + 1.0F) == 0) {
		*Y = afY;
		return 1;
	}
	else {
		*MoveY = bby - *Y + 1.0F;
		return 0;
	}
}
//上の移動のアルゴリズム
int MoveCharUp(float X, float *Y, float *MoveY, float Size) {
	float bty;
	float afY = *Y + *MoveY;
	bty = (float)((int)afY / Size)*Size;
	if (MapChipParam(X, afY + *MoveY - 1.0F) == 0) {
		*Y = afY;
		return 1;
	}
	else {
		*MoveY = bty - *Y + 1.0F;
		return 0;
	}
}

コード:

{
	MoveX = 0.0F;
	MoveY = 0.0F;
	//左右移動は完了した。だが、問題は上下移動だ…。
	if ((Input&PAD_INPUT_RIGHT) != 0) {
			Dir = TRUE;
			MoveX += 5.0F;
			int i = MoveCharRight(&PlayerX, PlayerY, &MoveX, CHIP_SIZE);
			if (i == 0) {
				printf("\n衝突しました。");
			}
		}
		if ((Input&PAD_INPUT_LEFT) != 0) {
			Dir = FALSE;
			MoveX -= 5.0F;
			int i = MoveCharLeft(&PlayerX, PlayerY, &MoveX, CHIP_SIZE);
			if (i == 0) {
				printf("\n衝突しました。");
			}
		}
			if ((Input&PAD_INPUT_UP) != 0) {
			MoveY -= 5.0F;
			int i = MoveCharUp(PlayerX, &PlayerY, &MoveY, CHIP_SIZE);
			if (i == 0) {
				printf("\n衝突しました。");
			}
		}
//落下アルゴリズム
	Grav = 0.5F;
	DropPower += Grav;
	MoveY = DropPower;
	int i = MoveCharDown(PlayerX, &PlayerY, &DropPower, &MoveY, CHIP_SIZE);
	if (i == 0) {
		DropPower = 0.0F;
		Grav = 0.0F;
		printf("\n着地しています。");
	}

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#58

投稿記事 by keito940 » 7年前

おかげさまでNo.57の件は解決いたしました。…しかし、地面に埋まってしまうので、アルゴリズムをまとめてみたのはいいのですが、キャラが中央にとどまったままです。(ちなみにここで挫折しました…。)どうやったら、ちゃんと動いてくれるのでしょうか?

コード:

//衝突のテストプログラム
//アクションゲームのテストシステムを作る前に、
//めり込み防止のアルゴリズムを初心者なりに作らざるをえない。
//Create 2017/02/10
#include "DxLib.h"

#define SCREEN_WIDTH (320)		//画面の横幅
#define SCREEN_HEIGHT (240)		//画面の縦幅
#define CHIP_SIZE (16)			//チップのサイズ
#define MAP_WIDTH (SCREEN_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (SCREEN_HEIGHT/CHIP_SIZE)
HANDLE Stdout;

char MapData[MAP_HEIGHT][MAP_WIDTH]
{
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,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,
};

float PlayerX, PlayerY;
float SaveX, SaveY;
float MoveX, MoveY;
float DropPower,Grav;
char JumpFlag,Dir;

int Input, EdgeInput;
int FreamStartTime;
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY);
int CharMove(float *X, float *Y, float MoveX, float MoveY, float Size);
int MapChipParam(float X, float Y);
int MoveChar(float *X, float *Y, float *MoveX, float *MoveY, float G, float *Drop, char Jump, float Size);
int GroundCheck(float *X, float *Y, float *Drop, float *G, float *MoveY,char *Jump, float Size);

int MapChipParam(float X, float Y) {
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;
	
	return MapData[y][x];
}
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (MapChipParam(X, Y) == 1) {
		float blx,brx;
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;
		brx = (float)((int)afX / CHIP_SIZE + 1)*CHIP_SIZE;
		if (*MoveX > 0.0F) {
			*MoveY = 0.0F;
			//移動量を補正する
			*MoveX = blx - X - 1.0F;
			//右の壁に当たったと判定する
			return 1;
		}
		if (*MoveX < 0.0F) {
			*MoveY = 0.0F;
			*MoveX = brx + X + 1.0F;
			return 2;
		}
		return 4;
	}
	return 0;
}
//移動アルゴリズム
int MoveChar(float *X, float *Y, float *MoveX, float *MoveY, float G, float *Drop, char Jump, float Size) {
	float blx, brx, bby, bty;
	float afX = *X + *MoveX;
	float afY = *Y + *MoveY;
	//当たり判定
	blx = (float)((int)afX / Size)*Size;	//左
	brx = (float)((int)afX / Size + 1)*Size;	//右
	bty = (float)((int)afY / Size)*Size;	//上
	bby = (float)((int)afY / Size + 1)*Size;	//下
	{
		//上にすすめるのなら、更新する
		if (*MoveY < 0.0F && MapChipParam(*X, afY + *MoveY + 1.0F) == 0) {
			*Y = afY;
			return 0;
		}
		//進めないのなら、3を返す
		else {
			*MoveY = bty - *Y + 1.0F;
			return 3;
		}
		//下にすすめるのなら、更新する
		if (*MoveY > 0.0F &&MapChipParam(*X, afY + 1.0F) == 0) {
			*Y = afY;
			return 0;
		}
		//進めない上に着地したのなら、4を返す
		else {
			*Drop = -1.0F;
			*MoveY = bby - *Y + 1.0F;
			int i = GroundCheck(&*X, &*Y, &*Drop, &G, &*MoveY, &Jump, Size);
			if (i == 0) {
				return 4;
			}
		}
		//左にすすめるなら、更新する
		if (*MoveX < 0.0F && MapChipParam(afX + *MoveX, *Y) == 0) {
			*X = afX;
			return 0;
		}
		//進めないのなら、ギリギリまで戻して1を返す
		else {
			*MoveX = blx - *X - 1.0F;
			return 1;
		}
		//右にすすめるのなら、更新する
		if (*MoveX > 0.0F && MapChipParam(afX + *MoveX - 1.0F, *Y) == 0) {
			*X = afX;
			return 0;
		}
		//進めないのならギリギリまで戻して2を返す
		else {
			*MoveX = brx - *X + 1.0F;
			return 2;
		}
		//ここまで来たら適当な数値を返して終了
		return 0;
	}
}
//着地判定
int GroundCheck(float *X, float *Y, float *Drop, float *G, float *MoveY,char *JumpFlag, float Size){
	float hsize;
	hsize = Size * 0.5F;
	if (MapChipParam(*X - hsize, *Y + hsize - 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize - 1.0F) == 0) {
		*JumpFlag = TRUE;
		return 1;
	}
	else {
		*MoveY = 0.0F;
		*G = 0.0F;
		*Drop = 0.0F;
		*JumpFlag = FALSE;
		return 0;
	}
}
int CharMove(float *X, float *Y, float MoveX, float MoveY, float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F;
	{
		if (MapHitCheck(*X + hsize + 5.0F, *Y - hsize, &MoveX, &Dummy) == 1) return 1;
		if (MapHitCheck(*X - hsize - 5.0F, *Y - hsize, &MoveX, &Dummy) == 2) return 2;
		if (MapHitCheck(*X + hsize + 5.0F, *Y + hsize, &MoveX, &Dummy) == 1) return 1;
		if (MapHitCheck(*X - hsize - 5.0F, *Y - hsize, &MoveX, &Dummy) == 2) return 2;
		*X += MoveX;
	}
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE),SetGraphMode(320,240,32),printf("初期化しています…"); 
	if (DxLib_Init() == -1) { return -1; }
	PlayerX = 160.0F, PlayerY = 120.0F, MoveX = 0.0F, MoveY = 0.0F;
	JumpFlag = FALSE, DropPower = 0.0F, Grav = 0.5F, Dir = TRUE;
	Input = 0, EdgeInput = 0, FreamStartTime = GetNowCount();
	return 0;
}
int main(void) {
	FreamStartTime = GetNowCount();
	while (GetNowCount() - FreamStartTime < 1000 / 60) { Sleep(1); }
	system("cls");
	printf("メインループ開始");
	printf("\nPlayerX=%d,PlayerY=%d,Grav=%8.1f", (int)PlayerX, (int)PlayerY, Grav);
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	//衝突する前の座標を保存する
	SaveX = PlayerX;
	SaveY = PlayerY;
	//移動できるかチェックして、できないのなら、保存した座標に動かす
	int i = MoveChar(&PlayerX, &PlayerY, &MoveX, &MoveY, Grav, &DropPower, JumpFlag, CHIP_SIZE);
	if (i == 0) {
		//移動処理(反応しません)
		{
			MoveX = 0.0F;
			MoveY = 0.0F;
			if ((Input&PAD_INPUT_RIGHT) != 0) {
				Dir = TRUE;
				MoveX += 5.0F;
			}
			if ((Input&PAD_INPUT_LEFT) != 0) {
				Dir = FALSE;
				MoveX -= 5.0F;
			}
			if (JumpFlag = FALSE && (EdgeInput&PAD_INPUT_1) != 0) {
				DropPower = -9.5F;
				JumpFlag = TRUE;
			}
			//落下処理
			Grav = 0.5F;
			DropPower += Grav;
			MoveY = DropPower;
			//移動処理
			i = MoveChar(&PlayerX, &PlayerY, &MoveX, &MoveY, Grav, &DropPower, JumpFlag, CHIP_SIZE);
		}
	}
	else {
		MoveX = 0.0F;
		MoveY = 0.0F;
		PlayerX = SaveX;
		PlayerY = SaveY;
	}
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
				DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i*CHIP_SIZE + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	AllocConsole(); FILE* out = 0; freopen_s(&out, "CON", "w", stdout); Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
	init();
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		main();
	}
	DxLib_End(); fclose(out); FreeConsole();
	return 0;
}

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#59

投稿記事 by keito940 » 7年前

ようやく、原因が見えてきました。常に上に衝突している状態が原因にあるようです。(詳しくはコンパイルしてみてください。)
どうすれば、その状態を改善できるのでしょうか?
移動アルゴリズム

コード:

int MoveChar(float *X, float *Y, float *MoveX, float *MoveY, float G, float *Drop, char *Jump, float Size) {
	float blx, brx, bby, bty;
	float afX = *X + *MoveX;
	float afY = *Y + *MoveY;
	//当たり判定
	blx = (float)((int)afX / Size)*Size;	//左
	brx = (float)((int)afX / Size + 1)*Size;	//右
	bty = (float)((int)afY / Size)*Size;	//上
	bby = (float)((int)afY / Size + 1)*Size;	//下
	{
		//上にすすめるのなら、更新する
		if (*MoveY < 0.0F && MapChipParam(*X, afY + *MoveY + 1.0F) == 0) {
			*Y = afY;
			return 0;
		}
		//進めないのなら、3を返す
		else {
			*MoveY = bty - *Y + 1.0F;
			return 3;
		}
		//下にすすめるのなら、更新する
		if (*MoveY > 0.0F &&MapChipParam(*X, afY + 1.0F) == 0) {
			*Y = afY;
			return 0;
		}
		//進めない上に着地したのなら、4を返す
		else {
			*Drop = -1.0F;
			*MoveY = bby - *Y + 1.0F;
			int i = GroundCheck(&*X, &*Y, &*Drop, &G, &*MoveY, &*Jump, Size);
			if (i == 0) {
				return 4;
			}
		}
		//左にすすめるなら、更新する
		if (*MoveX < 0.0F && MapChipParam(afX + *MoveX, *Y) == 0) {
			*X = afX;
			return 0;
		}
		//進めないのなら、ギリギリまで戻して1を返す
		else {
			*MoveX = blx - *X - 1.0F;
			return 1;
		}
		//右にすすめるのなら、更新する
		if (*MoveX > 0.0F && MapChipParam(afX + *MoveX - 1.0F, *Y) == 0) {
			*X = afX;
			return 0;
		}
		//進めないのならギリギリまで戻して2を返す
		else {
			*MoveX = brx - *X + 1.0F;
			return 2;
		}
		//ここまで来たら適当な数値を返して終了
		return 0;
	}
}
//着地判定
int GroundCheck(float *X, float *Y, float *Drop, float *G, float *MoveY,char *JumpFlag, float Size){
	float hsize;
	hsize = Size * 0.5F;
	if (MapChipParam(*X - hsize, *Y + hsize - 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize - 1.0F) == 0) {
		*JumpFlag = TRUE;
		return 1;
	}
	else {
		*MoveY = 0.0F;
		*G = 0.0F;
		*Drop = 0.0F;
		*JumpFlag = FALSE;
		return 0;
	}
メインコード

コード:

int main(void) {
	FreamStartTime = GetNowCount();
	while (GetNowCount() - FreamStartTime < 1000 / 60) { Sleep(1); }
	system("cls");
	printf("メインループ開始");
	printf("\nPlayerX=%d,PlayerY=%d,Grav=%8.1f", (int)PlayerX, (int)PlayerY, Grav);
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	//衝突する前の座標を保存する
	SaveX = PlayerX;
	SaveY = PlayerY;
	//移動処理(反応しません)
	{
		MoveX = 0.0F;
		MoveY = 0.0F;
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			Dir = TRUE;
			MoveX += 5.0F;
		}
		if ((Input&PAD_INPUT_LEFT) != 0) {
			Dir = FALSE;
			MoveX -= 5.0F;
		}
		if (JumpFlag = FALSE && (EdgeInput&PAD_INPUT_1) != 0) {
			DropPower = -9.5F;
			JumpFlag = TRUE;
		}
		//落下処理
		Grav = 0.5F;
		DropPower += Grav;
		MoveY = DropPower;
		//移動処理
		int i = MoveChar(&PlayerX, &PlayerY, &MoveX, &MoveY, Grav, &DropPower, &JumpFlag, CHIP_SIZE);
		//どういうわけか、常に上に衝突している。僕の考えでは、iが0なら、移動できるとしたいのだが…
		//ようやく、原因が見えてきたぞ。
		printf("\n現在衝突している場所(3:上、4:下、1:左、2:右)=%d", i);
		if (i != 0) {
			PlayerX = SaveX;
			PlayerY = SaveY;
		}
	}
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
				DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i*CHIP_SIZE + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: キャラが壁にハマってしまう

#60

投稿記事 by みけCAT » 7年前

直接の原因ではなさそうだとは思いますが、MoveChar()関数の
keito940 さんが書きました:

コード:

		//上にすすめるのなら、更新する
		if (*MoveY < 0.0F && MapChipParam(*X, afY + *MoveY + 1.0F) == 0) {
			*Y = afY;
			return 0;
		}
		//進めないのなら、3を返す
		else {
			*MoveY = bty - *Y + 1.0F;
			return 3;
		}
という部分で条件式が真でも偽でもreturnしていまい、
そのあとのせっかく書いてあるコードが実行されないのは、おかしいのではないかと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: キャラが壁にハマってしまう

#61

投稿記事 by みけCAT » 7年前

keito940 さんが書きました:どうすれば、その状態を改善できるのでしょうか?
何が問題かを調べるためのテストをして、その結果を利用してデバッグをすれば改善できるかもしれません。
例えば、afXやafYは*Xや*Yに*MoveXや*MoveYを足した値なのにさらに*MoveXや*MoveYを足している上、なぜか「下にすすめるのなら、更新する」の判定でだけ追加で足していないのが不自然なので、
どこのあたり判定をしているのかを(文字ではなく、点などのゲーム画面に統合されわかりやすいグラフィックで)可視化してみるとか。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#62

投稿記事 by keito940 » 7年前

コードをこの様にしたら上の当たり判定が勝手に落下していっているのが確認されました。
僕は、何をしたらいいのかを考えられないので教えてくれませんか?

コード:

//移動アルゴリズム
int MoveChar(float *X, float *Y, float *MoveX, float *MoveY, float G, float *Drop, char *Jump, float Size) {
	float blx, brx, bby, bty;
	float afX = *X + *MoveX;
	float afY = *Y + *MoveY;
	//当たり判定
	blx = (float)((int)afX / Size)*Size;	//左
	brx = (float)((int)afX / Size + 1)*Size;	//右
	bty = (float)((int)afY / Size)*Size;	//上
	bby = (float)((int)afY / Size + 1)*Size;	//下
	{
		//上にすすめるのなら、更新する
		if (*MoveY < 0.0F && MapChipParam(*X, afY + *MoveY + 1.0F) == 0) {
			*Y = afY;
		}
		//進めないのなら、3を返す
		else {
			*MoveX = 0.0F;
			*MoveY = bty - *Y + 1.0F;
			DrawLine(*X + 15.0F, (int)bty, *X + 15.0F, (int)bty + 15, GetColor(0, 255, 0));
			return 3;
		}
		//下にすすめるのなら、更新する
		if (*MoveY > 0.0F &&MapChipParam(*X, afY + 1.0F) == 0) {
			*Y = afY;
		}
		//進めない地面に着地したのなら、4を返す
		else {
			*MoveX = 0.0F;
			*Drop = -1.0F;
			*MoveY = bby - *Y + 1.0F;
			DrawLine(*X - 15.0F, (int)bby, *X - 15.0F, (int)bby - 15, GetColor(0, 255, 0));
			int i = GroundCheck(&*X, &*Y, &*Drop, &G, &*MoveY, &*Jump, Size);
			if (i == 0) {
				return 4;
			}
		}
		//左にすすめるなら、更新する
		if (*MoveX < 0.0F && MapChipParam(afX + *MoveX, *Y) == 0) {
			*X = afX;
		}
		//進めないのなら、ギリギリまで戻して1を返す
		else {
			*MoveY = 0.0F;
			*MoveX = blx - *X - 1.0F;
			DrawLine((int)blx, *Y + 15.0F, (int)blx + 15, *Y + 15, GetColor(0, 255, 0));
			return 1;
		}
		//右にすすめるのなら、更新する
		if (*MoveX > 0.0F && MapChipParam(afX + *MoveX - 1.0F, *Y) == 0) {
			*X = afX;
		}
		//進めないのならギリギリまで戻して2を返す
		else {
			*MoveY = 0.0F;
			*MoveX = brx - *X + 1.0F;
			DrawLine((int)blx, *Y + 15.0F, (int)blx + 15, *Y + 15, GetColor(0, 255, 0));
			return 2;
		}
		//ここまで来たら移動できることを証明して終了
		return 0;
	}
}

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#63

投稿記事 by keito940 » 7年前

関数を合体させるのはまだ早いということに気づき分離してみました。ですが、上に衝突したり床から床へ移動すると地面に延々と落下してしまう上に、
一番最初に下に着地させても、ジャンプしない限り、右にも左にも行きません。どこがおかしいのでしょうか?
当たり判定のアルゴリズム

コード:

int MoveCharUp(float X, float *Y, float *MoveX, float *MoveY, float *Drop,float Size) {
	float bty;
	float afY = *Y + *MoveY;
	bty = (float)((int)afY / Size)*Size;
	//上にすすめるのなら、更新する
	if (MapChipParam(X, afY + *MoveY + 1.0F) == 0) {
		*Y = afY;
		return 0;
	}
	//進めないのなら、3を返す
	else {
		*MoveX = 0.0F;
		*Drop = -1.0F;
		*MoveY = bty - *Y + 1.0F;
		return 1;
	}
}
int MoveCharDown(float X, float *Y, float *MoveX, float *MoveY, float G,float *Drop,char *Jump,float Size) {
	float bby;
	float afY = *Y + *MoveY;
	bby = (float)((int)afY / Size + 1)*Size;	//下
	//下にすすめるのなら、更新する
	if (MapChipParam(X, afY + *MoveY + 1.0F) == 0) {
		*Y = afY;
		return 0;
	}
	//進めない地面に着地したのなら、4を返す
	else {
		*MoveX = 0.0F;
		*MoveY = bby - *Y + 1.0F;
		int i = GroundCheck(&X, &*Y, &*Drop, &G, &*MoveY, &*Jump, Size);
		if (i == 0) {
			return 1;
		}
	}
}
int MoveCharLeft(float *X,float Y,float *MoveX,float *MoveY,float Size) {
	float blx;
	float afX = *X + *MoveX;
	blx = (float)((int)afX / Size)*Size;	//左
	//左にすすめるなら、更新する
	if (MapChipParam(afX + *MoveX, Y) == 0) {
		*X = afX;
		return 0;
	}
	//進めないのなら、ギリギリまで戻して1を返す
	else {
		*MoveY = 0.0F;
		*MoveX = blx - *X - 1.0F;
		return 1;
	}
}
int MoveCharRight(float *X, float Y, float *MoveX, float *MoveY,float Size) {
	float brx;
	float afX = *X + *MoveX;
	brx = (float)((int)afX / Size + 1)*Size;	//右
	//右にすすめるのなら、更新する
	if (MapChipParam(afX + *MoveX - 1.0F, Y) == 0) {
		*X = afX;
		return 0;
	}
	//進めないのならギリギリまで戻して2を返す
	else {
		*MoveY = 0.0F;
		*MoveX = brx - *X + 1.0F;
		return 1;
	}
}
//着地判定
int GroundCheck(float *X, float *Y, float *Drop, float *G, float *MoveY,char *JumpFlag, float Size){
	float hsize;
	hsize = Size * 0.5F;
	if (MapChipParam(*X - hsize, *Y + hsize - 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize - 1.0F) == 0) {
		*JumpFlag = TRUE;
		return 1;
	}
	else {
		*MoveY = 0.0F;
		*G = 0.0F;
		*Drop = 0.0F;
		*JumpFlag = FALSE;
		return 0;
	}
}
メインプログラム

コード:

int main(void) {
	FreamStartTime = GetNowCount();
	while (GetNowCount() - FreamStartTime < 1000 / 60) { Sleep(1); }
	system("cls");
	printf("メインループ開始");
	printf("\nPlayerX=%d,PlayerY=%d,Grav=%8.1f", (int)PlayerX, (int)PlayerY, Grav);
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	//衝突する前の座標を保存する
	SaveX = PlayerX;
	SaveY = PlayerY;
	//移動処理、衝突したら保存した座標に動かす
	{
		MoveX = 0.0F;
		MoveY = 0.0F;
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			Dir = TRUE;
			MoveX += 5.0F;
			int i = MoveCharLeft(&PlayerX, PlayerY, &MoveX, &MoveY, CHIP_SIZE);
			if (i == 1) {
				PlayerX = SaveX;
				PlayerY = SaveY;
				printf("衝突しました。");
			}
		}
		if ((Input&PAD_INPUT_LEFT) != 0) {
			Dir = FALSE;
			MoveX -= 5.0F;
			int i = MoveCharRight(&PlayerX, PlayerY, &MoveX, &MoveY, CHIP_SIZE);
			if (i == 1) {
				PlayerX = SaveX;
				PlayerY = SaveY;
				printf("衝突しました。");
			}
		}
		if (JumpFlag == FALSE && (EdgeInput&PAD_INPUT_1) != 0) {
			DropPower = -9.5F;
			JumpFlag = TRUE;
			int i = MoveCharUp(PlayerX, &PlayerY, &MoveX, &MoveY, &DropPower, CHIP_SIZE);
			if (i == 1) {
				PlayerY = SaveY;
				printf("衝突しました。");
			}
		}
		//落下処理
		Grav = 0.5F;
		DropPower += Grav;
		MoveY = DropPower;
		int i = MoveCharDown(PlayerX, &PlayerY, &MoveX, &MoveY, Grav, &DropPower, &JumpFlag, CHIP_SIZE);
		if (i == 1) {
			PlayerX = SaveX;
			PlayerY = SaveY;
			printf("衝突しました。");
		}
		/*//移動処理
		int i = MoveChar(&PlayerX, &PlayerY, &MoveX, &MoveY, Grav, &DropPower, &JumpFlag, CHIP_SIZE);
		//どういうわけか、常に上に衝突している。僕の考えでは、iが0なら、移動できるとしたいのだが…
		//ようやく、原因が見えてきたぞ。
		printf("\n現在衝突している場所(3:上、4:下、1:左、2:右)=%d", i);
		if (i != 0) {
			PlayerX = SaveX;
			PlayerY = SaveY;
		}*/
	}
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
				DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i*CHIP_SIZE + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#64

投稿記事 by keito940 » 7年前

失礼しました。No.63の件は簡単なミスだったようです。何回もトライ&エラーした結果、下の衝突判定が地面に着地するまで何回も行われているという事実を知りました。通常、アクションゲームで地面に着地する回数は1回だけなんですが、どういうわけか、何回も衝突してから地面に着地しているようです。
今現在のコードはこんな感じです。
移動アルゴリズム(No.63の件は修正しました。)

コード:

int MoveCharUp(float X, float *Y, float *MoveX, float *MoveY, float *Drop,float Size) {
	float bty;
	float afY = *Y + *MoveY;
	bty = (float)((int)afY / Size)*Size;
	//上にすすめるのなら、更新する
	if (MapChipParam(X, afY + *MoveY - 1.0F) == 0) {
		*Y = afY;
		return 0;
	}
	//進めないのなら、3を返す
	else {
		*MoveX = 0.0F;
		*Drop = -1.0F;
		*MoveY = bty - *Y + 1.0F;
		return 1;
	}
}
int MoveCharDown(float X, float *Y, float *MoveX, float *MoveY, float G,float *Drop,char *Jump,float Size) {
	float bby;
	float afY = *Y + *MoveY;
	bby = (float)((int)afY / Size + 1)*Size;	//下
	//下にすすめるのなら、更新する
	if (MapChipParam(X, afY + *MoveY + 2.0F) == 0) {
		*Y = afY;
		return 0;
	}
	//進めない地面に着地したのなら、4を返す
	else {
		*MoveX = 0.0F;
		*Drop = 0.0F;
		*MoveY = bby - *Y + 1.0F;
		int i = GroundCheck(&X, &*Y, &*Drop, &G, &*MoveY, &*Jump, Size);
		if (i == 0) {
			return 1;
		}
	}
}
int MoveCharLeft(float *X,float Y,float *MoveX,float *MoveY,float Size) {
	float blx;
	float afX = *X + *MoveX;
	blx = (float)((int)afX / Size)*Size;	//左
	//左にすすめるなら、更新する
	if (MapChipParam(afX + *MoveX + 1.0F, Y) == 0) {
		*X = afX;
		return 0;
	}
	//進めないのなら、ギリギリまで戻して1を返す
	else {
		*MoveY = 0.0F;
		*MoveX = blx - *X - 1.0F;
		return 1;
	}
}
int MoveCharRight(float *X, float Y, float *MoveX, float *MoveY,float Size) {
	float brx;
	float afX = *X + *MoveX;
	brx = (float)((int)afX / Size + 1)*Size;	//右
	//右にすすめるのなら、更新する
	if (MapChipParam(afX + *MoveX - 1.0F, Y) == 0) {
		*X = afX;
		return 0;
	}
	//進めないのならギリギリまで戻して2を返す
	else {
		*MoveY = 0.0F;
		*MoveX = brx - *X + 1.0F;
		return 1;
	}
}
//着地判定
int GroundCheck(float *X, float *Y, float *Drop, float *G, float *MoveY,char *JumpFlag, float Size){
	float hsize;
	hsize = Size * 0.5F;
	if (MapChipParam(*X - hsize, *Y + hsize - 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize - 1.0F) == 0) {
		*JumpFlag = TRUE;
		return 1;
	}
	else {
		*MoveY = 0.0F;
		*G = 0.0F;
		*JumpFlag = FALSE;
		return 0;
	}
}
メインプログラム

コード:

int main(void) {
	FreamStartTime = GetNowCount();
	while (GetNowCount() - FreamStartTime < 1000 / 60) { Sleep(1); }
	system("cls");
	printf("メインループ開始");
	printf("\nPlayerX=%d,PlayerY=%d,Grav=%8.1f,DropPower=%8.1f", (int)PlayerX, (int)PlayerY, Grav,DropPower);
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	//衝突する前の座標を保存する
	SaveX = PlayerX;
	SaveY = PlayerY;
	//移動処理
	{
		MoveX = 0.0F;
		MoveY = 0.0F;
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			Dir = TRUE;
			MoveX += 5.0F;
			int i = MoveCharLeft(&PlayerX, PlayerY, &MoveX, &MoveY, CHIP_SIZE);
			if (i == 1) {
				printf("左に衝突しました。");
			}
		}
		if ((Input&PAD_INPUT_LEFT) != 0) {
			Dir = FALSE;
			MoveX -= 5.0F;
			int i = MoveCharRight(&PlayerX, PlayerY, &MoveX, &MoveY, CHIP_SIZE);
			if (i == 1) {
				printf("右に衝突しました。");
			}
		}
		if (JumpFlag == FALSE && (EdgeInput&PAD_INPUT_1) != 0) {
			DropPower = -9.5F;
			JumpFlag = TRUE;
			int i = MoveCharUp(PlayerX, &PlayerY, &MoveX, &MoveY, &DropPower, CHIP_SIZE);
			if (i == 1) {
				printf("上に衝突しました。");
			}
		}
		//落下処理
		Grav = 0.5F;
		DropPower += Grav;
		MoveY = DropPower;
		int i = MoveCharDown(PlayerX, &PlayerY, &MoveX, &MoveY, Grav, &DropPower, &JumpFlag, CHIP_SIZE);
		if (i == 1) {
			//どうやら、下に何回も衝突しているようだ。
			printf("下に衝突しました。");
		}
		/*//移動処理
		int i = MoveChar(&PlayerX, &PlayerY, &MoveX, &MoveY, Grav, &DropPower, &JumpFlag, CHIP_SIZE);
		//どういうわけか、常に上に衝突している。僕の考えでは、iが0なら、移動できるとしたいのだが…
		//ようやく、原因が見えてきたぞ。
		printf("\n現在衝突している場所(3:上、4:下、1:左、2:右)=%d", i);
		if (i != 0) {
			PlayerX = SaveX;
			PlayerY = SaveY;
		}*/
	}
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
				DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i*CHIP_SIZE + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

cattail
記事: 75
登録日時: 10年前

Re: キャラが壁にハマってしまう

#65

投稿記事 by cattail » 7年前

原因が分かって良かったですね。
がんばって下さい。
一つ気に掛かった事なのですが、
CPUがプログラムを追っていく様を気にした方がいいように思えます。
ゲームの1ループがどう流れているのかとか、そういうのを気にしたほうがいいと思っています。
1/60秒の間のことです。
あきらめないでくださいね。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#66

投稿記事 by keito940 » 7年前

cattailさんが1フレームの流れを気にしろと言うことで、1フレームの流れをコンソールに写してみました。下の当たり判定と同時に着地判定が行われているようですね…。どうすれば、着地判定と下の当たり判定を分離させることができるのでしょうか?ちなみにサンプルコード(http://dxlib.o.oo7.jp/program/ActionSample.cpp)ではしっかり分離されていたようです。

コード:

//衝突のテストプログラム
//アクションゲームのテストシステムを作る前に、
//めり込み防止のアルゴリズムを初心者なりに作らざるをえない。
//Create 2017/02/10
#include "DxLib.h"

#define SCREEN_WIDTH (320)		//画面の横幅
#define SCREEN_HEIGHT (240)		//画面の縦幅
#define CHIP_SIZE (16)			//チップのサイズ
#define MAP_WIDTH (SCREEN_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (SCREEN_HEIGHT/CHIP_SIZE)
HANDLE Stdout;

char MapData[MAP_HEIGHT][MAP_WIDTH]
{
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,1, 1,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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
};

float PlayerX, PlayerY;
float SaveX, SaveY;
float MoveX, MoveY;
float DropPower,Grav;
char JumpFlag,Dir;

int Input, EdgeInput;
int FreamStartTime;
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY);
int CharMove(float *X, float *Y, float MoveX, float MoveY, float Size);
int MapChipParam(float X, float Y);
int MoveCharUp(float X, float *Y, float *MoveX, float *MoveY, float *Drop, float Size);
int MoveCharDown(float X, float *Y, float *MoveX, float *MoveY, float *G, float *Drop, char *Jump, float Size);
int MoveCharLeft(float *X, float Y, float *MoveX, float *MoveY, float Size);
int MoveCharRight(float *X, float Y, float *MoveX, float *MoveY, float Size);
//int MoveChar(float *X, float *Y, float *MoveX, float *MoveY, float G, float *Drop, char *Jump, float Size);
int GroundCheck(float *X, float *Y, float *Drop, float *G, float *MoveY,char *Jump, float Size);

int MapChipParam(float X, float Y) {
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;
	
	return MapData[y][x];
}
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;

	if (MapChipParam(X, Y) == 1) {
		float blx,brx;
		blx = (float)((int)afX / CHIP_SIZE)*CHIP_SIZE;
		brx = (float)((int)afX / CHIP_SIZE + 1)*CHIP_SIZE;
		if (*MoveX > 0.0F) {
			*MoveY = 0.0F;
			//移動量を補正する
			*MoveX = blx - X - 1.0F;
			//右の壁に当たったと判定する
			return 1;
		}
		if (*MoveX < 0.0F) {
			*MoveY = 0.0F;
			*MoveX = brx + X + 1.0F;
			return 2;
		}
		return 4;
	}
	return 0;
}
/*(完成と呼べない段階であることが発覚したのでコメントアウト)
//移動アルゴリズム
int MoveChar(float *X, float *Y, float *MoveX, float *MoveY, float G, float *Drop, char *Jump, float Size) {
	float blx, brx, bby, bty;
	float afX = *X + *MoveX;
	float afY = *Y + *MoveY;
	//当たり判定
	blx = (float)((int)afX / Size)*Size;	//左
	brx = (float)((int)afX / Size + 1)*Size;	//右
	bty = (float)((int)afY / Size)*Size;	//上
	bby = (float)((int)afY / Size + 1)*Size;	//下
	{
		//上にすすめるのなら、更新する
		if (*MoveY < 0.0F && MapChipParam(*X, afY + *MoveY + 1.0F) == 0) {
			*Y = afY;
		}
		//進めないのなら、3を返す
		else {
			*MoveX = 0.0F;
			*Drop = -1.0F;
			*MoveY = bty - *Y + 1.0F;
			return 3;
		}
		//下にすすめるのなら、更新する
		if (*MoveY > 0.0F &&MapChipParam(*X, afY + 1.0F) == 0) {
			*Y = afY;
		}
		//進めない地面に着地したのなら、4を返す
		else {
			*MoveX = 0.0F;
			*Drop = -1.0F;
			*MoveY = bby - *Y + 1.0F;
			DrawLine(*X - 15.0F, (int)bby, *X - 15.0F, (int)bby - 15, GetColor(0, 255, 0));
			int i = GroundCheck(&*X, &*Y, &*Drop, &G, &*MoveY, &*Jump, Size);
			if (i == 0) {
				return 4;
			}
		}
		//左にすすめるなら、更新する
		if (*MoveX < 0.0F && MapChipParam(afX + *MoveX, *Y) == 0) {
			*X = afX;
			return 0;
		}
		//進めないのなら、ギリギリまで戻して1を返す
		else {
			*MoveY = 0.0F;
			*MoveX = blx - *X - 1.0F;
			return 1;
		}
		//右にすすめるのなら、更新する
		if (*MoveX > 0.0F && MapChipParam(afX + *MoveX - 1.0F, Y) == 0) {
			*X = afX;
			return 0;
		}
		//進めないのならギリギリまで戻して2を返す
		else {
			*MoveY = 0.0F;
			*MoveX = brx - *X + 1.0F;
			return 1;
		}
		//ここまで来たら移動できることを証明して終了
		return 0;
	}
}*/
int MoveCharUp(float X, float *Y, float *MoveX, float *MoveY, float *Drop,float Size) {
	float bty;
	float afY = *Y + *MoveY;
	bty = (float)((int)afY / Size)*Size;
	printf("上の当たり判定を行ってます。");
	//上にすすめるのなら、更新する
	if (MapChipParam(X, afY + *MoveY - 1.0F) == 0) {
		*Y = afY;
		return 0;
	}
	//進めないのなら、3を返す
	else {
		*Drop = -1.0F;
		*MoveY = bty - *Y + 1.0F;
		return 1;
	}
}
int MoveCharDown(float X, float *Y, float *MoveX, float *MoveY, float *G,float *Drop,char *Jump,float Size) {
	float bby;
	float afY = *Y + *MoveY;
	bby = (float)((int)afY / Size + 1)*Size;	//下
	printf("下の当たり判定を行ってます。");
	//下にすすめるのなら、更新する
	if (MapChipParam(X, afY + *MoveY + 1.0F) == 0) {
		*Y = afY;
		return 0;
	}
	//進めない地面に着地したのなら、4を返す
	else {
		*Drop = 0.0F;
		*MoveY = bby - *Y + 1.0F;
		int i = GroundCheck(&X, &*Y, &*Drop, &*G, &*MoveY, &*Jump, Size);
		if (i == 0) {
			return 1;
		}
	}
}
int MoveCharLeft(float *X,float Y,float *MoveX,float *MoveY,float Size) {
	float blx;
	float afX = *X + *MoveX;
	blx = (float)((int)afX / Size)*Size;	//左
	printf("左の当たり判定を行ってます。");
	//左にすすめるなら、更新する
	if (MapChipParam(afX + *MoveX + 1.0F, Y) == 0) {
		*X = afX;
		return 0;
	}
	//進めないのなら、ギリギリまで戻して1を返す
	else {
		*MoveX = blx - *X - 1.0F;
		return 1;
	}
}
int MoveCharRight(float *X, float Y, float *MoveX, float *MoveY,float Size) {
	float brx;
	float afX = *X + *MoveX;
	brx = (float)((int)afX / Size + 1)*Size;	//右
	printf("右の当たり判定を行ってます。");
	//右にすすめるのなら、更新する
	if (MapChipParam(afX + *MoveX - 1.0F, Y) == 0) {
		*X = afX;
		return 0;
	}
	//進めないのならギリギリまで戻して2を返す
	else {
		*MoveX = brx - *X + 1.0F;
		return 1;
	}
}
//着地判定
int GroundCheck(float *X, float *Y, float *Drop, float *G, float *MoveY,char *JumpFlag, float Size){
	printf("着地判定を行っています。");
	float hsize;
	hsize = Size * 0.5F;
	if (MapChipParam(*X - hsize, *Y + hsize + 1.0F+0.5F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F+0.5F) == 0) {
		*JumpFlag = TRUE;
		return 1;
	}
	else {
		*MoveY = 0.0F;
		*G = 0.0F;
		*JumpFlag = FALSE;
		return 0;
	}
}
int CharMove(float *X, float *Y, float MoveX, float MoveY, float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F;
	{
		if (MapHitCheck(*X + hsize + 5.0F, *Y - hsize, &MoveX, &Dummy) == 1) return 1;
		if (MapHitCheck(*X - hsize - 5.0F, *Y - hsize, &MoveX, &Dummy) == 2) return 2;
		if (MapHitCheck(*X + hsize + 5.0F, *Y + hsize, &MoveX, &Dummy) == 1) return 1;
		if (MapHitCheck(*X - hsize - 5.0F, *Y - hsize, &MoveX, &Dummy) == 2) return 2;
		*X += MoveX;
	}
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE),SetGraphMode(320,240,32),printf("初期化しています…"); 
	if (DxLib_Init() == -1) { return -1; }
	PlayerX = 160.0F, PlayerY = 216.0F, MoveX = 0.0F, MoveY = 0.0F;
	JumpFlag = FALSE, DropPower = 0.0F, Grav = 0.5F, Dir = TRUE;
	Input = 0, EdgeInput = 0, FreamStartTime = GetNowCount();
	return 0;
}
int main(void) {
	FreamStartTime = GetNowCount();
	while (GetNowCount() - FreamStartTime < 1000 / 60) { Sleep(1); }
	system("cls");
	printf("メインループ開始\n");
	printf("\nPlayerX=%d,PlayerY=%d,Grav=%8.1f,DropPower=%8.1f", (int)PlayerX, (int)PlayerY, Grav,DropPower);
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	//衝突する前の座標を保存する
	SaveX = PlayerX;
	SaveY = PlayerY;
	//移動処理
	{
		MoveX = 0.0F;
		MoveY = 0.0F;
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			Dir = TRUE;
			MoveX += 5.0F;
			int i = MoveCharLeft(&PlayerX, PlayerY, &MoveX, &MoveY, CHIP_SIZE);
			if (i == 1) {
				printf("左に衝突しました。");
			}
		}
		if ((Input&PAD_INPUT_LEFT) != 0) {
			Dir = FALSE;
			MoveX -= 5.0F;
			int i = MoveCharRight(&PlayerX, PlayerY, &MoveX, &MoveY, CHIP_SIZE);
			if (i == 1) {
				printf("右に衝突しました。");
			}
		}
		if (JumpFlag == FALSE && (EdgeInput&PAD_INPUT_1) != 0) {
			Grav = 0.5F;
			DropPower = -9.5F;
			JumpFlag = TRUE;
			int i = MoveCharUp(PlayerX, &PlayerY, &MoveX, &MoveY, &DropPower, CHIP_SIZE);
			if (i == 1) {
				printf("上に衝突しました。");
			}
		}
		//落下処理
		if (MapChipParam(PlayerX-CHIP_SIZE*0.5F,PlayerY)==0&&MapChipParam(PlayerX+CHIP_SIZE*0.5F,PlayerY)==0) {
			Grav = 0.5F;
			DropPower += Grav;
			MoveY = DropPower;
			int i = MoveCharDown(PlayerX, &PlayerY, &MoveX, &MoveY, &Grav, &DropPower, &JumpFlag, CHIP_SIZE);
			if (i == 1) {
				//どうやら、下に何回も衝突しているようだ。
				printf("下に衝突しました。");
			}
		}
		/*//移動処理
		int i = MoveChar(&PlayerX, &PlayerY, &MoveX, &MoveY, Grav, &DropPower, &JumpFlag, CHIP_SIZE);
		//どういうわけか、常に上に衝突している。僕の考えでは、iが0なら、移動できるとしたいのだが…
		//ようやく、原因が見えてきたぞ。
		printf("\n現在衝突している場所(3:上、4:下、1:左、2:右)=%d", i);
		if (i != 0) {
			PlayerX = SaveX;
			PlayerY = SaveY;
		}*/
	}
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
				DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i*CHIP_SIZE + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	AllocConsole(); FILE* out = 0; freopen_s(&out, "CON", "w", stdout); Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
	init();
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		main();
	}
	DxLib_End(); fclose(out); FreeConsole();
	return 0;
}

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#67

投稿記事 by keito940 » 7年前

頃はよしと、衝突判定の関数を統合させて見たのですが、左に動くと地面に落ちてしまいます。
しかも、キャラが画像のようになってしまいます。まだまだアクションゲームを作る前に課題がありそうです…

コード:

//衝突のテストプログラム
//アクションゲームのテストシステムを作る前に、
//めり込み防止のアルゴリズムを初心者なりに作らざるをえない。
//Create 2017/02/10
#include "DxLib.h"

#define SCREEN_WIDTH (320)		//画面の横幅
#define SCREEN_HEIGHT (240)		//画面の縦幅
#define CHIP_SIZE (16)			//チップのサイズ
#define MAP_WIDTH (SCREEN_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (SCREEN_HEIGHT/CHIP_SIZE)
HANDLE Stdout;

char MapData[MAP_HEIGHT][MAP_WIDTH]
{
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,1, 1,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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
};

float PlayerX, PlayerY;
float SaveX, SaveY;
float MoveX, MoveY;
float DropPower,Grav;
char JumpFlag,Dir;

int Input, EdgeInput;
int FreamStartTime;
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY,float Size);
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop, float *G, char *Jump, float Size);
int MapChipParam(float X, float Y);
int MoveCharUp(float X, float *Y, float *MoveX, float *MoveY, float *Drop, float Size);
int MoveCharDown(float X, float *Y, float *MoveX, float *MoveY, float G, float *Drop, char *Jump, float Size);
int MoveCharLeft(float *X, float Y, float *MoveX, float *MoveY, float Size);
int MoveCharRight(float *X, float Y, float *MoveX, float *MoveY, float Size);
//int MoveChar(float *X, float *Y, float *MoveX, float *MoveY, float G, float *Drop, char *Jump, float Size);
int GroundCheck(float *X, float *Y, float *Drop, float *G, float *MoveY,char *Jump, float Size);

int MapChipParam(float X, float Y) {
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;
	
	return MapData[y][x];
}
//衝突判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY,float Size) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;
	float blx,brx,bby,bty;
	blx = (float)((int)afX / Size)*Size;
	brx = (float)((int)afX / Size + 1)*Size;
	bty = (float)((int)afY / Size)*Size;
	bby = (float)((int)afY / Size + 1)*Size;
	if (MapChipParam(X, afY + *MoveY - 1.0F) == 1 && *MoveY > 0.0F) {
		printf("下に当たりました");
		//移動量を補正する
		*MoveY = bty - Y - 1.0F;
		//上の壁に当たったと判定する
		return 3;
	}
	if (MapChipParam(X, afY + *MoveY + 1.0F)==1 && *MoveY < 0.0F) {
		printf("上に当たりました");
		//移動量を補正する
		*MoveY = bby - Y + 1.0F;
		//下の壁に当たったと判定する
		return 4;
	}
	if (MapChipParam(afX + *MoveX + 1.0F, Y)==1 &&*MoveX > 0.0F) {
		printf("右に当たりました");
		//移動量を補正する
		*MoveX = blx - X - 1.0F;
		//右の壁に当たったと判定する
		return 1;
	}
	if (MapChipParam(afX + *MoveX - 1.0F, Y)==1 && *MoveX < 0.0F) {
		printf("左に当たりました");
		//移動量を補正する
		*MoveX = brx + X + 1.0F;
		//左の壁に当たったと判定する
		return 2;
	}
	return 0;
}
/*(完成と呼べない段階であることが発覚したのでコメントアウト)
//移動アルゴリズム
int MoveChar(float *X, float *Y, float *MoveX, float *MoveY, float G, float *Drop, char *Jump, float Size) {
	float blx, brx, bby, bty;
	float afX = *X + *MoveX;
	float afY = *Y + *MoveY;
	//当たり判定
	blx = (float)((int)afX / Size)*Size;	//左
	brx = (float)((int)afX / Size + 1)*Size;	//右
	bty = (float)((int)afY / Size)*Size;	//上
	bby = (float)((int)afY / Size + 1)*Size;	//下
	{
		//上にすすめるのなら、更新する
		if (*MoveY < 0.0F && MapChipParam(*X, afY + *MoveY + 1.0F) == 0) {
			*Y = afY;
		}
		//進めないのなら、3を返す
		else {
			*MoveX = 0.0F;
			*Drop = -1.0F;
			*MoveY = bty - *Y + 1.0F;
			return 3;
		}
		//下にすすめるのなら、更新する
		if (*MoveY > 0.0F &&MapChipParam(*X, afY + 1.0F) == 0) {
			*Y = afY;
		}
		//進めない地面に着地したのなら、4を返す
		else {
			*MoveX = 0.0F;
			*Drop = -1.0F;
			*MoveY = bby - *Y + 1.0F;
			DrawLine(*X - 15.0F, (int)bby, *X - 15.0F, (int)bby - 15, GetColor(0, 255, 0));
			int i = GroundCheck(&*X, &*Y, &*Drop, &G, &*MoveY, &*Jump, Size);
			if (i == 0) {
				return 4;
			}
		}
		//左にすすめるなら、更新する
		if (*MoveX < 0.0F && MapChipParam(afX + *MoveX, *Y) == 0) {
			*X = afX;
			return 0;
		}
		//進めないのなら、ギリギリまで戻して1を返す
		else {
			*MoveY = 0.0F;
			*MoveX = blx - *X - 1.0F;
			return 1;
		}
		//右にすすめるのなら、更新する
		if (*MoveX > 0.0F && MapChipParam(afX + *MoveX - 1.0F, Y) == 0) {
			*X = afX;
			return 0;
		}
		//進めないのならギリギリまで戻して2を返す
		else {
			*MoveY = 0.0F;
			*MoveX = brx - *X + 1.0F;
			return 1;
		}
		//ここまで来たら移動できることを証明して終了
		return 0;
	}
}*/
int MoveCharUp(float X, float *Y, float *MoveX, float *MoveY, float *Drop,float Size) {
	float bby;
	float afY = *Y + *MoveY;
	bby = (float)((int)afY / Size + 1)*Size;
	printf("上の当たり判定を行ってます。");
	//上にすすめるのなら、更新する
	if (MapChipParam(X, afY + *MoveY - 1.0F) == 0) {
		*Y = afY;
		return 0;
	}
	//進めないのなら、3を返す
	else {
		*MoveY = bby - *Y + 1.0F;
		return 1;
	}
}
int MoveCharDown(float X, float *Y, float *MoveX, float *MoveY, float G,float *Drop,char *Jump,float Size) {
	float bty;
	float afY = *Y + *MoveY;
	bty = (float)((int)afY / Size)*Size;	//下
	printf("下の当たり判定を行ってます。");
	//下にすすめるのなら、更新する
	if (MapChipParam(X, afY + *MoveY + 1.0F) == 0) {
		*Y = afY;
		return 0;
	}
	//進めない地面に着地したのなら、4を返す
	else {
		*Drop = 0.0F;
		*MoveY = bty - *Y - 1.0F;
		int i = GroundCheck(&X, &*Y, &*Drop, &G, &*MoveY, &*Jump, Size);
		if (i == 0) {
			return 1;
		}
	}
}
int MoveCharLeft(float *X,float Y,float *MoveX,float *MoveY,float Size) {
	float blx;
	float afX = *X + *MoveX;
	blx = (float)((int)afX / Size)*Size;	//左
	printf("左の当たり判定を行ってます。");
	//左にすすめるなら、更新する
	if (MapChipParam(afX + *MoveX + 1.0F, Y) == 0) {
		*X = afX;
		return 0;
	}
	//進めないのなら、ギリギリまで戻して1を返す
	else {
		*MoveX = blx - *X - 1.0F;
		return 1;
	}
}
int MoveCharRight(float *X, float Y, float *MoveX, float *MoveY,float Size) {
	float brx;
	float afX = *X + *MoveX;
	brx = (float)((int)afX / Size + 1)*Size;	//右
	printf("右の当たり判定を行ってます。");
	//右にすすめるのなら、更新する
	if (MapChipParam(afX + *MoveX - 1.0F, Y) == 0) {
		*X = afX;
		return 0;
	}
	//進めないのならギリギリまで戻して2を返す
	else {
		*MoveX = brx - *X + 1.0F;
		return 1;
	}
}
//着地判定
int GroundCheck(float *X, float *Y, float *Drop, float *G, float *MoveY,char *Jump, float Size){
	printf("着地判定を行っています。");
	float hsize;
	hsize = Size * 0.5F;
	if (MapChipParam(*X - hsize, *Y + hsize + 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F) == 0) {
		*Jump = TRUE;
		return 1;
	}
	else {
		*MoveY = 0.0F;
		*G = 0.0F;
		*Jump = FALSE;
		return 0;
	}
}
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop,float *G,char *Jump,float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F; 
	//上下の当たり判定チェック、上に衝突したら落下させ、下に衝突したら着地させる。
	{
		if (MapHitCheck(*X + hsize, *Y + hsize + 1.0F, &Dummy, &MoveY,Size) == 3) *Drop = 0.0F;
		if (MapHitCheck(*X - hsize, *Y + hsize + 1.0F, &Dummy, &MoveY,Size) == 3) *Drop = 0.0F;
		if (MapHitCheck(*X + hsize, *Y - hsize - 1.0F, &Dummy, &MoveY,Size) == 4) *Drop = -1.0F;
		if (MapHitCheck(*X - hsize, *Y - hsize - 1.0F, &Dummy, &MoveY,Size) == 4) *Drop = -1.0F;
		//問題ないのなら移動させる
		*Y += MoveY;
	}
	//左右の当たり判定チェック
	{
		MapHitCheck(*X + hsize + 1.0F, *Y + hsize, &MoveX, &Dummy, Size);
		MapHitCheck(*X - hsize - 1.0F, *Y + hsize, &MoveX, &Dummy, Size);
		MapHitCheck(*X + hsize + 1.0F, *Y - hsize, &MoveX, &Dummy, Size);
		MapHitCheck(*X - hsize - 1.0F, *Y - hsize, &MoveX, &Dummy, Size);
		//問題ないのなら移動させる
		*X += MoveX;
	}
	{
		if (MapChipParam(*X - hsize, *Y + hsize + 1.0F + 0.5F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F + 0.5F) == 0) {
			*Jump = TRUE;
		}
		else {
			*G = 0.0F;
			*Jump = FALSE;
		}
	}
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE),SetGraphMode(320,240,32),printf("初期化しています…"); 
	if (DxLib_Init() == -1) { return -1; }
	PlayerX = 160.0F, PlayerY = 216.0F, MoveX = 0.0F, MoveY = 0.0F;
	JumpFlag = FALSE, DropPower = 0.0F, Grav = 0.5F, Dir = TRUE;
	Input = 0, EdgeInput = 0, FreamStartTime = GetNowCount();
	return 0;
}
int main(void) {
	FreamStartTime = GetNowCount();
	while (GetNowCount() - FreamStartTime < 1000 / 60) { Sleep(1); }
	system("cls");
	printf("メインループ開始\n");
	printf("\nPlayerX=%d,PlayerY=%d,Grav=%8.1f,DropPower=%8.1f", (int)PlayerX, (int)PlayerY, Grav,DropPower);
	printf("MoveX=%8.1f,MoveY=%8.1f", MoveX, MoveY);
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	//衝突する前の座標を保存する
	SaveX = PlayerX;
	SaveY = PlayerY;
	//移動処理
	{
		MoveX = 0.0F;
		MoveY = 0.0F;
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			Dir = TRUE;
			MoveX += 5.0F;
		}
		//こっちに動くと落下する
		if ((Input&PAD_INPUT_LEFT) != 0) {
			Dir = FALSE;
			MoveX -= 5.0F;
		}
		if (JumpFlag == FALSE && (EdgeInput&PAD_INPUT_1) != 0) {
			Grav = 0.5F;
			DropPower = -9.5F;
			JumpFlag = TRUE;
		}
		//落下処理
		if (MapChipParam(PlayerX-CHIP_SIZE*0.5F,PlayerY)==0&&MapChipParam(PlayerX+CHIP_SIZE*0.5F,PlayerY)==0) {
			Grav = 0.5F;
			DropPower += Grav;
			MoveY = DropPower;
		}
		CharMove(&PlayerX, &PlayerY, MoveX, MoveY, &DropPower, &Grav, &JumpFlag, CHIP_SIZE);
		/*//移動処理
		int i = MoveChar(&PlayerX, &PlayerY, &MoveX, &MoveY, Grav, &DropPower, &JumpFlag, CHIP_SIZE);
		//どういうわけか、常に上に衝突している。僕の考えでは、iが0なら、移動できるとしたいのだが…
		//ようやく、原因が見えてきたぞ。
		printf("\n現在衝突している場所(3:上、4:下、1:左、2:右)=%d", i);
		if (i != 0) {
			PlayerX = SaveX;
			PlayerY = SaveY;
		}*/
	}
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
				DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i*CHIP_SIZE + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	AllocConsole(); FILE* out = 0; freopen_s(&out, "CON", "w", stdout); Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
	init();
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		main();
	}
	DxLib_End(); fclose(out); FreeConsole();
	return 0;
}
添付ファイル
質問用.PNG
質問用.PNG (1.4 KiB) 閲覧数: 21886 回

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#68

投稿記事 by keito940 » 7年前

何回かトライ&エラーしてみた結果、当たり判定が暴走を起こしていたことにあることがわかりました。そこでその暴走を止めようと以下のコードを入れたのですが、hsizeの部分で、「式には整数型または対象範囲外の列挙型を使用する必要があります」というエラーを起こしてしまいます。どこを直せばいいのでしょうか?

コード:

//衝突判定
int MapHitCheck(float *X, float *Y, float *MoveX, float *MoveY,float Size) {
	float afX, afY;
	afX = *X + *MoveX;
	afY = *Y + *MoveY;
	float blx,brx,bby,bty;
	blx = (float)((int)afX / Size)*Size;
	brx = (float)((int)afX / Size + 1)*Size;
	bty = (float)((int)afY / Size)*Size;
	bby = (float)((int)afY / Size + 1)*Size;
	if (MapChipParam(*X, afY + *MoveY - 1.0F) == 1 && *MoveY > 0.0F) {
		printf("下に当たりました");
		//当たり判定が暴走しないようにする
		afY = *Y;
		//移動量を補正する
		*MoveY = bty - *Y - 1.0F;
		//上の壁に当たったと判定する
		return 3;
	}
	if (MapChipParam(*X, afY + *MoveY + 1.0F)==1 && *MoveY < 0.0F) {
		printf("上に当たりました");
		afY = *Y;
		//移動量を補正する
		*MoveY = bby - *Y + 1.0F;
		//下の壁に当たったと判定する
		return 4;
	}
	if (MapChipParam(afX + *MoveX + 1.0F, *Y)==1 &&*MoveX > 0.0F) {
		printf("右に当たりました");
		//当たり判定が暴走しないようにする
		afX = *X;
		//移動量を補正する
		*MoveX = blx - *X - 1.0F;
		//右の壁に当たったと判定する
		return 1;
	}
	if (MapChipParam(afX - *MoveX - 1.0F, *Y)==1 && *MoveX < 0.0F) {
		printf("左に当たりました");
		//当たり判定が暴走しないようにする
		afX = *X;
		//移動量を補正する
		*MoveX = brx - *X + 1.0F;
		//左の壁に当たったと判定する
		return 2;
	}
	return 0;
}
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop,float *G,char *Jump,float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F; 
	//上下の当たり判定チェック、上に衝突したら落下させ、下に衝突したら着地させる。
	{
		if (MapHitCheck(&*X - hsize, &*Y + hsize + 1.0F, &Dummy, &MoveY,Size) == 3) *Drop = 0.0F;
		if (MapHitCheck(&*X + hsize, &*Y + hsize + 1.0F, &Dummy, &MoveY,Size) == 3) *Drop = 0.0F;
		if (MapHitCheck(&*X - hsize, &*Y - hsize - 1.0F, &Dummy, &MoveY,Size) == 4) *Drop = -1.0F;
		if (MapHitCheck(&*X + hsize, &*Y - hsize - 1.0F, &Dummy, &MoveY,Size) == 4) *Drop = -1.0F;
		//問題ないのなら移動させる
		*Y += MoveY;
	}
	//左右の当たり判定チェック
	{
		MapHitCheck(&*X - hsize + 1.0F, &*Y + hsize, &MoveX, &Dummy, Size);
		MapHitCheck(&*X + hsize + 1.0F, &*Y + hsize, &MoveX, &Dummy, Size);
		MapHitCheck(&*X - hsize - 1.0F, &*Y - hsize, &MoveX, &Dummy, Size);
		MapHitCheck(&*X - hsize + 1.0F, &*Y - hsize, &MoveX, &Dummy, Size);
		//問題ないのなら移動させる
		*X += MoveX;
	}
	{
		if (MapChipParam(*X - hsize, *Y + hsize + 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F) == 0) {
			*Jump = TRUE;
		}
		else {
			*G = 0.0F;
			*Jump = FALSE;
		}
	}
	return 0;
}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: キャラが壁にハマってしまう

#69

投稿記事 by みけCAT » 7年前

keito940 さんが書きました:hsizeの部分で、「式には整数型または対象範囲外の列挙型を使用する必要があります」というエラーを起こしてしまいます。どこを直せばいいのでしょうか?
ポインタに実数(浮動小数点数)は足したり引いたりできない、というエラーですね。
まずは、読みにくくなる原因にもなっていると思われる、
・データが十分小さい
・呼び出される関数で書きかえない
のに引数として無駄にポインタを要求するのをやめるべきである気がします。
例えば、MapHitCheck関数のXやYは
・float型(4バイトくらい?)のデータなのでポインタ(4~8バイトくらい?)と比べて大きくない
・関数内でデータを書きかえない
という条件を満たしているので、ポインタではなくfloat型の値をそのまま渡す仕様にするべきであると思います。
MoveXやMoveYは関数内でデータを書きかえているので、ポインタまたは参照を使うべきでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#70

投稿記事 by keito940 » 7年前

つまり、ポインタはよく考えて使ってくださいということですね。ちょっと見直しました。
さて、地面に着地する空中に少し浮く上に数回着地する原因ですが、着地と同時にDropPowerに1.5Fの実数が何故か代入されてしまっていることにあるようです。
また、左に衝突すると、右に跳ね返ってしまい、右に衝突して、左に行こうとすると、もっと右に行って、そのまま画面外へと行ってしまいます。
衝突判定と当たり判定チェックのコードを見せますので、どこがおかしいのかご指摘願います。

コード:

//衝突判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY,float Size) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;
	float blx,brx,bby,bty;
	blx = (float)((int)afX / Size)*Size;
	brx = (float)((int)afX / Size + 1)*Size;
	bty = (float)((int)afY / Size)*Size;
	bby = (float)((int)afY / Size + 1)*Size;
	if (MapChipParam(X, afY + *MoveY - 1.0F) == 1 && *MoveY > 0.0F) {
		printf("下に当たりました");
		//当たり判定が暴走しないようにする
		//移動量を補正する
		*MoveY = bty - Y - 1.0F;
		//上の壁に当たったと判定する
		return 3;
	}
	if (MapChipParam(X, afY + *MoveY + 1.0F)==1 && *MoveY < 0.0F) {
		printf("上に当たりました");
		//移動量を補正する
		*MoveY = bby - Y + 1.0F;
		//下の壁に当たったと判定する
		return 4;
	}
	//右の当たり判定
	if (MapChipParam(afX + *MoveX - 1.0F, Y)==1 &&*MoveX > 0.0F) {
		printf("右に当たりました");
		//移動量を補正する
		*MoveX = blx - X - 1.0F;
		//右の壁に当たったと判定する
		return 1;
	}
	//左の当たり判定
	if (MapChipParam(afX + *MoveX + 1.0F, Y)==1 && *MoveX < 0.0F) {
		printf("左に当たりました");
		//移動量を補正する
		*MoveX = brx - X + 1.0F;
		//左の壁に当たったと判定する
		return 2;
	}
	return 0;
}
//当たり判定チェック
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop,float *G,char *Jump,float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F; 
	//上下の当たり判定チェック、上に衝突したら落下させ、下に衝突したら着地させる。
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize + 1.0F, &Dummy, &MoveY,Size) == 3) *Drop = 0.0F;
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize + 1.0F, &Dummy, &MoveY,Size) == 3) *Drop = 0.0F;
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize - 1.0F, &Dummy, &MoveY,Size) == 4) *Drop = -1.0F;
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize - 1.0F, &Dummy, &MoveY,Size) == 4) *Drop = -1.0F;
		//問題ないのなら移動させる
		*Y += MoveY;
	}
	//左右の当たり判定チェック
	{
		//左下
		MapHitCheck(*X - hsize + 1.0F, *Y + hsize, &MoveX, &Dummy, Size);
		//右上
		MapHitCheck(*X + hsize + 1.0F, *Y + hsize, &MoveX, &Dummy, Size);
		//左上
		MapHitCheck(*X - hsize - 1.0F, *Y - hsize, &MoveX, &Dummy, Size);
		//右上
		MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy, Size);
		//問題ないのなら移動させる
		*X += MoveX;
	}
	//着地判定
	{
		if (MapChipParam(*X - hsize, *Y + hsize + 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F) == 0) {
			*Jump = TRUE;
		}
		else {
			*Drop = 0.0F;
			*G = 0.0F;
			*Jump = FALSE;
		}
	}
	return 0;
}
追記:説明不足になるといけないので、少し書き足しました。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#71

投稿記事 by keito940 » 7年前

…どうやら、先程から質問している件は別なところでやってください、というわけでですね。
ということで、スレを立ててみました。近況報告はここでやりますので。
当たり判定に関する質問はこちらです。

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#72

投稿記事 by keito940 » 7年前

どうやら簡単なミスだったようです。ちなみに現在のコードは、以下のとおりです。(気づくのがおそすぎた…)

コード:

//衝突判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY, int Size) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;
	float blx, brx, bby, bty;
	blx = (float)((int)afX / Size)*Size;
	brx = (float)((int)afX / Size + 1)*Size;
	bty = (float)((int)afY / Size)*Size;
	bby = (float)((int)afY / Size + 1)*Size;
	if (MapChipParam(afX, afY) == 1) {
		if (*MoveY > 0.0F) {
			printf("\n下に当たりました。");
			//移動量を補正する
			*MoveY = bty - Y - 1.0F;
			//上の壁に当たったと判定する
			return 3;
		}
		if (*MoveY < 0.0F) {
			printf("\n上に当たりました。");
			//移動量を補正する
			*MoveY = bby - Y + 1.0F;
			//下の壁に当たったと判定する
			return 4;
		}
		//右の当たり判定
		if (*MoveX > 0.0F) {
			printf("\n右に当たりました。");
			//移動量を補正する
			*MoveX = blx - X - 1.0F;
			//右の壁に当たったと判定する
			return 1;
		}
		//左の当たり判定
		if (*MoveX < 0.0F) {
			printf("\n左に当たりました。");
			//移動量を補正する
			*MoveX = brx - X + 1.0F;
			//左の壁に当たったと判定する
			return 2;
		}
		//ここに来たら適当な値を返す
		return 4;
	}
	return 0;
}
//当たり判定チェック
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop,float *G,char *Jump,float Size){
	float Dummy = 0.0F;
	float hsize;

	hsize = Size * 0.5F; 
	//上下の当たり判定チェック、上に衝突したら落下させ、下に衝突したら着地させる。
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize - 1.0F, &Dummy, &MoveY,(int)Size) == 3) *Drop = 0.0F,MoveY -= 1.0F,printf("\n上下::左下");
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize - 1.0F, &Dummy, &MoveY,(int)Size) == 3) *Drop = 0.0F,MoveY -= 1.0F,printf("\n上下::右下");
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize + 1.0F, &Dummy, &MoveY,(int)Size) == 4) *Drop *= 1.0F,MoveY = 0.0F,printf("\n上下::左上");
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize + 1.0F, &Dummy, &MoveY,(int)Size) == 4) *Drop *= 1.0F,MoveY = 0.0F,printf("\n上下::右上");
		//問題ないのなら移動させる
		*Y += MoveY;
	}
	//左右の当たり判定チェック
	{
		//左下
		if(MapHitCheck(*X - hsize + 1.0F, *Y + hsize, &MoveX, &Dummy, (int)Size))printf("\n左右::左下");
		//右上
		if(MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy, (int)Size))printf("\n左右::右下");
		//左上
		if(MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy, (int)Size))printf("\n左右::左上");
		//右上
		if(MapHitCheck(*X + hsize - 1.0F, *Y - hsize, &MoveX, &Dummy, (int)Size))printf("\n左右::右上");
		//問題ないのなら移動させる
		*X += MoveX;
	}
	//着地判定
	{
		if (MapChipParam(*X - hsize, *Y + hsize + 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F) == 0) {
			*Jump = TRUE;
		}
		else {
			*Drop = 0.0F;
			*G = 0.0F;
			*Jump = FALSE;
		}
	}
	return 0;
}

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#73

投稿記事 by keito940 » 7年前

なんとか、完成にまでこぎつけました。ですが、今度はアクションゲームの坂道を実装しなければいけません。
サンプルコードを確認しながら、頑張っていきたいと思います。

コード:

//衝突のテストプログラム
//アクションゲームのテストシステムを作る前に、
//めり込み防止のアルゴリズムを初心者なりに作らざるをえない。
//Create 2017/02/10
#include "DxLib.h"

#define SCREEN_WIDTH (320)		//画面の横幅
#define SCREEN_HEIGHT (240)		//画面の縦幅
#define CHIP_SIZE (16)			//チップのサイズ
#define MAP_WIDTH (SCREEN_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (SCREEN_HEIGHT/CHIP_SIZE)
HANDLE Stdout;

char MapData[MAP_HEIGHT][MAP_WIDTH]
{
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
	1,0,0,0,0, 0,0,0,0,1, 1,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,1,

	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,0,0,0,0, 0,0,0,0,0, 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,1,
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
};

float PlayerX, PlayerY;
float SaveX, SaveY;
float MoveX, MoveY;
float DropPower, Grav;
char JumpFlag, Dir;

int Input, EdgeInput;
int FreamStartTime;
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY, int Size);
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop, float *G, char *Jump, float Size);
int MapChipParam(float X, float Y);

int MapChipParam(float X, float Y) {
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;

	return MapData[y][x];
}
//衝突判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY, int Size) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;
	float blx, brx, bby, bty;
	blx = (float)((int)afX / Size)*Size;
	brx = (float)((int)afX / Size + 1)*Size;
	bty = (float)((int)afY / Size)*Size;
	bby = (float)((int)afY / Size + 1)*Size;
	if (MapChipParam(afX, afY) == 1) {
		if (*MoveY > 0.0F) {
			printf("\n下に当たりました。");
			//移動量を補正する
			*MoveY = bty - Y - 1.0F;
			//上の壁に当たったと判定する
			return 3;
		}
		if (*MoveY < 0.0F) {
			printf("\n上に当たりました。");
			//移動量を補正する
			*MoveY = bby - Y + 1.0F;
			//下の壁に当たったと判定する
			return 4;
		}
		//右の当たり判定
		if (*MoveX > 0.0F) {
			printf("\n右に当たりました。");
			//移動量を補正する
			*MoveX = blx - X - 1.0F;
			//右の壁に当たったと判定する
			return 1;
		}
		//左の当たり判定
		if (*MoveX < 0.0F) {
			printf("\n左に当たりました。");
			//移動量を補正する
			*MoveX = brx - X + 1.0F;
			//左の壁に当たったと判定する
			return 2;
		}
		//ここに来たら適当な値を返す
		return 4;
	}
	return 0;
}
//当たり判定チェック
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop,float *G,char *Jump,float Size){
	float Dummy = 0.0F;
	float hsize;
	//直前フレーム
	float PrevX = *X + MoveX;
	float PrevY = *Y + MoveY;
	//ベクトルのバックアップ
	float SaveMoveX = MoveX;
	float SaveMoveY = MoveY;

	hsize = Size * 0.5F; 
	//上下の当たり判定チェック、上に衝突したら落下させ、下に衝突したら着地させる。
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize - 1.0F, &Dummy, &MoveY,(int)Size) == 3) *Drop = 0.0F,MoveY -= 1.0F,printf("\n上下::左下");
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize - 1.0F, &Dummy, &MoveY,(int)Size) == 3) *Drop = 0.0F,MoveY -= 1.0F,printf("\n上下::右下");
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize + 1.0F, &Dummy, &MoveY,(int)Size) == 4) *Drop *= -0.5F,MoveY = 0.0F,printf("\n上下::左上");
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize + 1.0F, &Dummy, &MoveY,(int)Size) == 4) *Drop *= -0.5F,MoveY = 0.0F,printf("\n上下::右上");
		//問題ないのなら移動させる
		PrevY = *Y + MoveY;
		*Y = PrevY;
	}
	//左右の当たり判定チェック
	{
		//左下
		if (MapHitCheck(*X - hsize + 1.0F, *Y + hsize, &MoveX, &Dummy, (int)Size))MoveX += 1.0F, printf("\n左右::左下");
		//右上
		if (MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy, (int)Size))MoveX -= 1.0F, printf("\n左右::右下");
		//左上
		if (MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy, (int)Size))MoveX += 1.0F, printf("\n左右::左上");
		//右上
		if (MapHitCheck(*X + hsize - 1.0F, *Y - hsize, &MoveX, &Dummy, (int)Size))MoveX -= 1.0F, printf("\n左右::右上");
		//問題ないのなら移動させる
		PrevX = *X + MoveX;
		*X = PrevX;
	}
	//着地判定
	{
		if (MapChipParam(*X - hsize, *Y + hsize + 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F) == 0) {
			*Jump = TRUE;
			*G = 0.5F;
		}
		else {
			*Drop = 0.0F;
			*G = 0.0F;
			*Jump = FALSE;
		}
	}
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE),SetGraphMode(320,240,32),printf("初期化しています…"); 
	if (DxLib_Init() == -1) { return -1; }
	PlayerX = 160.0F, PlayerY = 214.0F, MoveX = 0.0F, MoveY = 0.0F;
	JumpFlag = FALSE, DropPower = 0.0F, Grav = 0.5F, Dir = TRUE;
	Input = 0, EdgeInput = 0, FreamStartTime = GetNowCount();
	return 0;
}
int main(void) {
	FreamStartTime = GetNowCount();
	while (GetNowCount() - FreamStartTime < 1000 / 60) { Sleep(1); }
	system("cls");
	printf("メインループ開始\n");
	printf("\nPlayerX=%d,PlayerY=%d,Grav=%8.1f,DropPower=%8.1f", (int)PlayerX, (int)PlayerY, Grav,DropPower);
	printf("MoveX=%8.1f,MoveY=%8.1f,Jump=%d", MoveX, MoveY,JumpFlag);
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	//移動処理
	{
		MoveX = 0.0F;
		MoveY = 0.0F;
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			Dir = TRUE;
			MoveX += 5.0F;
		}
		if ((Input&PAD_INPUT_LEFT) != 0) {
			Dir = FALSE;
			MoveX -= 5.0F;
		}
		if (JumpFlag == FALSE && (EdgeInput&PAD_INPUT_1) != 0) {
			Grav = 0.5F;
			DropPower = -9.5F;
			JumpFlag = TRUE;
		}
		//落下処理
		DropPower += Grav;
		MoveY = DropPower;
		//移動量に基づいて移動する。
		CharMove(&PlayerX, &PlayerY, MoveX, MoveY, &DropPower, &Grav, &JumpFlag, CHIP_SIZE);
	}
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
				DrawBox(j*CHIP_SIZE, i*CHIP_SIZE, j*CHIP_SIZE + CHIP_SIZE, i*CHIP_SIZE + CHIP_SIZE, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	DrawBox((int)(PlayerX - CHIP_SIZE*0.5F), (int)(PlayerY - CHIP_SIZE*0.5F), (int)(PlayerX + CHIP_SIZE*0.5F) + 1, (int)(PlayerY + 0.5F*CHIP_SIZE), GetColor(255, 0, 0), TRUE);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	AllocConsole(); FILE* out = 0; freopen_s(&out, "CON", "w", stdout); Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
	init();
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		main();
	}
	DxLib_End(); fclose(out); FreeConsole();
	return 0;
}

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#74

投稿記事 by keito940 » 7年前

http://dixq.net/forum/viewtopic.php?f=3 ... おかしいのでしょうか?衝突判定は一応完成しました。

コード:

//衝突のテストプログラム
//アクションゲームのテストシステムを作る前に、
//めり込み防止のアルゴリズムを初心者なりに作らざるをえない。
//Create 2017/02/10
#include "DxLib.h"

#define SCREEN_WIDTH (320)		//画面の横幅
#define SCREEN_HEIGHT (240)		//画面の縦幅
#define STAGE_WIDTH  (336)
#define STAGE_HEIGHT (480)
#define CHIP_SIZE (16)			//チップのサイズ
#define MAP_WIDTH (STAGE_WIDTH/CHIP_SIZE)
#define MAP_HEIGHT (STAGE_HEIGHT/CHIP_SIZE)
HANDLE Stdout;

char MapData[MAP_HEIGHT][MAP_WIDTH]
{
	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1, 
	1,0,0,0,0, 0,0,0,0,0, 0,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, 1, 
	1,0,0,0,0, 0,0,0,0,0, 0,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, 1,

	1,0,0,0,0, 0,0,0,0,0, 0,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, 1,
	1,0,0,0,0, 0,0,0,0,0, 0,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, 1,
	1,0,0,0,0, 0,0,0,0,0, 0,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, 1,
	1,0,0,0,0, 0,0,0,0,0, 0,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, 1,
	1,0,0,0,0, 0,0,0,0,0, 0,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, 1,

	1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,
};

float PlayerX, PlayerY;
float SaveX, SaveY;
float MoveX, MoveY;
float DropPower, Grav;
char JumpFlag, Dir;

int Input, EdgeInput;
int FreamStartTime;
int CameraX = 0;
int CameraY = 0;
int CharX, CharY, View_CharX, View_CharY;
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY, int Size);
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop, float *G, char *Jump, float Size);
int MapChipParam(float X, float Y);

int MapChipParam(float X, float Y) {
	int x, y;

	x = (int)X / CHIP_SIZE;
	y = (int)Y / CHIP_SIZE;

	if (x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0) return 0;

	return MapData[y][x];
}
//衝突判定
int MapHitCheck(float X, float Y, float *MoveX, float *MoveY, int Size) {
	float afX, afY;
	afX = X + *MoveX;
	afY = Y + *MoveY;
	float blx, brx, bby, bty;
	blx = (float)((int)afX / Size)*Size;
	brx = (float)((int)afX / Size + 1)*Size;
	bty = (float)((int)afY / Size)*Size;
	bby = (float)((int)afY / Size + 1)*Size;
	if (MapChipParam(afX, afY) == 1) {
		if (*MoveY > 0.0F) {
			printf("\n下に当たりました。");
			//移動量を補正する
			*MoveY = bty - Y - 1.0F;
			//上の壁に当たったと判定する
			return 3;
		}
		if (*MoveY < 0.0F) {
			printf("\n上に当たりました。");
			//移動量を補正する
			*MoveY = bby - Y + 1.0F;
			//下の壁に当たったと判定する
			return 4;
		}
		//右の当たり判定
		if (*MoveX > 0.0F) {
			printf("\n右に当たりました。");
			//移動量を補正する
			*MoveX = blx - X - 1.0F;
			//右の壁に当たったと判定する
			return 1;
		}
		//左の当たり判定
		if (*MoveX < 0.0F) {
			printf("\n左に当たりました。");
			//移動量を補正する
			*MoveX = brx - X + 1.0F;
			//左の壁に当たったと判定する
			return 2;
		}
		//ここに来たら適当な値を返す
		return 4;
	}
	return 0;
}
//当たり判定チェック
int CharMove(float *X, float *Y, float MoveX, float MoveY, float *Drop,float *G,char *Jump,float Size){
	float Dummy = 0.0F;
	float hsize;
	//直前フレーム
	float PrevX = *X + MoveX;
	float PrevY = *Y + MoveY;
	//ベクトルのバックアップ
	float SaveMoveX = MoveX;
	float SaveMoveY = MoveY;

	hsize = Size * 0.5F; 
	//上下の当たり判定チェック、上に衝突したら落下させ、下に衝突したら着地させる。
	{
		//左下
		if (MapHitCheck(*X - hsize, *Y + hsize - 1.0F, &Dummy, &MoveY,(int)Size) == 3) *Drop = 0.0F,MoveY -= 1.0F,printf("\n上下::左下");
		//右下
		if (MapHitCheck(*X + hsize, *Y + hsize - 1.0F, &Dummy, &MoveY,(int)Size) == 3) *Drop = 0.0F,MoveY -= 1.0F,printf("\n上下::右下");
		//左上
		if (MapHitCheck(*X - hsize, *Y - hsize + 1.0F, &Dummy, &MoveY,(int)Size) == 4) *Drop *= -0.5F,MoveY = 0.0F,printf("\n上下::左上");
		//右上
		if (MapHitCheck(*X + hsize, *Y - hsize + 1.0F, &Dummy, &MoveY,(int)Size) == 4) *Drop *= -0.5F,MoveY = 0.0F,printf("\n上下::右上");
		//問題ないのなら移動させる
		PrevY = *Y + MoveY;
		*Y = PrevY;
	}
	//左右の当たり判定チェック
	{
		//左下
		if (MapHitCheck(*X - hsize + 1.0F, *Y + hsize, &MoveX, &Dummy, (int)Size))MoveX += 1.0F, printf("\n左右::左下");
		//右上
		if (MapHitCheck(*X + hsize - 1.0F, *Y + hsize, &MoveX, &Dummy, (int)Size))MoveX -= 1.0F, printf("\n左右::右下");
		//左上
		if (MapHitCheck(*X - hsize + 1.0F, *Y - hsize, &MoveX, &Dummy, (int)Size))MoveX += 1.0F, printf("\n左右::左上");
		//右上
		if (MapHitCheck(*X + hsize - 1.0F, *Y - hsize, &MoveX, &Dummy, (int)Size))MoveX -= 1.0F, printf("\n左右::右上");
		//問題ないのなら移動させる
		PrevX = *X + MoveX;
		*X = PrevX;
	}
	//着地判定
	{
		if (MapChipParam(*X - hsize, *Y + hsize + 1.0F) == 0 && MapChipParam(*X + hsize, *Y + hsize + 1.0F) == 0) {
			*Jump = TRUE;
			*G = 0.5F;
		}
		else {
			*Drop = 0.0F;
			*G = 0.0F;
			*Jump = FALSE;
		}
	}
	return 0;
}
int init(void) {
	ChangeWindowMode(TRUE),SetGraphMode(320,240,32),printf("初期化しています…"); 
	if (DxLib_Init() == -1) { return -1; }
	PlayerX = 160.0F, PlayerY = 120.0F, MoveX = 0.0F, MoveY = 0.0F;
	JumpFlag = FALSE, DropPower = 0.0F, Grav = 0.5F, Dir = TRUE;
	Input = 0, EdgeInput = 0, FreamStartTime = GetNowCount();
	return 0;
}
int main(void) {
	FreamStartTime = GetNowCount();
	while (GetNowCount() - FreamStartTime < 1000 / 60) { Sleep(1); }
	system("cls");
	printf("メインループ開始\n");
	printf("\nPlayerX=%d,PlayerY=%d,Grav=%8.1f,DropPower=%8.1f", (int)PlayerX, (int)PlayerY, Grav,DropPower);
	printf("MoveX=%8.1f,MoveY=%8.1f,Jump=%d", MoveX, MoveY,JumpFlag);
	{
		int i;
		i = GetJoypadInputState(DX_INPUT_KEY_PAD1);
		EdgeInput = i & ~Input;
		Input = i;
	}
	//移動処理
	{
		MoveX = 0.0F;
		MoveY = 0.0F;
		if ((Input&PAD_INPUT_RIGHT) != 0) {
			Dir = TRUE;
			MoveX += 5.0F;
		}
		if ((Input&PAD_INPUT_LEFT) != 0) {
			Dir = FALSE;
			MoveX -= 5.0F;
		}
		if (JumpFlag == FALSE && (EdgeInput&PAD_INPUT_1) != 0) {
			Grav = 0.5F;
			DropPower = -9.5F;
			JumpFlag = TRUE;
		}
		//落下処理
		DropPower += Grav;
		MoveY = DropPower;
		//移動量に基づいて移動する。
		CharMove(&PlayerX, &PlayerY, MoveX, MoveY, &DropPower, &Grav, &JumpFlag, CHIP_SIZE);
	}
	//カメラのチェック
	CharX = PlayerX;
	CharY = PlayerY;
	//カメラの位置を計算する
	CameraX = CharX - SCREEN_WIDTH / 2;
	CameraY = CharY - SCREEN_HEIGHT / 2;
	//カメラの補正
	if (CameraX < 0)CameraX = 0;
	if (CameraX > (STAGE_WIDTH - SCREEN_WIDTH))CameraX = (STAGE_WIDTH - SCREEN_WIDTH);
	if (CameraY < 0)CameraY = 0;
	if (CameraY > (STAGE_HEIGHT - SCREEN_HEIGHT))CameraY = (STAGE_HEIGHT - SCREEN_HEIGHT);
	//画面上の位置
	View_CharX = CharX - CameraX;
	View_CharY = CharY + CameraY;
	//マップの描画
	{
		int i, j;
		for (i = 0; i < MAP_HEIGHT; i++) {
			for (j = 0; j < MAP_WIDTH; j++) {
				if (MapData[i][j] == 1) {
					DrawBox(j*CHIP_SIZE + CameraX, i*CHIP_SIZE + CameraY, j*CHIP_SIZE + CHIP_SIZE + CameraX, i*CHIP_SIZE + CHIP_SIZE + CameraY, GetColor(255, 255, 255), TRUE);
				}
			}
		}
	}
	//キャラの描画
	DrawBox((int)(View_CharX), (int)(View_CharY), (int)(View_CharX+CHIP_SIZE) + 1, (int)(View_CharY+CHIP_SIZE) + 1, GetColor(255, 0, 0), TRUE);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	AllocConsole(); FILE* out = 0; freopen_s(&out, "CON", "w", stdout); Stdout = GetStdHandle(STD_OUTPUT_HANDLE);
	init();
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		main();
	}
	DxLib_End(); fclose(out); FreeConsole();
	return 0;
}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: キャラが壁にハマってしまう

#75

投稿記事 by みけCAT » 7年前

オフトピック
衝突判定が完成して問題が「キャラが壁にハマってしまう」ではなくなったのなら、別のトピックにするべきであるような気が…
「キャラの重力のとカメラの動きが逆になってしまいます」というのは意味がよくわからないのですが、
View_CharXの計算だけはカメラの座標をちゃんと引いているのに、他(View_CharY, マップ)ではカメラの座標を足してしまっているのはよくなさそうですね。
カメラが動いた分被写体は逆に動いて見えるはずなので、座標は引かないといけません。
camera-20170226.png
カメラと座標の関係
camera-20170226.png (5.36 KiB) 閲覧数: 21418 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

keito940
記事: 105
登録日時: 7年前

Re: キャラが壁にハマってしまう

#76

投稿記事 by keito940 » 7年前

ということは解決というわけですね…。
ありがとうございました。

閉鎖

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