弾の壁との判定

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

弾の壁との判定

#1

投稿記事 by Mk. » 13年前

bullet関数というものを最後に追加し、弾が壁に当たった場合には弾を消す(shot_flag=0)ようにしました。
同じ方向でも、貫通できる壁,できない壁ができてしまいました。
新たにスペースキーを押しながら方向キーを押すことで、方向だけ変えれるようになりました。
20x20の画像を準備してコンパイルお願いします。
また、Esc以外で閉じてしまうとプロセスが残ったままなってしまうので普段はint main(void)の中に書いているのですが解決方法はありますか?

コード:

#include"DxLib.h"

int able_walk(struct player);//進行方向を判定する
int bullet(struct shot);//弾が壁に当たったら弾を消す。

struct player{//player構造体
	int x,y;
	int direction;
};

struct shot{//shot構造体
	int x,y;
	int direction;
};


int map[5][5]={{0,0,1,1,0},//ダンジョン形
{1,0,0,0,0},
{0,0,1,0,1},
{0,1,0,0,1},
{1,1,1,0,1}};


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
			 LPSTR lpCmdLine, int nCmdShow )
{
	ChangeWindowMode(TRUE);
	SetDrawScreen(DX_SCREEN_BACK);


	if(DxLib_Init()==-1)
		return -1;
	int graph;
	int walk_flag=0;
	int shot_flag=0;
	int space_flag=0;
	int map_color;
	int cr=GetColor(255,255,0);
	int i,j;

	struct shot shots;
	struct player pc;//0:上向き,1:下,2:右,3:左

	shots.x;
	shots.y;
	shots.direction;

	pc.x=20;
	pc.y=0;
	pc.direction=1;

	map_color=GetColor(255,255,255);

	graph=LoadGraph("円.jpg");//20x20の円の画像

	while(1){  
		ProcessMessage();
		ClearDrawScreen();
		/*-------------------------------------
		キャラクターの移動処理
		スペースキーを押しっぱなしのまま方向キーで
		方向転換(進まずに方向転換)
		---------------------------------------*/
		if(pc.x%20==0&&pc.y%20==0){
			walk_flag=1;
			if(CheckHitKey(KEY_INPUT_UP)==1)
				pc.direction=0;		
			else if(CheckHitKey(KEY_INPUT_DOWN)==1)
				pc.direction=1;
			else if(CheckHitKey(KEY_INPUT_RIGHT)==1)
				pc.direction=2;
			else if(CheckHitKey(KEY_INPUT_LEFT)==1)
				pc.direction=3;
			else if(CheckHitKey(KEY_INPUT_SPACE)==1)//スペースキーが押されているか
				space_flag=1;
			else {
				walk_flag=0;
				space_flag=0;
			}
			if(walk_flag==1){
				if(able_walk(pc)==1)
					walk_flag=0;
			}
		}
		if((walk_flag==1)&&space_flag==0){
			if     (pc.direction==0)
				pc.y--;
			else if(pc.direction==1)
				pc.y++;
			else if(pc.direction==2)
				pc.x++;
			else if(pc.direction==3)
				pc.x--;
		}

		//ショット
		if(CheckHitKey(KEY_INPUT_W)==1&&shot_flag==0){
			shots.x=pc.x;
			shots.y=pc.y;
			shots.direction=pc.direction;

			if(pc.direction==0)
				DrawBox(shots.x+7,shots.y-10,shots.x+12,shots.y,cr,TRUE);
			else if(pc.direction==1)//下向き
				DrawBox(shots.x+7,shots.y+20,shots.x+12,shots.y+30,cr,TRUE);
			else if(pc.direction==2)//右向き
				DrawBox(shots.x+20,shots.y+7,shots.x+30,shots.y+12,cr,TRUE);
			else if(pc.direction==3)//左向き
				DrawBox(shots.x-10,shots.y+7,shots.x,shots.y+12,cr,TRUE);

			shot_flag=1;
		}
		if(CheckHitKey(KEY_INPUT_ESCAPE)==1)//※ゲーム終了
			break;

		//キャラクター描写
		DrawGraph(pc.x,pc.y,graph,TRUE);

		//弾描写
		if(shot_flag==1){
			if(shots.direction==0)
				shots.y-=2; 
			else if(shots.direction==1)
				shots.y+=2;
			else if(shots.direction==2)
				shots.x+=2;
			else if(shots.direction==3)
				shots.x-=2;

			if(shots.x<0||shots.y<0||shots.x>100||shots.y>100)
				shot_flag=0;
			if(shots.direction==0)
				DrawBox(shots.x+7,shots.y-10,shots.x+12,shots.y,cr,TRUE);
			else if(shots.direction==1)//下向き
				DrawBox(shots.x+7,shots.y+20,shots.x+12,shots.y+30,cr,TRUE);
			else if(shots.direction==2)//右向き
				DrawBox(shots.x+20,shots.y+7,shots.x+30,shots.y+12,cr,TRUE);
			else if(shots.direction==3)//左向き
				DrawBox(shots.x-10,shots.y+7,shots.x,shots.y+12,cr,TRUE);

			if(bullet(shots)==1){
				shot_flag=0;
			}


		}


		//map描写	
		for(i=0;i<5;i++){
			for(j=0;j<5;j++){
				if(map[j][i]==1)
					DrawBox(i*20,j*20,i*20+20,j*20+20,map_color,TRUE);
			}
		}

		ScreenFlip();
	}

	DxLib_End();

	return 0;
}

int able_walk(struct player pc)//進行方向が壁ならばエラー(1)を返す
{
	if(pc.direction==0)//上
		if(map[pc.y/20-1][pc.x/20]==1)
			return 1;//エラー
	if(pc.direction==1)//下
		if(map[pc.y/20+1][pc.x/20]==1)
			return 1;
	if(pc.direction==2)//右
		if(map[pc.y/20][pc.x/20+1]==1)
			return 1;
	if(pc.direction==3)//左
		if(map[pc.y/20][pc.x/20-1]==1)
			return 1;

	return 0;//正常
}
int bullet(struct shot shots)
{
	if(shots.direction==0)
		if(map[shots.y/10+1][shots.x/5]==1)
			return 1;//エラー(壁に衝突)
	if(shots.direction==1)
		if(map[shots.y/10-1][shots.x/5]==1)
			return 1;
	if(shots.direction==2)
		if(map[shots.y/5][shots.x/10+1]==1)
			return 1;
	if(shots.direction==3)
		if(map[shots.y/5][shots.x/10-1]==1)
			return 1;

	return 0;//壁にぶつかってない

}

アバター
へにっくす
記事: 634
登録日時: 13年前
住所: 東京都

Re: 弾の壁との判定

#2

投稿記事 by へにっくす » 13年前

Mk. さんが書きました:Esc以外で閉じてしまうとプロセスが残ったままなってしまうので普段はint main(void)の中に書いているのですが解決方法はありますか?
えーと
弾の動きについて
のトントンさんのコメント、みていないのですか?
ProcessMessage関数の戻り値を、whileの条件式にあてりゃいいだけだよ?
written by へにっくす

トントン
記事: 100
登録日時: 15年前

Re: 弾の壁との判定

#3

投稿記事 by トントン » 13年前

http://dixq.net/forum/viewtopic.php?f=3&t=11429
こちらで、softyaさんも
とりあえず「新ゲームプログラミングの館」のコードを参考にされてはどうでしょうか?
http://dixq.net/g/
まだ読まれていなかったらひと通り読まれることをおすすめします。
と、述べています。
全部でなくても、さっと見ては如何でしょう?

アバター
Dixq (管理人)
管理人
記事: 1662
登録日時: 15年前
住所: 北海道札幌市
連絡を取る:

Re: 弾の壁との判定

#4

投稿記事 by Dixq (管理人) » 13年前

コードは役割ごとに関数化すると見やすいですよ。
動き部分に関してサンプルを書いてみました、こんな感じでどうでしょう。
http://dixq.net/code/walksample.zip

今はmain.cppにほとんど書いていますが、これをファイルごとに書くともっと見やすくなるでしょう。
モジュールを多重化出来るようにしておけば、プレイヤーとほとんど同じ仕組みで弾も実現可能になると思います。

Keyboardについては、
http://dixq.net/g/
こちらのd.4章を使用しています。

必要な説明はコメントに書きました。
ザっと書いただけなので、どこかおかしいかもしれませんが・・
イメージ掴んで頂けるのではないかと思います。

いずれにしても、一度ゲームプログラミングの館を一読頂いた方が理解が早いと思います。
(特にゲーム設計編等)

コード:

#include "DxLib.h"
#include "Keyboard.h"

//向き
enum eDirection_t{
	eLeft,
	eUp,
	eRight,
	eDown,
};

//プレイヤーの構造体
struct Player_t{
	int  x,y;		//座標
	bool isMoving;	//動いているか?
	eDirection_t eDirection;	//向き
};

const static int BLOCK_SIZE = 32;	//ブロックサイズ
const static int SPEED = 2;			//移動スピード
const static int XN = 10;			//ブロックの水平方向の数
const static int YN = 10;			//ブロックの鉛直方向の数

const static int map[YN][XN]={	//マップ
	{1,1,1,1,1,1,1,1,1,1},
	{1,0,1,0,0,0,0,0,0,1},
	{1,0,1,1,1,1,1,1,0,1},
	{1,0,0,0,0,0,0,1,0,1},
	{1,0,1,1,1,1,0,1,0,1},
	{1,0,1,0,0,1,0,1,0,1},
	{1,0,1,1,0,1,0,1,0,1},
	{1,0,1,1,0,1,1,1,0,1},
	{1,0,0,0,0,0,0,0,0,1},
	{1,1,1,1,1,1,1,1,1,1}
};

//プレイヤー構造体
Player_t player = {BLOCK_SIZE*1, BLOCK_SIZE*1, false, eDown};

//画像ハンドル格納用変数
int imgBack, imgBlock, imgPlayer;

//ロード
void load(){
	imgBack   = LoadGraph("image/back.png");
	imgBlock  = LoadGraph("image/block.png");
	imgPlayer = LoadGraph("image/player.png");
}

//directionの方向に進めるか?
bool canGo(eDirection_t direction){
	int xn=0, yn=0;
	switch(direction){//方向ごとに
	case eLeft:
		xn--;
		break;
	case eUp:
		yn--;
		break;
	case eRight:
		xn++;
		break;
	case eDown:
		yn++;
		break;
	}
	//その方向のマップの要素を見て、0なら進める、1なら進めない信号を返す
	if(map[player.y/BLOCK_SIZE+yn][player.x/BLOCK_SIZE+xn]==0){//本来要素範囲外アクセスチェックをすべき
		return true;
	} else {
		return false;
	}
}

//動かす
void move(){
	if( player.isMoving ){//動いているなら
		switch(player.eDirection){
		case eLeft:
			player.x -= SPEED;
			break;
		case eUp:
			player.y -= SPEED;
			break;
		case eRight:
			player.x += SPEED;
			break;
		case eDown:
			player.y += SPEED;
			break;
		}
		//32x32ずつ進めるので、下の位置に来るととりあえず止める
		if( player.x%BLOCK_SIZE==0 && player.y%BLOCK_SIZE==0 ){
			player.isMoving = false;
		}
	}
}

//動き状態を変える
void changeMovingStatus(){
	if( player.isMoving == false ){//動いていないのなら、キーの入力に応じて状態変化させる
		bool isKeyDown = false;//今十字キーが押されているか
		if     ( Keyboard_Get(KEY_INPUT_LEFT) ){
			isKeyDown = true;
			player.eDirection = eLeft;
		}
		else if( Keyboard_Get(KEY_INPUT_UP) ){
			isKeyDown = true;
			player.eDirection = eUp;
		}
		else if( Keyboard_Get(KEY_INPUT_RIGHT) ){
			isKeyDown = true;
			player.eDirection = eRight;
		}
		else if( Keyboard_Get(KEY_INPUT_DOWN) ){
			isKeyDown = true;
			player.eDirection = eDown;
		}
		if( isKeyDown ){//十字キーが押されていたら
			if( canGo(player.eDirection) ){//その方向に進めるかどうかチェックし
				player.isMoving = true;//その方向に進ませる
			}
		}
	}
}

//描画する
void draw(){
	for(int y=0; y<YN; y++){
		for(int x=0; x<XN; x++){
			if(map[y][x]==0){
				DrawGraph(x*BLOCK_SIZE, y*BLOCK_SIZE, imgBack, TRUE);
			} else {
				DrawGraph(x*BLOCK_SIZE, y*BLOCK_SIZE, imgBlock, TRUE);
			}
		}
	}
	DrawGraph(player.x, player.y, imgPlayer, TRUE);
}

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK);
	load();//画像読み込み
	while(!ScreenFlip()&&!ProcessMessage()&&!ClearDrawScreen()){
		Keyboard_Update();//キーボードの更新
		move();//キャラを動かす
		changeMovingStatus();//キャラの移動状態変更
		draw();//描画
	}
	DxLib_End();
	return 0;
}
添付ファイル
testDx.png

アバター
Dixq (管理人)
管理人
記事: 1662
登録日時: 15年前
住所: 北海道札幌市
連絡を取る:

Re: 弾の壁との判定

#5

投稿記事 by Dixq (管理人) » 13年前

ショットについてのサンプルが無かったので、ショットも含めてサンプル作ってみました。

2時間位かかったのであまりにコードが長くなってしまった感がありますが。。。。

http://dixq.net/code/SampleDjnGame.zip

中に入っているexeファイルをダブルクリックすれば遊べます。
十字キーで移動、Zキーでショットが打てます。
なるべくピュアCで分かりやすく書いたつもりです。
しばらくピュアC書いてないので結構戸惑いましたが。。。

main.cppから見ていけばわかると思います。
Mgrと名付いている物は、その下にあるモジュールを管理している物です。

基本的にゲームプログラミングの館にある「ゲーム設計」の延長であそこに書いてある通りに実装しています。
添付ファイル
game.png

Mk.
記事: 4
登録日時: 13年前
住所: 石川県

Re: 弾の壁との判定

#6

投稿記事 by Mk. » 13年前

サンプルまで作っていただきありがとうございます。
人の作ったコードを読むいい機会になりました。

閉鎖

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