C++で倉庫番のようなものを作っています

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

C++で倉庫番のようなものを作っています

#1

投稿記事 by EKISUKE » 13年前

C++(opneframeworks)で倉庫番のようなものををつくっています。
ルールとしては制限時間内に操作キャラの吸い込み、吹き飛ばし機能を使いゴールまで導くというものです。
マップは以下のように配列で作っています。

コード:

int mapdata[3][15][20]={
	{ // 1ステージ目
		{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},	//1
		{1,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1},	//2
		{1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,0,1},	//3
		{1,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,1,0,1},	//4
		{1,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,1,2,1},	//5
		{1,0,4,0,0,0,0,1,1,1,1,1,1,0,1,0,1,1,1,1},	//6
		{1,0,0,0,0,0,0,1,1,1,1,0,0,0,1,0,1,1,1,1},	//7
		{1,0,0,0,4,0,0,1,1,1,1,4,1,1,0,0,0,0,1,1},	//8
		{1,0,0,0,0,0,0,1,1,1,1,0,1,1,0,1,1,0,1,1},	//9
		{1,0,4,0,0,0,0,1,1,1,1,0,0,1,0,1,1,0,1,1},	//10
		{1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,1,0,1,1},	//11
		{1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,1,0,1,1},	//12
		{1,0,0,4,0,0,0,1,1,1,1,1,1,1,1,0,0,0,1,1},	//13
		{1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1},	//14
		{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}	//15
	},

	{ // 2ステージ目
		{1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},	//1
		{0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0},	//2
		{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},	//3
		{1,0,0,0,0,0,0,0,1,1,1,1,1,0,1,0,1,0,0,1},	//4
		{1,0,0,0,0,0,0,0,1,1,1,1,1,0,1,0,1,0,2,1},	//5
		{1,0,0,0,0,0,0,0,1,1,1,1,1,0,1,0,1,0,0,1},	//6
		{1,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,1,0,0,1},	//7
		{1,0,0,0,0,0,0,0,1,1,1,0,1,1,0,0,0,0,0,1},	//8
		{1,0,0,0,0,0,0,0,1,1,1,0,1,1,0,1,1,0,0,1},	//9
		{1,0,0,0,0,0,0,0,0,1,1,0,0,1,0,1,1,0,0,1},	//10
		{1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,0,0,1},	//11
		{1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,1,0,0,1},	//12
		{1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1},	//13
		{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},	//14
		{1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}	//15
	},

	{ // 3ステージ目
		{2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},	//1
		{1,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1},	//2
		{1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,0,1},	//3
		{1,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,1,0,1},	//4
		{1,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,1,2,1},	//5
		{1,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,1,1,1},	//6
		{1,0,0,0,0,0,0,1,1,1,1,0,0,0,1,0,1,1,1,1},	//7
		{1,0,0,0,0,0,0,1,1,1,1,0,1,1,0,0,0,0,1,1},	//8
		{1,0,0,0,0,0,0,1,1,1,1,0,1,1,0,1,1,0,1,1},	//9
		{1,0,0,0,0,0,0,1,1,1,1,0,0,1,0,1,1,0,1,1},	//10
		{1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,1,0,1,1},	//11
		{1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,1,0,1,1},	//12
		{1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,1,1},	//13
		{1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1},	//14
		{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}	//15
	}
};
今はまだゲームの機能ができていないので、マップの構造は適当です。
画面サイズは(800,600)です。

やりたいこととしましては、
2ステージ目の[1][0]に操作キャラがいる場合左方向に吸い込みをすると[1][17]から[1][19]までに玉があれば吸い込んで、操作キャラと同じ座標に移動させたいのです。


吸い込む機能の関数は以下のとおりです。

コード:

//	吸い込まれる関数
 void testApp::reach(float *pos_x,float *pos_y,float tpos_x,float tpos_y){
	const int BLOCK_SIZE = 40;
        
        //仮想的に上下左右にもう1ステージを作りそっちの配列を調べるようにした
	//プレイヤーの進む先にブロックのサイズ20個分(もう1ステージ分)足し配列に戻してから1ステージ分引いて元の場所にもどす。
	int circleX = ((int)*pos_x +BLOCK_SIZE * 20) / BLOCK_SIZE - 20;
	int circleY = ((int)*pos_y +BLOCK_SIZE * 15) / BLOCK_SIZE - 15;

		circleX = (circleX + 20) % 20;									//	マイナスの値も正の値にもどす
		circleY = (circleY + 15) % 15;

		
	int z = circle.stage;                                       //配列[z][y][x]の[z]
	int x = ((int)tpos_x  + BLOCK_SIZE * 20)/ BLOCK_SIZE - 20;  //配列[z][y][x]の[x]
	int y = ((int)tpos_y  + BLOCK_SIZE * 15)/ BLOCK_SIZE - 15;  //配列[z][y][x]の[y]
	int offsetX, offsetY;
	    
		x = (x + 20) % 20;
		y = (x + 15) % 15;
	   
	// 左方向
	if( player.axisX < 0 && y == circleY ){           // player.axisX(プレイヤーの向きに*4したもの)<0(プレイヤーの向きが左)かつy == circleY(Y座標の配列番号が同じ)なら
		for(int i=0; i<abs(player.axisX); i++) { //  i < abs(player.axisX)(=4)だけX方向の配列を調べる
			offsetX = x - i;
			if( offsetX < 0 ) break;		// 配列外を参照しないため
			if( mapdata[z][y][offsetX] == 1 ) break;
			if( mapdata[z][y][offsetX] == 4 && offsetX == circleX ){	//	玉とキャラの間に壊れる壁があったら
				mapdata[z][y][offsetX] = 0;	//	その配列のデータを0にして床にする
			}
			

			if( offsetX == circleX || offsetX + circleX == 20 ){	// 調べた配列先が玉の配列の同じかまたは(足したときに20になったら←仮)
				if(abs(*pos_x - tpos_x) < 3) break;				// 玉とプレイヤーの長さが3より小さければ以下の処理を飛ばす
				if(player.blow_active == false){					// 吹き飛ばすフラグがfalseなら玉の座標を+2.0fづつしていく
					*pos_x += 2.0f;
				}else{
					*pos_x -= 2.0f;									// trueなら玉の座標を-2.0fしていく
				}
				break;
			}
		}
	}
	// 右方向
	else if( player.axisX > 0 && y == circleY){
		for(int i=0; i < abs(player.axisX); i++){
			offsetX = x + i;
			if( offsetX > 20 )break;
			if( mapdata[z][y][offsetX] == 1)break;
			if( mapdata[z][y][offsetX] == 4 && offsetX == circleX){
				mapdata[z][y][offsetX] = 0;
			}

			if( offsetX == circleX || offsetX + circleX == 20){
				if(abs(*pos_x - tpos_x) < 3) break;
				if(player.blow_active == false){
					*pos_x -= 2.0f;
				}else{
					*pos_x += 2.0f;
				}
				break;
			}
		}
	}
	//上方向
	else if( player.axisY < 0 && x == circleX){
		for(int i = 0; i < abs(player.axisY); i++){
			offsetY = y - i;
			if( offsetY < 0)break;
			if( mapdata[z][offsetY][x] == 1) break;
			if( mapdata[z][offsetY][x] == 4 && offsetY == circleY){
				mapdata[z][offsetY][x] = 0;
			}

			if( offsetY == circleY ){
				if(abs(*pos_y - tpos_y) < 3) break;
				if(player.blow_active == false){
					*pos_y += 2.0f;
				}else{
					*pos_y -= 2.0f;
				}
				break;
			}
		}
	}
	//下方向
	else if( player.axisY > 0 && x == circleX){
		for(int i = 0; i < abs(player.axisY); i++){
			offsetY = y + i;
			if( offsetY < 0)break;
			if( mapdata[z][offsetY][x] == 1) break;
			if( mapdata[z][offsetY][x] == 4 && offsetY == circleY){		
				mapdata[z][offsetY][x] = 0;
			}

			if( offsetY == circleY ){
				if(abs(*pos_y - tpos_y) < 3) break;
				if(player.blow_active == false){
					*pos_y -= 2.0f;
				}else{
					*pos_y += 2.0f;
				}
				break;
			}
		}
	}
}
色々説明不足なのですが、すみません。
足りないところ言っていただければ補足していきます。
回答お願いします。

たいちう
記事: 418
登録日時: 14年前

Re: C++で倉庫番のようなものを作っています

#2

投稿記事 by たいちう » 13年前

必要十分な情報を下さい。
まずソースコードですが、コンパイル・実行できる最小限のもの。

2ステージでの操作を聞きたいならば、2ステージ以外のマップは不要です。
左方向の吸い込みがうまくいかないならば、それ以外の方向も取りあえずは不要。
独自ルールである「吸い込み」についても、この説明では判りません。

回答が得られやすいような質問をまとめて下さい。
その過程で問題の本質に自分で気付くことも多いです。

EKISUKE

Re: C++で倉庫番のようなものを作っています

#3

投稿記事 by EKISUKE » 13年前

たいちう さんが書きました:必要十分な情報を下さい。
まずソースコードですが、コンパイル・実行できる最小限のもの。
ファイルを添付するのはどうすればいいのでしょうか・・・
返信の時のボタンを見たり、ヘルプをみたのですが、わかりませんでした。

たいちう さんが書きました: 2ステージでの操作を聞きたいならば、2ステージ以外のマップは不要です。
左方向の吸い込みがうまくいかないならば、それ以外の方向も取りあえずは不要。
独自ルールである「吸い込み」についても、この説明では判りません。
吸い込みは操作キャラの方向から玉が操作キャラ3つ分以内であれば玉が操作キャラの方向へ向かって進み、
操作キャラの座標と玉の座標の差が3以内であれば操作キャラと玉の座標を同じにして吸い込みが終わるというような感じです。
今はスペースキーを押し続けてる間操作キャラの方向に進み玉と操作キャラの間に壁がなければ操作キャラ玉がかさなると吸い込みが終わります。
reachでやっているのは操作キャラから操作キャラの向いている方向に配列3つ分しらべ、調べているときに調べている座標(OffsetX)と玉のXの配列circleXが同じだったら
操作キャラ方向へ座標を移動させていくというものです。
たいちう さんが書きました: 回答が得られやすいような質問をまとめて下さい。
その過程で問題の本質に自分で気付くことも多いです。
わかりました。すこし考えてみます。
回答有難うございます。

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

Re: C++で倉庫番のようなものを作っています

#4

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

EKISUKE さんが書きました:ファイルを添付するのはどうすればいいのでしょうか・・・
返信の時のボタンを見たり、ヘルプをみたのですが、わかりませんでした。
ファイルの添付は登録ユーザーでないとできません。
アップローダーなどをお使いください。
http://www.axfc.net/uploader/
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: C++で倉庫番のようなものを作っています

#5

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

ファイルを公開するには、ここのmixc++の会員になってもらうか、何処かのアップローダを利用してください。
mixc++の会員なら投稿時にファイル添付タブからzipファイルなどを添付できます。
なお、圧縮ファイルにはipch/debugなどのフォルダや拡張子sdf等のファイルは不要です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

EKISUKE

Re: C++で倉庫番のようなものを作っています

#6

投稿記事 by EKISUKE » 13年前

http://www1.axfc.net/uploader/Li/so/134859
DLkey : EKISUKE

openframeworks(of_preRelease_v007_vs2010)の中のappsの中にフォルダを作ってその中に保存すれば動くと思います。
みけCAT さんが書きました:ファイルの添付は登録ユーザーでないとできません。
アップローダーなどをお使いください。
http://www.axfc.net/uploader/
有難うございます。このような形でいいのでしょうか?
softya(ソフト屋) さんが書きました:なお、圧縮ファイルにはipch/debugなどのフォルダや拡張子sdf等のファイルは不要です。
一応削除しましたが大丈夫でしょうか?

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

Re: C++で倉庫番のようなものを作っています

#7

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

申し訳ないですが、我が家ではアップローダーのサーバーが遅すぎて途中でエラーになりダウンロード出来ませんでした。
mixc++に登録してもらったほうがよさそうです。登録ボタンは、このページの左下にあります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

Re: C++で倉庫番のようなものを作っています

#8

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

softya(ソフト屋) さんが書きました:申し訳ないですが、我が家ではアップローダーのサーバーが遅すぎて途中でエラーになりダウンロード出来ませんでした。
mixc++に登録してもらったほうがよさそうです。登録ボタンは、このページの左下にあります。
僕の環境でも厳しそうです。
ただ、mixc++に10MB相当のファイルをUPする事って
できるんですかね?(日記の方で12MBぐらいのzipをUPしようとしたら失敗したため)

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

Re: C++で倉庫番のようなものを作っています

#9

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

トントン さんが書きました:
softya(ソフト屋) さんが書きました:申し訳ないですが、我が家ではアップローダーのサーバーが遅すぎて途中でエラーになりダウンロード出来ませんでした。
mixc++に登録してもらったほうがよさそうです。登録ボタンは、このページの左下にあります。
僕の環境でも厳しそうです。
ただ、mixc++に10MB相当のファイルをUPする事って
できるんですかね?(日記の方で12MBぐらいのzipをUPしようとしたら失敗したため)
40MBぐらいはアップされていのは見たことがりますがアップは光じゃないと遅いとは思います。
ダメそうなら、すごく小さくなるソース/ヘッダだけでもお願いします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

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

Re: C++で倉庫番のようなものを作っています

#10

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

softya(ソフト屋) さんが書きました:
トントン さんが書きました:
softya(ソフト屋) さんが書きました:申し訳ないですが、我が家ではアップローダーのサーバーが遅すぎて途中でエラーになりダウンロード出来ませんでした。
mixc++に登録してもらったほうがよさそうです。登録ボタンは、このページの左下にあります。
僕の環境でも厳しそうです。
ただ、mixc++に10MB相当のファイルをUPする事って
できるんですかね?(日記の方で12MBぐらいのzipをUPしようとしたら失敗したため)
40MBぐらいはアップされていのは見たことがりますがアップは光じゃないと遅いとは思います。
ダメそうなら、すごく小さくなるソース/ヘッダだけでもお願いします。
他の方の添付ファイルを見ても
普通に10MB以上あげていますね。僕ん所は回線貧弱なのかな。。。orz

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#11

投稿記事 by EKISUKE » 13年前

ファイル添付のタブの許可拡張子にカーソルを合わせたところzipは8MBまでだそうなので、ヘッダとCPPだけはいっているsrcを添付してみました。
添付ファイル
summerworks.zip
これでいけてますか?
(5.72 KiB) ダウンロード数: 167 回
最後に編集したユーザー EKISUKE on 2012年8月17日(金) 15:48 [ 編集 1 回目 ]

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

Re: C++で倉庫番のようなものを作っています

#12

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

EKISUKE さんが書きました:ファイルを参照して追加ボタンを押しましたが、これでいけてますかね
添付されていませんね。
投稿前にアップロードが終わってなかったのかも知れません。
添付が成功すればファイル添付欄が出来るはずなんですが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#13

投稿記事 by EKISUKE » 13年前

追加をおしてもページがリロードされて記入していた文字が全部消えて初期状態にもどるだけですね・・

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

Re: C++で倉庫番のようなものを作っています

#14

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

EKISUKE さんが書きました:追加をおしてもページがリロードされて記入していた文字が全部消えて初期状態にもどるだけですね・・
ちなみにzipファイルでしょうか?
文字が全部消えるのも変な症状なんですけどね。
ブラウザによって動作に問題があるのかも知れません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#15

投稿記事 by EKISUKE » 13年前

ブラウザはFirefoxですね。
一応上のほうのレスにファイル添付できたようです。
画像がをつかっているので画像を入れたいのですが、
画像以外のファイルが大きいようなので画像だけzipにして添付してみましたが、これで大丈夫ですか?
添付ファイル
summerworks.zip
(26.35 KiB) ダウンロード数: 128 回

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

Re: C++で倉庫番のようなものを作っています

#16

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

EKISUKE さんが書きました:ブラウザはFirefoxですね。
一応上のほうのレスにファイル添付できたようです。
画像がをつかっているので画像を入れたいのですが、
画像以外のファイルが大きいようなので画像だけzipにして添付してみましたが、これで大丈夫ですか?
画像とソースはOKでした。
画像やソース以外が大きいとすると他にも余分なフォルダがあるんでしょうね。

ofMain.hって何のライブラリでしょうか?
GLUTを使っているのは分かったのですがofMain.hが無いのでエラーになります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#17

投稿記事 by EKISUKE » 13年前

Openframeworksですね。
そのライブラリだと思います。
なので、openframeworks(of_preRelease_v007_vs2010)の中のappsの中にフォルダを作ってその中に保存すれば動くと思います。

おそらくここからダウンロードしていただければ手に入ると思います。
http://openframeworks.jp/download/

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

Re: C++で倉庫番のようなものを作っています

#18

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

2010版は諸事情で動かないので古い2008版をダウンロードしています。
うごくと良いなぁ。 少し不安。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#19

投稿記事 by EKISUKE » 13年前

softya(ソフト屋) さんが書きました:2010版は諸事情で動かないので古い2008版をダウンロードしています。
うごくと良いなぁ。 少し不安。
お手数おかけしてすみません。

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

Re: C++で倉庫番のようなものを作っています

#20

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

EKISUKE さんが書きました:
softya(ソフト屋) さんが書きました:2010版は諸事情で動かないので古い2008版をダウンロードしています。
うごくと良いなぁ。 少し不安。
お手数おかけしてすみません。
ちと挫折気味。あとでまた再挑戦します。
なんでヘッダとかバラバラなんだ・・・(^^;)
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#21

投稿記事 by EKISUKE » 13年前

softya(ソフト屋) さんが書きました: ちと挫折気味。あとでまた再挑戦します。
なんでヘッダとかバラバラなんだ・・・(^^;)
ヘッダバラバラでしたかすみません。
お願いします。
有難うございます。

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

Re: C++で倉庫番のようなものを作っています

#22

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

駄目な例かもしれません。
とりあえず、こんな感じに編集してみました程度です。
参考程度で見てください。

コード:

	// 左方向
	if( player.axisX < 0 && y == circleY ){						// player.axisX(プレイヤーの向きに*4したもの)<0(プレイヤーの向きが左)かつy == circleY(Y座標の配列番号が同じ)なら
		//for(int i=0; i<abs(player.axisX); i++) {				//  i < abs(player.axisX)(=4)だけX方向の配列を調べる
		for(int i=0; i< 20; i++) {	
			if (i<abs(player.axisX)){
				offsetX = x - i;
				if( offsetX < 0 ) break;							// 配列外を参照しないため
				if( mapdata[z][y][offsetX] == 1 ) break;
				if( mapdata[z][y][offsetX] == 4 && offsetX == circleX ){//	玉とキャラの間に壊れる壁があったら
					mapdata[z][y][offsetX] = 0;						//	その配列のデータを0にして床にする
				}

				if( offsetX == circleX || offsetX + circleX == 20 ){	// 調べた配列先が玉の配列の同じかまたは
					if(abs(*pos_x - tpos_x) < 3) break;					// 玉とプレイヤーの長さが3より小さければ以下の処理を飛ばす
					if(player.blow_active == false){					// 吹き飛ばすフラグがfalseなら玉の座標を+2.0fづつしていく
						*pos_x += 2.0f;
						if (*pos_x >= 800) {
							*pos_x = 0;
						}
					}else{
						*pos_x -= 2.0f;									// trueなら玉の座標を-2.0fしていく
					}
					break;
				}
			}
		}
	}
	// 右方向
	else if( player.axisX > 0 && y == circleY){
		for(int i=0; i < abs(player.axisX); i++){
			offsetX = x + i;
			if (offsetX == 20){
				offsetX = 0;
			}
			if( offsetX > 20 )break;
			if( mapdata[z][y][offsetX] == 1)break;
			if( mapdata[z][y][offsetX] == 4 && offsetX == circleX){
				mapdata[z][y][offsetX] = 0;
			}

			if( offsetX == circleX || offsetX + circleX == 20){
				if(abs(*pos_x - tpos_x) < 3) break;
				if(player.blow_active == false){
					*pos_x -= 2.0f;
					if (*pos_x <= 0) {
						*pos_x = 800;
					}
				}else{
					*pos_x += 2.0f;
				}
				break;
			}
		}
	}
原因
自機が[1][19]、赤丸が[1][0]のとき、
offsetが19なので、ループでまわしても赤丸に対して判定が届きません。
自機が[1][0]、赤丸が[1][19]のとき、
offsetが0なので、ループでまわしてもaxisX=4なので赤丸に対して判定が届きません。
なので、境界を越えたときに値を変えてやるというのがいいのかなと思いました。
作りかけだと思うので他の件に関してはスルーしときます。

(面白そうなので、完成したらぜひとも遊ばせてくださいね。)

追記
駄目な例かもしれませんというか駄目でした。
左方向と、右方向でソースがばらばらな奴をあげてしまった。。。
時間ないので、また後で考えます。

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

Re: C++で倉庫番のようなものを作っています

#23

投稿記事 by ISLe » 13年前

コード:

	// オフセット(?)を初期設定
	offsetX = x;
	offsetY = y;

	// 左方向
	if( player.axisX < 0 && y == circleY ) {          // player.axisX(プレイヤーの向きに*4したもの)<0(プレイヤーの向きが左)かつy == circleY(Y座標の配列番号が同じ)なら
		for(int i=1; i<abs(player.axisX); i++) {
			//  i < abs(player.axisX)(=4)だけX方向の配列を調べる
			-- offsetX;
			offsetX = (offsetX + 20) % 20;
			//【削除】if( offsetX < 0 ) break;        // 配列外を参照しないため
			if( mapdata[z][y][offsetX] == 1 ) break;
			if( mapdata[z][y][offsetX] == 4 && offsetX == circleX ) {   //  玉とキャラの間に壊れる壁があったら
				mapdata[z][y][offsetX] = 0; //  その配列のデータを0にして床にする
			}

			if( offsetX == circleX || offsetX + circleX == 20 ) {   // 調べた配列先が玉の配列の同じかまたは(足したときに20になったら←仮)
				// 【↓※】*pos_xとtpos_xの左右の位置関係で条件を分ける必要あり
				if(abs(*pos_x - tpos_x) < 3) break;             // 玉とプレイヤーの長さが3より小さければ以下の処理を飛ばす
				if(player.blow_active == false) {                   // 吹き飛ばすフラグがfalseなら玉の座標を+2.0fづつしていく
					*pos_x += 2.0f;
					// 【↑※】はみ出したら反対側に
				} else {
					*pos_x -= 2.0f;                                 // trueなら玉の座標を-2.0fしていく
					// 【↑※】はみ出したら反対側に
				}
				break;
			}
		}
	}
後半めんどうくさくなったのでコメントだけで。
他の方向は同様に変更してください。
というかうまくやれば全方向ひとつにまとめられます。

ここでは玉を動かす方向だけを覚えておいて、玉を動かすところは別にしたほうが分かりやすくなると思います。
#吹き飛ばすとき玉の向こう側に壁があったら突き抜けてしまうような…。

#この直前のコードに間違いがあります。

(編集)
カウントのタイミングに合わせてループ変数を1からに変更
自分の居場所は調べる必要ないと思うので。
最後に編集したユーザー ISLe on 2012年8月17日(金) 22:43 [ 編集 1 回目 ]

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#24

投稿記事 by EKISUKE » 13年前

トントン さんが書きました:追記
駄目な例かもしれませんというか駄目でした。
左方向と、右方向でソースがばらばらな奴をあげてしまった。。。
時間ないので、また後で考えます。
了解です。回答有難うございます。
ISLe さんが書きました:  //【削除】if( offsetX < 0 ) break;
ここを削除するのはどうしてなんでしょうか?
offsetXが常にプラスだから必要のない処理ということですかね?
ISLe さんが書きました:// 【↓※】*pos_xとtpos_xの左右の位置関係で条件を分ける必要あり
というのはその下の処理を左の場合右の場合とするということですか?
ISLe さんが書きました:

コード:

 if(abs(*pos_x - tpos_x) < 3) break;
absで絶対値をとってるので、左右関係なくできませんか?
それとも左と右とでは処理が違うようにするべきということなのでしょうか?

【追記】
その通りにしたのですが、玉とプレイヤーが重なるまで玉が移動してくれません。
そこでプログラムをコメントアウトしたりして、動作確認してみたところ
下のプログラムのところでなぜかおかしくなっていたようです。

コード:

--offsetX;
offsetX = (offsetX + 20) % 20;
ここがおかしいのですが、元々のプログラムの

コード:

offsetX = x - i;
とどこが違うのでしょうか?
上のものだと下のものよりoffsetXの値が一つ大きいので、プレイヤーと同じ配列まで調べようとはしないので重ならなかったです。
おそらく上は最初からoffsetXがマイナスされるのに対して、下は一回そのままのoffsetXで調べるからだと思うのですが、あっているでしょうか?
間違っていたら教えてください。すみません。
最後に編集したユーザー EKISUKE on 2012年8月17日(金) 23:12 [ 編集 1 回目 ]

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

Re: C++で倉庫番のようなものを作っています

#25

投稿記事 by ISLe » 13年前

EKISUKE さんが書きました:
ISLe さんが書きました:  //【削除】if( offsetX < 0 ) break;
ここを削除するのはどうしてなんでしょうか?
offsetXが常にプラスだから必要のない処理ということですかね?
常にプラスと言えばそうなのですが、
マップ内をループする処理を加えたので範囲外にならないから
というのが正確な理由です。
EKISUKE さんが書きました:
ISLe さんが書きました:// 【↓※】*pos_xとtpos_xの左右の位置関係で条件を分ける必要あり
というのはその下の処理を左の場合右の場合とするということですか?
ISLe さんが書きました:

コード:

 if(abs(*pos_x - tpos_x) < 3) break;
absで絶対値をとってるので、左右関係なくできませんか?
それとも左と右とでは処理が違うようにするべきということなのでしょうか?
現状は、右向き左向きに関係なく、玉とプレイヤーのマップ内側での距離を求めているだけです。
左向きの処理で、玉がプレイヤーより左にあれば良いですが、玉がプレイヤーより右にあるなら壁を挟んでループした距離を使う必要があります。


offsetXの更新タイミングに問題があったので、ループ変数を1から始まるように元記事を変更しました。

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#26

投稿記事 by EKISUKE » 13年前

ISLe さんが書きました:現状は、右向き左向きに関係なく、玉とプレイヤーのマップ内側での距離を求めているだけです。
左向きの処理で、玉がプレイヤーより左にあれば良いですが、玉がプレイヤーより右にあるなら壁を挟んでループした距離を使う必要があります。
玉は上下左右に仮想的に作っているので、玉が右にありウィンドウを越えてきても実質左に仮想的にある玉との判定なので、問題ないのではないですか?

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

Re: C++で倉庫番のようなものを作っています

#27

投稿記事 by ISLe » 13年前

EKISUKE さんが書きました:その通りにしたのですが、玉とプレイヤーが重なるまで玉が移動してくれません。
重なって良かったんですか。
それならこんな感じで。

コード:

    // オフセット(?)を初期設定
    offsetX = x;
    offsetY = y;
 
    // 左方向
    if( player.axisX < 0 && y == circleY ) {          // player.axisX(プレイヤーの向きに*4したもの)<0(プレイヤーの向きが左)かつy == circleY(Y座標の配列番号が同じ)なら
        for(int i=0; i<abs(player.axisX); i++) {
            //  i < abs(player.axisX)(=4)だけX方向の配列を調べる
            //【削除】if( offsetX < 0 ) break;        // 配列外を参照しないため
            if( mapdata[z][y][offsetX] == 1 ) break;
            if( mapdata[z][y][offsetX] == 4 && offsetX == circleX ) {   //  玉とキャラの間に壊れる壁があったら
                mapdata[z][y][offsetX] = 0; //  その配列のデータを0にして床にする
            }
 
            if( offsetX == circleX || offsetX + circleX == 20 ) {   // 調べた配列先が玉の配列の同じかまたは(足したときに20になったら←仮)
                // 【↓※】*pos_xとtpos_xの左右の位置関係で条件を分ける必要あり
                if(abs(*pos_x - tpos_x) < 3) break;             // 玉とプレイヤーの長さが3より小さければ以下の処理を飛ばす
                if(player.blow_active == false) {                   // 吹き飛ばすフラグがfalseなら玉の座標を+2.0fづつしていく
                    *pos_x += 2.0f;
                    // 【↑※】はみ出したら反対側に
                } else {
                    *pos_x -= 2.0f;                                 // trueなら玉の座標を-2.0fしていく
                    // 【↑※】はみ出したら反対側に
                }
                break;
            }
            -- offsetX;
            offsetX = (offsetX + 20) % 20;
        }
    }

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

Re: C++で倉庫番のようなものを作っています

#28

投稿記事 by ISLe » 13年前

EKISUKE さんが書きました:玉は上下左右に仮想的に作っているので、玉が右にありウィンドウを越えてきても実質左に仮想的にある玉との判定なので、問題ないのではないですか?
「上下左右に仮想的」の意味が分からないですが、マップの外周を挟んですぐ近くである場合を判定できているならそれで良いのではないでしょうか。

あと、このコードでは右(あるいは下)にある玉に対しては、約1ブロック分長い距離が対象になってしまうと思います。

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#29

投稿記事 by EKISUKE » 13年前

ISLe さんが書きました:「上下左右に仮想的」の意味が分からないですが、マップの外周を挟んですぐ近くである場合を判定できているならそれで良いのではないでしょうか。
描画のところでですね、下のように作っているので玉は全部で常に5つ描画しているので「上下左右に仮想的に玉をつくっている」という表現をしました。
説明不足ですみません。

コード:

//玉描画関数
void testApp::draw_circle(){
	int x = circle.pos._x;
	int y = circle.pos._y;
	int r = circle.radius;

		ofSetColor(255,0,0);
		ofCircle(x,y,r);					// 元
		ofCircle(x + 40*20,y,r);			// 右
		ofCircle(x - 40*20,y,r);			// 左
		ofCircle(x,y + 40*15,r);			// 下
		ofCircle(x,y - 40*15,r);			// 上							
}
ISLe さんが書きました:あと、このコードでは右(あるいは下)にある玉に対しては、約1ブロック分長い距離が対象になってしまうと思います。
そうですね。それを見直して作り直します。ご指摘ありがとうございます。

それと、玉をマップの外周を越えて吸い込み、吹き飛ばしができるようになりました。

ISLeさんの
ISLe さんが書きました:

コード:

 offsetX = (offsetX + 20) % 20;
というところを入れて

コード:

// 左方向
   	if( player.axisX < 0 && y == circleY ){						// player.axisX(プレイヤーの向きに*4したもの)<0(プレイヤーの向きが左)かつy == circleY(Y座標の配列番号が同じ)なら
		for(int i=0; i<abs(player.axisX); i++) {				//  i < abs(player.axisX)(=4)だけX方向の配列を調べる
			offsetX = x - i;
			offsetX = (offsetX + 20) % 20;
			
			//if( offsetX < 0 ) break;							// 配列外を参照しないため
			if( mapdata[z][y][offsetX] == 1 ) break;
			if( mapdata[z][y][offsetX] == 4 && offsetX == circleX ){//	玉とキャラの間に壊れる壁があったら
				mapdata[z][y][offsetX] = 0;						//	その配列のデータを0にして床にする
			}
			

			if( offsetX == circleX ){	// 調べた配列先が玉の配列の同じかまたは
				if(abs(*pos_x - tpos_x) < 3) break;					// 玉とプレイヤーの長さが3より小さければ以下の処理を飛ばす
				if(player.blow_active == false){					// 吹き飛ばすフラグがfalseなら玉の座標を+2.0fづつしていく
					circle.mov._x =  1;
					*pos_x += 2.0f;
				}else{
					circle.mov._x = -1;
					*pos_x -= 2.0f;									// trueなら玉の座標を-2.0fしていく
				}
				break;
			}
		}
	}
となり、これで吸い込み吹き飛ばしができるようになったのですが、一回玉がマップの外周をまたいだあとプレイヤーが吸い込みをしたら玉とプレイヤーが重ならなかったので、
プログラムを見直していくと

コード:

if(circle.pos._x < 0.0f){
		circle.pos._x += 20 * BLOCK_SIZE;
}
if(circle.pos._x > 20 * BLOCK_SIZE){
		circle.pos._x -= 20 * BLOCK_SIZE;
}
if(circle.pos._y < 0.0f){
		circle.pos._y += 15 * BLOCK_SIZE;
}
if(circle.pos._y > 15 * BLOCK_SIZE ){
		circle.pos._y -= 15 * BLOCK_SIZE;
}
という玉がマップの外周をまたいだときに座標をブロック*ウィンドウの幅を足すという処理が抜けていたため、reach関数ではマップ外の玉と判定していたみたいです。

回答してくださった皆さん有難うございます。おかげさまで悩んでいたことが解決しました。

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

Re: C++で倉庫番のようなものを作っています

#30

投稿記事 by ISLe » 13年前

EKISUKE さんが書きました:描画のところでですね、下のように作っているので玉は全部で常に5つ描画しているので「上下左右に仮想的に玉をつくっている」という表現をしました。
説明不足ですみません。
描画してるだけでtestApp::reach関数は5つ呼び出してないですよね。
呼び出したら逆におかしなことになりますけど。

先にも書きましたが、玉を移動する処理があちこちにあるのはややこしいので、一箇所にまとめたほうが良いと思います。
プログラムを見直すときの効率が上がります。

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#31

投稿記事 by EKISUKE » 13年前

ISLe さんが書きました:描画してるだけでtestApp::reach関数は5つ呼び出してないですよね。
呼び出したら逆におかしなことになりますけど。

コード:

void testApp::draw_circle(){
	int x = circle.pos._x;
	int y = circle.pos._y;
	int r = circle.radius;

		ofSetColor(255,0,0);
		ofCircle(x,y,r);					// 元
		ofCircle(x + 40*20,y,r);			// 右
		ofCircle(x - 40*20,y,r);			// 左
		ofCircle(x,y + 40*15,r);			// 下
		ofCircle(x,y - 40*15,r);			// 上
									
}
玉は5つ描画し「元」の部分で判定し、その「元」に対してそれぞれ右左下上というように描画しているので、
「元」が左端のウィンドウから半分でたら「右」の玉が半分描画されワープしてるようにみえるようにしてるだけですね。

コード:

if(circle.pos._x < 0.0f){
			circle.pos._x += 20 * BLOCK_SIZE;
		}
		if(circle.pos._x > 20 * BLOCK_SIZE){
			circle.pos._x -= 20 * BLOCK_SIZE;
		}
		if(circle.pos._y < 0.0f){
			circle.pos._y += 15 * BLOCK_SIZE;
		}
		if(circle.pos._y > 15 * BLOCK_SIZE ){
			circle.pos._y -= 15 * BLOCK_SIZE;
		}
そしてここで「元」の座標がマイナスになったら反対側の端の座標を渡すようにしてるので、
「仮想的に作っている」というよりは「ワープした感じを表現する」のほうが正しいですね。
すみません。


ISLe さんが書きました:先にも書きましたが、玉を移動する処理があちこちにあるのはややこしいので、一箇所にまとめたほうが良いと思います。
プログラムを見直すときの効率が上がります。
玉を動かす関数

コード:

void testApp::action(float *pos_x,float *pos_y,int num){
	switch(num){
	case 0:							// 左
		circle.mov._y = 0;			//	y方向の初期化

		if(player.blow_active == true && circle.blow_possible == true){
			circle.mov._x = -1;
			*pos_x -= 2.0f;			//吹き飛ばし
		}else  if(player.blow_active == false){
			circle.mov._x =  1;
			*pos_x += 2.0f;			//吸い込み
		}
		break;

	}
}	
吸い込み、吹き飛ばしができるかどうかを判定

コード:

// 左方向
   	if( player.axisX < 0 && y == circleY ){						// player.axisX(プレイヤーの向きに*4したもの)<0(プレイヤーの向きが左)かつy == circleY(Y座標の配列番号が同じ)なら
		for(int i=0; i<abs(player.axisX); i++) {				//  i < abs(player.axisX)(=4)だけX方向の配列を調べる
			offsetX = x - i;
			offsetX = (offsetX + 20) % 20;
			if( mapdata[z][y][offsetX] == 1 ) break;
			if( mapdata[z][y][offsetX] == 4 && offsetX == circleX ){//	玉とキャラの間に壊れる壁があったら
				mapdata[z][y][offsetX] = 0;						//	その配列のデータを0にして床にする
			}

			if( offsetX == circleX ){							// 調べた配列先が玉の配列の同じなら
				if(abs(*pos_x - tpos_x) < 3){ 					// 玉とプレイヤーの長さが3より小さければ以下の処理を飛ばす
					*pos_x = tpos_x; 
					*pos_y = tpos_y; 
					break;
				}
				action(&*pos_x,&*pos_y,0);						//吹き飛ばし且つ吸い込み関数をよびだす
				break;
			}
		}
	}
といったように分けましたが、もっと分けるべきでしょうか?

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

Re: C++で倉庫番のようなものを作っています

#32

投稿記事 by ISLe » 13年前

EKISUKE さんが書きました:といったように分けましたが、もっと分けるべきでしょうか?
testApp::actionでプレイヤーの情報を参照しているので独立性が低いですね。

testApp::reach内で直接動かさずに、どの方向へ動くのかを記録しておいて、玉を動かす処理を他の処理と並列に行うとプログラムの構造がシンプルになります。

吸い込み/吹き飛ばし→玉の移動のあいだにワンクッション入れて玉の移動処理の独立性を高めることで、例えば玉を吸い込むトラップなどを実装したときでも玉の移動処理を使い回せます。

とは言え完成させることを優先してください。
完成したプログラムを改良するほうがより深く身に付くと思います。

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#33

投稿記事 by EKISUKE » 13年前

ISLe さんが書きました:testApp::actionでプレイヤーの情報を参照しているので独立性が低いですね。

testApp::reach内で直接動かさずに、どの方向へ動くのかを記録しておいて、玉を動かす処理を他の処理と並列に行うとプログラムの構造がシンプルになります。

吸い込み/吹き飛ばし→玉の移動のあいだにワンクッション入れて玉の移動処理の独立性を高めることで、例えば玉を吸い込むトラップなどを実装したときでも玉の移動処理を使い回せます。
なるほど、いまはreach,blow関数はなくして、actionで一括でやっているのですが、actionをワンクッションとしてフラグか何かを返す関数にして
玉の当たり判定処理のする↓のようなプログラムに移動を加えるというものでしょうか?

コード:

//==========================================================
//玉と壁の当たり判定
//==========================================================
	float tmpx;
	float tmpy;
	float tmpx2;
	float tmpy2;

	Destination( &tmpx, &tmpy, &tmpx2, &tmpy2, circle.pos._x, circle.pos._y, circle.mov._x, circle.mov._y);
	
	int cx	= ((int)tmpx  + BLOCK_SIZE * 20)/ BLOCK_SIZE - 20;
	int cy	= ((int)tmpy  + BLOCK_SIZE * 15)/ BLOCK_SIZE - 15;
	int cx2	= ((int)tmpx2 + BLOCK_SIZE * 20)/ BLOCK_SIZE - 20;
	int cy2	= ((int)tmpy2 + BLOCK_SIZE * 15)/ BLOCK_SIZE - 15;
	
	//それぞれマイナスが出たときも0~19(0~14)の配列にもどす
	cx = (cx + 20) % 20;
	cy = (cy + 15) % 15;
	cx2 = (cx2 + 20) % 20;
	cy2 = (cy2 + 15) % 15;


	if(mapdata[circle.stage][cy][cx] != 1 && mapdata[circle.stage][cy2][cx2] != 1){
		
		circle.blow_possible = true;

		if(circle.pos._x < 0.0f){
			circle.pos._x += 20 * BLOCK_SIZE;
		}
		if(circle.pos._x > 20 * BLOCK_SIZE){
			circle.pos._x -= 20 * BLOCK_SIZE;
		}
		if(circle.pos._y < 0.0f){
			circle.pos._y += 15 * BLOCK_SIZE;
		}
		if(circle.pos._y > 15 * BLOCK_SIZE ){
			circle.pos._y -= 15 * BLOCK_SIZE;
		}
	}else{
		circle.blow_possible = false;
	}
}
ISLe さんが書きました:とは言え完成させることを優先してください。
完成したプログラムを改良するほうがより深く身に付くと思います。
わかりました。回答有難うございます。
完成させて自分でいろいろ改良してわからなくなったらまた新しいスレッドを立てて質問させていただきます。


みなさん回答有難うございました。
本当に勉強になりました。
またつまづいたり、したときは質問させていただきますので、よろしくお願いします。

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

Re: C++で倉庫番のようなものを作っています

#34

投稿記事 by ISLe » 13年前

EKISUKE さんが書きました:なるほど、いまはreach,blow関数はなくして、actionで一括でやっているのですが、actionをワンクッションとしてフラグか何かを返す関数にして
玉の当たり判定処理のする↓のようなプログラムに移動を加えるというものでしょうか?
そうですね。
関連する処理はまとめたほうが分かりやすいですしプログラムの変更にも強くなります。

それから例えば、
上下左右に対応したキーが押されたときプレイヤーを上下左右に動かすのではなく、
上下左右のキーが押されたのきっかけに、プレイヤーを各方向に動かすように(記憶)する
というふうに考えると玉もプレイヤーも基本的なロジックはまったく同じにできると思いませんか?

ゲームの中で起きるアクションは、それを発生させるイベントをきっかけに対象が自発的に行うように実装します。
そうするとプログラムで擬似的にイベントを発生させることができるのでデバッグも楽になります。

EKISUKE
記事: 108
登録日時: 13年前

Re: C++で倉庫番のようなものを作っています

#35

投稿記事 by EKISUKE » 13年前

ISLe さんが書きました:上下左右に対応したキーが押されたときプレイヤーを上下左右に動かすのではなく、
上下左右のキーが押されたのきっかけに、プレイヤーを各方向に動かすように(記憶)する
というふうに考えると玉もプレイヤーも基本的なロジックはまったく同じにできると思いませんか?
なるほど、ということはキーを押したときに番号か何かを保存する変数に値を与え、
移動だけする関数にswitch文で判断させるという風にすれば、玉でも同じ関数を使って移動がおこなえるということですね。
でも、その場合玉の吸い込まれる速度と、プレイヤーの移動速度が違う場合どのようにして速度を定めればいいのでしょうか?

ISLe さんが書きました:ゲームの中で起きるアクションは、それを発生させるイベントをきっかけに対象が自発的に行うように実装します。
そうするとプログラムで擬似的にイベントを発生させることができるのでデバッグも楽になります。
自発的にというのは↑のように 「キーが押された → 変数に値をいれる → その変数を使って移動のみの関数に引数を渡す → 結果移動する」というものですか?

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

Re: C++で倉庫番のようなものを作っています

#36

投稿記事 by ISLe » 13年前

EKISUKE さんが書きました:なるほど、ということはキーを押したときに番号か何かを保存する変数に値を与え、
移動だけする関数にswitch文で判断させるという風にすれば、玉でも同じ関数を使って移動がおこなえるということですね。
でも、その場合玉の吸い込まれる速度と、プレイヤーの移動速度が違う場合どのようにして速度を定めればいいのでしょうか?
同じ関数にまとめないといけないことはないですが。
ソースコードの構造が同じで、読み易いというだけでもメリットがあります。

共通化できるなら共通化できる部分だけで関数化して、パラメータ(引数)として移動速度を渡してやれば良いのではないでしょうか。
EKISUKE さんが書きました:自発的にというのは↑のように 「キーが押された → 変数に値をいれる → その変数を使って移動のみの関数に引数を渡す → 結果移動する」というものですか?
変数に値といれると言えばそうですが、プレイヤーや玉自身が次の行動をパラメータとして持つようにするということです。
自身が持つパラメータで次の行動が決定するように設計する、といったほうが良いですかね。

例えば
player.goRight();
と一回指示を出したら、playerが内部で右へ動くことを記憶して、
player.update();
がメインループで繰り返し呼び出されるとフレーム単位で適切に右に移動するような形にします。
実際の処理はupdateメソッドから呼び出されるようにするところがキモです。

そうすると、壁が壊れるアニメとか、複数フレームに掛けて行う処理を組み込むのも楽になります。
開始したいところで指示を出すメソッドを呼び出すだけで良くなりますから。

閉鎖

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