ジャンプさせ、着地したときにその位置で止める

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

ジャンプさせ、着地したときにその位置で止める

#1

投稿記事 by chalaza » 14年前

アクションゲームをつくっており、DXライブラリサンプルのマップチップを参考にさせてもらい
壁と空間の設定ができて、キャラの画像の四隅を使って左右に壁があるときは歩けないようにできたので
ジャンプの処理に取り掛かりました。
私の作ったコードは、ジャンプ中は『Jump』という変数が1で、着地中は0という設定にしたうえで、
キャラの右下と左下がマップチップの『1』(床)だったら『Jump』を0にして、スペースキーを押したら『Jump』を1にして飛び上がらせ、
『Jump』が1の間だけキャラを落下させるというコードを組みました。
歩いているときに踏み外した場合も『Jump』を1にさせるところまでいったのですが、
着地したときに落下速度を0にするだけでは床にめりこんでしまうことになってしまいました。
床の位置を座標で指定していたときは着地したら床のY座標にキャラを動かせば良いのですが、
マップチップで考えると着地した床だけの座標が決まっていないので『キャラのY座標をこの位置にうごかす』
ということができない気がするんですが…着地したらキャラのY座標をどう動かせばよいのでしょうか…

ちなみにキャラの画像は64×64の大きさの画像の中心に32×64の縦2マス分のキャラが描かれています。
24コマ入っていますが今は12コマしか使ってません。

コード:

 
#include "DxLib.h"


//構造体

			//プレイヤー構造体	
	struct Playerdata{
			int X, Y, img;
	}Player;

////

int Key[256];
 
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
        else                            GetHitKeyStateAll_InputKey[i]=0;
    }
    return 0;
}


#define MAP_SIZE	32			// マップチップ一つのドットサイズ
#define MAP_WIDTH	20			// マップの幅
#define MAP_HEIGHT	15			// マップの縦長さ
// マップのデータ
int 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, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
} ;

 /////

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

	
// 画像をロード
		//マップ
	int lenga1 = LoadGraph( "image/map/lenga1.png" );
	int statesbar = LoadGraph( "image/statesbar.png" );
	int haikei1 = LoadGraph( "image/haikei1.png" );
		//キャラ関係
	int chara[24];		//キャラ画像
	int HPgazou[11];	//HPの画像
	LoadDivGraph( "image/chara.png" , 24 , 6 , 4 , 64 , 64 , chara );//プレイヤー
	LoadDivGraph( "image/HP.png" , 11 , 1 , 11 , 224 , 32 , HPgazou );//体力


//関数

	Player.X = 32 , Player.Y = 288 ;	//プレイヤー座標

	int JumpPower = 0 ;			//ジャンプパワー
	int Jump = 0 ;				//ジャンプ状態か
	int walkdirection = 1 ;		//歩く向き
	int walkanime = 0 ;			//歩くアニメーション用

	int HP = 10 ;				//HP
	int HPimg ;					//HP画像
	int i , j ;					//座標用



    while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
          //↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない
 
//ココから
		//背景を描画
	DrawGraph( 0, 0, haikei1, FALSE ); // 背景

		// マップを描画
		for( i = 0 ; i < MAP_HEIGHT ; i ++ )
		{
			for( j = 0 ; j < MAP_WIDTH ; j ++ )
			{
				if( MapData[ i ][ j ] == 1 ) //1のとき壁を描画
				{
					DrawGraph( j * MAP_SIZE , i * MAP_SIZE , lenga1 , FALSE ) ;
				}
			}
		}

			// ジャンプ状態じゃなく、ジャンプボタンを押して地面についていたらジャンプ
		if ( Jump==0 && (Key[KEY_INPUT_SPACE] >=1 ))
			if(MapData[(Player.Y+63)/32][(Player.X + 17)/32] != 1
				&&MapData[(Player.Y+63)/32][(Player.X + 47)/32] != 1)
					{
			JumpPower = 16 ;
			Jump = 1 ;
		}

			//ジャンプ状態で右向きなら右ジャンプの画像
		if ( walkdirection == 1 && Jump == 1 ){
			Player.img=chara[5];
		}

			//ジャンプ状態で左向きなら左ジャンプの画像
		if ( walkdirection == 0 && Jump == 1 ){
			Player.img=chara[11];
		}


        if( Key[ KEY_INPUT_RIGHT ] >= 1 ) {		//右キーが押されて
			if(MapData[(Player.Y)/32][(Player.X + 47)/32] != 1		//右が壁じゃなかったら
				&&MapData[(Player.Y+63)/32][(Player.X + 47)/32] != 1)
			Player.X+=3 ;	//右に動く
			walkdirection = 1 ;
		}

        if( Key[ KEY_INPUT_RIGHT ] >= 1 && Jump== 0 ){	// 右キーが押されていてジャンプ状態じゃなかったら
					walkanime++;
					Player.img=chara[(walkanime/10)%4 +1];//右に歩くアニメ
		}

		if( walkdirection == 1 && ( Key[ KEY_INPUT_RIGHT ] == 0 )&& Jump== 0 )// 右キーが離されてジャンプ状態じゃなかったら
				Player.img=chara[0];		//右を向く
		

		if( Key[ KEY_INPUT_LEFT ] >= 1 ){// 左キーが押されて
			if(MapData[(Player.Y)/32][(Player.X+17)/32] != 1
				&&MapData[(Player.Y+63)/32][(Player.X+17)/32] != 1)		//左が壁じゃなかったら
			Player.X-=3 ;	//左に動く
			walkdirection = 0 ;
	}

		if(( Key[ KEY_INPUT_LEFT  ] >= 1 ) && Player.Y == 288 && Jump== 0 ){	// 左キーが押されていてジャンプ状態じゃなかったら
					walkanime++;
					Player.img=chara[(walkanime/10)%4 +7];//右に歩くアニメ
		}

		if( walkdirection == 0 && ( Key[ KEY_INPUT_LEFT ] == 0 ) && Jump== 0 )	// 左キーが離されてジャンプ状態じゃなかったら
				Player.img=chara[6];		//左を向く

		if( Key[ KEY_INPUT_RIGHT ] >= 1 && Key[ KEY_INPUT_LEFT  ] >= 1)//左右両方押されてたら右向く
			Player.img=chara[0];



		// ジャンプ中ならキャラの落下処理
		if(Jump == 1){
			Player.Y -= JumpPower ;
			JumpPower -= 1 ;
		}

	// ジャンプ中にキャラが地面についたら落下をやめる
		if(Jump == 1)
			if(MapData[(Player.Y+65)/32][(Player.X + 17)/32] != 0
				&&MapData[(Player.Y+65)/32][(Player.X + 47)/32] != 0)
	{
		JumpPower = 0 ;
		Jump = 0 ;
	}

	//歩いているときに踏み外したらジャンプ状態にする
		if(Jump == 0)
			if(MapData[(Player.Y+65)/32][(Player.X + 17)/32] != 1
				&&MapData[(Player.Y+65)/32][(Player.X + 47)/32] != 1)
	{
		Jump = 1 ;
	}
	
	//HP
	if( HP==10 )
		HPimg = HPgazou[10];

			//画像

	DrawGraph( Player.X, Player.Y, Player.img, TRUE ); // x,y の位置にキャラを描画


	//ステータスバー背景
	for(int y=0 ; y<1 ; y++){
		for(int x=0 ; x<20 ; x++){
			DrawGraph(x*32+0,y*32+418,statesbar,FALSE);
			}
	}

	DrawGraph( 0, 420, HPimg, TRUE ); // HPバー
 
 
 
        ScreenFlip();
    }
 
    DxLib_End();
    return 0;
}



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

Re: ジャンプさせ、着地したときにその位置で止める

#2

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

落下で床にめり込んだら、床のマップパーツの座標を基準にプレイヤー座標を上に補正するれば大丈夫です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

chalaza

Re: ジャンプさせ、着地したときにその位置で止める

#3

投稿記事 by chalaza » 14年前

マップの座標を基準にってことは
キャラのY座標にMapDataを使った値を代入しても良いということでしょうか…
物分かりわるくてすみません
マップデータの壁にめりこんだらプレイヤーの足元のY座標を32で割ったマップデータ座標を代入したつもりですが
やっぱりおかしいようですね…

コード:

#include "DxLib.h"


//構造体

			//プレイヤー構造体	
	struct Playerdata{
			int X, Y, img;
	}Player;

////

int Key[256];
 
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
        else                            GetHitKeyStateAll_InputKey[i]=0;
    }
    return 0;
}


#define MAP_SIZE	32			// マップチップ一つのドットサイズ
#define MAP_WIDTH	20			// マップの幅
#define MAP_HEIGHT	15			// マップの縦長さ
// マップのデータ
int 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, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
} ;

 /////

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

	
// 画像をロード
		//マップ
	int lenga1 = LoadGraph( "image/map/lenga1.png" );
	int statesbar = LoadGraph( "image/statesbar.png" );
	int haikei1 = LoadGraph( "image/haikei1.png" );
		//キャラ関係
	int chara[24];		//キャラ画像
	int HPgazou[11];	//HPの画像
	LoadDivGraph( "image/chara.png" , 24 , 6 , 4 , 64 , 64 , chara );//プレイヤー
	LoadDivGraph( "image/HP.png" , 11 , 1 , 11 , 224 , 32 , HPgazou );//体力


//関数

	Player.X = 32 , Player.Y = 288 ;	//プレイヤー座標

	int JumpPower = 0 ;			//ジャンプパワー
	int Jump = 0 ;				//ジャンプ状態か
	int walkdirection = 1 ;		//歩く向き
	int walkanime = 0 ;			//歩くアニメーション用

	int HP = 10 ;				//HP
	int HPimg ;					//HP画像
	int i , j ;					//座標用



    while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
          //↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない
 
//ココから
		//背景を描画
	DrawGraph( 0, 0, haikei1, FALSE ); // 背景

		// マップを描画
		for( i = 0 ; i < MAP_HEIGHT ; i ++ )
		{
			for( j = 0 ; j < MAP_WIDTH ; j ++ )
			{
				if( MapData[ i ][ j ] == 1 ) //1のとき壁を描画
				{
					DrawGraph( j * MAP_SIZE , i * MAP_SIZE , lenga1 , FALSE ) ;
				}
			}
		}

			// ジャンプ状態じゃなく、ジャンプボタンを押して地面についていたらジャンプ
		if ( Jump==0 && (Key[KEY_INPUT_SPACE] >=1 ))
			if(MapData[(Player.Y+63)/32][(Player.X + 17)/32] != 1
				&&MapData[(Player.Y+63)/32][(Player.X + 47)/32] != 1)
					{
			JumpPower = 16 ;
			Jump = 1 ;
		}

			//ジャンプ状態で右向きなら右ジャンプの画像
		if ( walkdirection == 1 && Jump == 1 ){
			Player.img=chara[5];
		}

			//ジャンプ状態で左向きなら左ジャンプの画像
		if ( walkdirection == 0 && Jump == 1 ){
			Player.img=chara[11];
		}


        if( Key[ KEY_INPUT_RIGHT ] >= 1 ) {		//右キーが押されて
			if(MapData[(Player.Y)/32][(Player.X + 47)/32] != 1		//右が壁じゃなかったら
				&&MapData[(Player.Y+63)/32][(Player.X + 47)/32] != 1)
			Player.X+=3 ;	//右に動く
			walkdirection = 1 ;
		}

        if( Key[ KEY_INPUT_RIGHT ] >= 1 && Jump== 0 ){	// 右キーが押されていてジャンプ状態じゃなかったら
					walkanime++;
					Player.img=chara[(walkanime/10)%4 +1];//右に歩くアニメ
		}

		if( walkdirection == 1 && ( Key[ KEY_INPUT_RIGHT ] == 0 )&& Jump== 0 )// 右キーが離されてジャンプ状態じゃなかったら
				Player.img=chara[0];		//右を向く
		

		if( Key[ KEY_INPUT_LEFT ] >= 1 ){// 左キーが押されて
			if(MapData[(Player.Y)/32][(Player.X+17)/32] != 1
				&&MapData[(Player.Y+63)/32][(Player.X+17)/32] != 1)		//左が壁じゃなかったら
			Player.X-=3 ;	//左に動く
			walkdirection = 0 ;
	}

		if(( Key[ KEY_INPUT_LEFT  ] >= 1 ) && Player.Y == 288 && Jump== 0 ){	// 左キーが押されていてジャンプ状態じゃなかったら
					walkanime++;
					Player.img=chara[(walkanime/10)%4 +7];//右に歩くアニメ
		}

		if( walkdirection == 0 && ( Key[ KEY_INPUT_LEFT ] == 0 ) && Jump== 0 )	// 左キーが離されてジャンプ状態じゃなかったら
				Player.img=chara[6];		//左を向く

		if( Key[ KEY_INPUT_RIGHT ] >= 1 && Key[ KEY_INPUT_LEFT  ] >= 1)//左右両方押されてたら右向く
			Player.img=chara[0];



		// ジャンプ中ならキャラの落下処理
		if(Jump == 1){
			Player.Y -= JumpPower ;
			JumpPower -= 1 ;
		}

	// ジャンプ中にキャラが地面についたら落下をやめる
		if(Jump == 1)
			if(MapData[(Player.Y+65)/32][(Player.X + 17)/32] != 0
				&&MapData[(Player.Y+65)/32][(Player.X + 47)/32] != 0)
	{
		JumpPower = 0 ;
		Jump = 0 ;
	}


	//床にめりこんだら床の上のY座標に移動(おかしい)
			if(MapData[(Player.Y+66)/32][(Player.X + 17)/32] != 0
				&&MapData[(Player.Y+66)/32][(Player.X + 47)/32] != 0)
	{
		Player.Y = MapData[(Player.Y+65)/32][(Player.X)];
	}


	//歩いているときに踏み外したらジャンプ状態にする
		if(Jump == 0)
			if(MapData[(Player.Y+65)/32][(Player.X + 17)/32] != 1
				&&MapData[(Player.Y+65)/32][(Player.X + 47)/32] != 1)
	{
		Jump = 1 ;
	}
	
	//HP
	if( HP==10 )
		HPimg = HPgazou[10];

			//画像

	DrawGraph( Player.X, Player.Y, Player.img, TRUE ); // x,y の位置にキャラを描画


	//ステータスバー背景
	for(int y=0 ; y<1 ; y++){
		for(int x=0 ; x<20 ; x++){
			DrawGraph(x*32+0,y*32+418,statesbar,FALSE);
			}
	}

	DrawGraph( 0, 420, HPimg, TRUE ); // HPバー
 
 
 
        ScreenFlip();
    }
 
    DxLib_End();
    return 0;
}

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

Re: ジャンプさせ、着地したときにその位置で止める

#4

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

着地した場合は、(Player.Y+65)/32がマップに既にキャラが刺さった状態ですよね。
なので、これを補正する場合は刺さったマップチップの上の座標を計算しますので
Player.Y = ((Player.Y+65)/32) * 32 - 65 - 1
と言う式になると思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

chalaza

Re: ジャンプさせ、着地したときにその位置で止める

#5

投稿記事 by chalaza » 14年前

softyaさんの式を参考にさせていただき(最後は+1でした)、
いろいろ間違いがあったので訂正してみて、
キャラの右下、右上より1ドット右の部分が壁なら右へ進めなくし、めりこまないよう左に補正し、
キャラの左下、左上より1ドット左の部分が壁なら左へ進めなくし、右に補正。
キャラの右下、左下より1ドット下の部分が床なら着地させ(jump=0)、上に補正。
このようにしたつもりなのですが、壁に向かって歩きながらジャンプすると壁にひっかかって途中で止まり、空中で壁向きに歩いてしまうようになりました…
キャラの着地判定のX座標はしっかりキャラの画像内におさめたので、ジャンプしたまま着地はしないと思ったのですが…
何か他の所がおかしいのでしょうか…

キャラの画像は64×64の中心に縦64×横32の縦2マス分のキャラなので、
キャラの画像内の位置は、横:X+17~X+47ドット、縦:Y~Y+63ドットだと思います。

コード:


#include "DxLib.h"


//構造体

			//プレイヤー構造体	
	struct Playerdata{
			int X, Y, img;
	}Player;

////

int Key[256];
 
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
        else                            GetHitKeyStateAll_InputKey[i]=0;
    }
    return 0;
}


#define MAP_SIZE	32			// マップチップ一つのドットサイズ
#define MAP_WIDTH	20			// マップの幅
#define MAP_HEIGHT	15			// マップの縦長さ
// マップのデータ
int MapData[ MAP_HEIGHT ][ MAP_WIDTH ] =
	{
		{ 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, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
} ;

 /////

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

	
// 画像をロード
		//マップ
	int lenga1 = LoadGraph( "image/map/lenga1.png" );
	int statesbar = LoadGraph( "image/statesbar.png" );
	int haikei1 = LoadGraph( "image/haikei1.png" );
		//キャラ関係
	int chara[24];		//キャラ画像
	int HPgazou[11];	//HPの画像
	LoadDivGraph( "image/chara.png" , 24 , 6 , 4 , 64 , 64 , chara );//プレイヤー
	LoadDivGraph( "image/HP.png" , 11 , 1 , 11 , 224 , 32 , HPgazou );//体力


//関数

	Player.X = 32 , Player.Y = 288 ;	//プレイヤー座標

	int JumpPower = 0 ;			//ジャンプパワー
	int Jump = 0 ;				//ジャンプ状態か
	int walkdirection = 1 ;		//歩く向き
	int walkanime = 0 ;			//歩くアニメーション用

	int HP = 10 ;				//HP
	int HPimg ;					//HP画像
	int i , j ;					//座標用



    while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
          //↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない
 
//ココから
		//背景を描画
	DrawGraph( 0, 0, haikei1, FALSE ); // 背景

		// マップを描画
		for( i = 0 ; i < MAP_HEIGHT ; i ++ )
		{
			for( j = 0 ; j < MAP_WIDTH ; j ++ )
			{
				if( MapData[ i ][ j ] == 1 ) //1のとき壁を描画
				{
					DrawGraph( j * MAP_SIZE , i * MAP_SIZE , lenga1 , FALSE ) ;
				}
			}
		}

			// ジャンプ状態じゃなく、ジャンプボタンを押して地面についていたらジャンプ
		if ( Jump==0 && (Key[KEY_INPUT_SPACE] >=1 ))
			if(MapData[(Player.Y+64)/32][(Player.X + 16)/32] != 0
				||MapData[(Player.Y+64)/32][(Player.X + 47)/32] != 0)
					{
			JumpPower = 16 ;
			Jump = 1 ;
		}

			//ジャンプ状態で右向きなら右ジャンプの画像
		if ( walkdirection == 1 && Jump == 1 ){
			Player.img=chara[5];
		}

			//ジャンプ状態で左向きなら左ジャンプの画像
		if ( walkdirection == 0 && Jump == 1 ){
			Player.img=chara[11];
		}


        if( Key[ KEY_INPUT_RIGHT ] >= 1 ) {		//右キーが押されて
			if(MapData[(Player.Y)/32][(Player.X + 48)/32] == 0		//右が壁じゃなかったら
				||MapData[(Player.Y+63)/32][(Player.X + 48)/32] == 0)
			Player.X+=3 ;	//右に動く
			walkdirection = 1 ;
		}

        if( Key[ KEY_INPUT_RIGHT ] >= 1 && Jump== 0 ){	// 右キーが押されていてジャンプ状態じゃなかったら
					walkanime++;
					Player.img=chara[(walkanime/10)%4 +1];//右に歩くアニメ
		}

		if( walkdirection == 1 && ( Key[ KEY_INPUT_RIGHT ] == 0 )&& Jump== 0 )// 右キーが離されてジャンプ状態じゃなかったら
				Player.img=chara[0];		//右を向く
		

		if( Key[ KEY_INPUT_LEFT ] >= 1 ){// 左キーが押されて
			if(MapData[(Player.Y)/32][(Player.X+15)/32] == 0
				||MapData[(Player.Y+63)/32][(Player.X+15)/32] == 0)		//左が壁じゃなかったら
			Player.X-=3 ;	//左に動く
			walkdirection = 0 ;
	}

		if( Key[ KEY_INPUT_LEFT  ] >= 1 && Jump== 0 ){	// 左キーが押されていてジャンプ状態じゃなかったら
					walkanime++;
					Player.img=chara[(walkanime/10)%4 +7];//右に歩くアニメ
		}

		if( walkdirection == 0 && ( Key[ KEY_INPUT_LEFT ] == 0 ) && Jump== 0 )	// 左キーが離されてジャンプ状態じゃなかったら
				Player.img=chara[6];		//左を向く

		if( Key[ KEY_INPUT_RIGHT ] >= 1 && Key[ KEY_INPUT_LEFT  ] >= 1)//左右両方押されてたら右向く
			Player.img=chara[0];



		// ジャンプ中ならキャラの落下処理
		if(Jump == 1){
			Player.Y -= JumpPower ;
			JumpPower -= 1 ;
		}

	// ジャンプ中にキャラが地面についたら落下をやめる
		if(Jump == 1)
			if(MapData[(Player.Y+64)/32][(Player.X + 16)/32] != 0
				||MapData[(Player.Y+64)/32][(Player.X + 47)/32] != 0)
	{
		JumpPower = 0 ;
		Jump = 0 ;
	}

	//歩いているときに踏み外したらジャンプ状態にする
		if(Jump == 0)
			if(MapData[(Player.Y+64)/32][(Player.X + 16)/32] == 0
				&&MapData[(Player.Y+64)/32][(Player.X + 47)/32] == 0)
	{
		Jump = 1 ;
	}
	

	//補正//
	//床にめりこんだら上に補正
			if(MapData[(Player.Y+64)/32][(Player.X + 16)/32] != 0
				||MapData[(Player.Y+64)/32][(Player.X + 47)/32] != 0)
	{
		Player.Y = ((Player.Y+65)/32) * 32 - 65 + 1 ;
	}
	//右の壁にめりこんだら左に補正
			if(MapData[(Player.Y)/32][(Player.X + 48)/32] != 0
				||MapData[(Player.Y+63)/32][(Player.X + 48)/32] != 0)	
	{
		Player.X = ((Player.X+65)/32) * 32 - 65 + 16 + 1 ;
	}
	//左の壁にめりこんだら右に補正
			if(MapData[(Player.Y)/32][(Player.X+15)/32] != 0
				||MapData[(Player.Y+63)/32][(Player.X+15)/32] != 0)
	{
		Player.X = ((Player.X+65)/32) * 32 - 65 + 16 + 1 ;
	}
	

	//HP
	if( HP==10 )
		HPimg = HPgazou[10];

			//画像

	DrawGraph( Player.X, Player.Y, Player.img, TRUE ); // x,y の位置にキャラを描画


	//ステータスバー背景
	for(int y=0 ; y<1 ; y++){
		for(int x=0 ; x<20 ; x++){
			DrawGraph(x*32+0,y*32+418,statesbar,FALSE);
			}
	}

	DrawGraph( 0, 420, HPimg, TRUE ); // HPバー
 
 
 
        ScreenFlip();
    }
 
    DxLib_End();
    return 0;
}

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

Re: ジャンプさせ、着地したときにその位置で止める

#6

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

// ジャンプ中にキャラが地面についたら落下をやめる
でJumpPowerがマイナス時に地面チェックをしないと駄目だと思います。+時は無視。

あと地面チェックよりも先に左右の壁めり込み補正をしないと壁にめり込んだ時に着地と勘違いします。

細かい数値は絵がないのでコチラでの調整は難しいのでご了承ください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

chalaza

Re: ジャンプさせ、着地したときにその位置で止める

#7

投稿記事 by chalaza » 14年前

どうやらその通り処理の順番だったようです。あと落下中だけの着地判定を設定したら壁隣での不可解なジャンプ力も解決しました。
ついでに天井に頭があたったときの処理も左右の補正より前に書いたらうまくいきました。
ちなみに、キャラが縦2マス分ということで、キャラの四隅だけでは1マス分の足場に横から突っ込んだときにおかしくなるので
キャラの2マス分両方の四隅、合計8座標で左右補正をしたら完璧になりました。ありがとうございました。

コード:

#include "DxLib.h"


//構造体

			//プレイヤー構造体	
	struct Playerdata{
			int X, Y, img;
	}Player;

////

int Key[256];
 
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
        else                            GetHitKeyStateAll_InputKey[i]=0;
    }
    return 0;
}


#define MAP_SIZE	32			// マップチップ一つのドットサイズ
#define MAP_WIDTH	20			// マップの幅
#define MAP_HEIGHT	15			// マップの縦長さ
// マップのデータ
int 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, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1 } ,
		{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1 } ,
		{ 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ,
} ;

 /////

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

	
// 画像をロード
		//マップ
	int lenga1 = LoadGraph( "image/map/lenga1.png" );
	int statesbar = LoadGraph( "image/statesbar.png" );
	int haikei1 = LoadGraph( "image/haikei1.png" );
	int testimg = LoadGraph( "image/testimg.png" );
	//キャラ関係
	int chara[24];		//キャラ画像
	int HPgazou[11];	//HPの画像
	LoadDivGraph( "image/chara.png" , 24 , 6 , 4 , 64 , 64 , chara );//プレイヤー
	LoadDivGraph( "image/HP.png" , 11 , 1 , 11 , 224 , 32 , HPgazou );//体力


//関数

	Player.X = 32 , Player.Y = 288 ;	//プレイヤー座標

	int JumpPower = 0 ;			//ジャンプパワー
	int Jump = 0 ;				//ジャンプ状態か
	int walkdirection = 1 ;		//歩く向き
	int walkanime = 0 ;			//歩くアニメーション用

	int HP = 10 ;				//HP
	int HPimg ;					//HP画像
	int i , j ;					//座標用



    while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
          //↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない
 
//ココから
		//背景を描画
	DrawGraph( 0, 0, haikei1, FALSE ); // 背景

		// マップを描画
		for( i = 0 ; i < MAP_HEIGHT ; i ++ )
		{
			for( j = 0 ; j < MAP_WIDTH ; j ++ )
			{
				if( MapData[ i ][ j ] == 1 ) //1のとき壁を描画
				{
					DrawGraph( j * MAP_SIZE , i * MAP_SIZE , lenga1 , FALSE ) ;
				}
			}
		}

			// ジャンプ状態じゃなく、ジャンプボタンを押して地面についていたらジャンプ
		if ( Jump==0 && (Key[KEY_INPUT_SPACE] >=1 ) && JumpPower <= 0)
			if(MapData[(Player.Y+64)/32][(Player.X + 16)/32] != 0
				||MapData[(Player.Y+64)/32][(Player.X + 47)/32] != 0)
					{
			JumpPower = 16 ;
			Jump = 1 ;
		}

			//ジャンプ状態で右向きなら右ジャンプの画像
		if ( walkdirection == 1 && Jump == 1 ){
			Player.img=chara[5];
		}

			//ジャンプ状態で左向きなら左ジャンプの画像
		if ( walkdirection == 0 && Jump == 1 ){
			Player.img=chara[11];
		}


        if( Key[ KEY_INPUT_RIGHT ] >= 1 ) {		//右キーが押されて
			if(MapData[(Player.Y)/32][(Player.X + 48)/32] == 0		//右が壁じゃなかったら
				&&MapData[(Player.Y+31)/32][(Player.X + 48)/32] == 0
				&&MapData[(Player.Y+32)/32][(Player.X + 48)/32] == 0
				&&MapData[(Player.Y+63)/32][(Player.X + 48)/32] == 0)
			Player.X+=3 ;	//右に動く
			walkdirection = 1 ;
		}

        if( Key[ KEY_INPUT_RIGHT ] >= 1 && Jump== 0 ){	// 右キーが押されていてジャンプ状態じゃなかったら
					walkanime++;
					Player.img=chara[(walkanime/10)%4 +1];//右に歩くアニメ
		}

		if( walkdirection == 1 && ( Key[ KEY_INPUT_RIGHT ] == 0 )&& Jump== 0 )// 右キーが離されてジャンプ状態じゃなかったら
				Player.img=chara[0];		//右を向く
		

		if( Key[ KEY_INPUT_LEFT ] >= 1 ){// 左キーが押されて
			if(MapData[(Player.Y)/32][(Player.X+15)/32] == 0
				&&MapData[(Player.Y+31)/32][(Player.X+15)/32] == 0
				&&MapData[(Player.Y+32)/32][(Player.X+15)/32] == 0
				&&MapData[(Player.Y+63)/32][(Player.X+15)/32] == 0)		//左が壁じゃなかったら
			Player.X-=3 ;	//左に動く
			walkdirection = 0 ;
	}

		if( Key[ KEY_INPUT_LEFT  ] >= 1 && Jump== 0 ){	// 左キーが押されていてジャンプ状態じゃなかったら
					walkanime++;
					Player.img=chara[(walkanime/10)%4 +7];//右に歩くアニメ
		}

		if( walkdirection == 0 && ( Key[ KEY_INPUT_LEFT ] == 0 ) && Jump== 0 )	// 左キーが離されてジャンプ状態じゃなかったら
				Player.img=chara[6];		//左を向く

		if( Key[ KEY_INPUT_RIGHT ] >= 1 && Key[ KEY_INPUT_LEFT  ] >= 1)//左右両方押されてたら右向く
			Player.img=chara[0];



		// ジャンプ中ならキャラの落下処理
		if(Jump == 1){
			Player.Y -= JumpPower ;
			JumpPower -= 1 ;
		}

	//補正//
	//床にめりこんだら上に補正
			if(JumpPower < 0)
				if(MapData[(Player.Y+64)/32][(Player.X + 16)/32] != 0
				||MapData[(Player.Y+64)/32][(Player.X + 47)/32] != 0)
	{
		Player.Y = ((Player.Y+65)/32) * 32 - 65 + 1 ;
	}
	//天井にめりこんだら下に補正
			if(JumpPower > 0)
				if(MapData[(Player.Y-1)/32][(Player.X + 16)/32] != 0
				||MapData[(Player.Y-1)/32][(Player.X + 47)/32] != 0)
	{
		Player.Y = ((Player.Y+65)/32) * 32 - 65 + 32 + 1 ;
		JumpPower = 0 ;
	}

	//右の壁にめりこんだら左に補正
			if(MapData[(Player.Y)/32][(Player.X + 48)/32] != 0
				||MapData[(Player.Y+63)/32][(Player.X + 48)/32] != 0)	
	{
		Player.X = ((Player.X+65)/32) * 32 - 65 + 16 + 1 ;
	}
	//左の壁にめりこんだら右に補正
			if(MapData[(Player.Y)/32][(Player.X+15)/32] != 0
				||MapData[(Player.Y+63)/32][(Player.X+15)/32] != 0)
	{
		Player.X = ((Player.X+65)/32) * 32 - 65 + 16 + 1 ;
	}




	// ジャンプ中にキャラが地面についたら落下をやめる
		if(Jump == 1 && JumpPower < 0 )
			if(MapData[(Player.Y+64)/32][(Player.X + 16)/32] != 0
				||MapData[(Player.Y+64)/32][(Player.X + 47)/32] != 0)
	{
		JumpPower = 0 ;
		Jump = 0 ;
	}

	//歩いているときに踏み外したらジャンプ状態にする
		if(Jump == 0)
			if(MapData[(Player.Y+64)/32][(Player.X + 16)/32] == 0
				&&MapData[(Player.Y+64)/32][(Player.X + 47)/32] == 0)
	{
		Jump = 1 ;
	}
	


	//HP
	if( HP==10 )
		HPimg = HPgazou[10];

			//画像

	DrawGraph( Player.X, Player.Y, Player.img, TRUE ); // x,y の位置にキャラを描画


	//ステータスバー背景
	for(int y=0 ; y<1 ; y++){
		for(int x=0 ; x<20 ; x++){
			DrawGraph(x*32+0,y*32+418,statesbar,FALSE);
			}
	}

	DrawGraph( 0, 420, HPimg, TRUE ); // HPバー
 
 	DrawGraph( 0, 0, testimg, FALSE ); // テストイメージ
 
        ScreenFlip();
    }
 
    DxLib_End();
    return 0;
}

閉鎖

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