荷物を指定の場所に運ぶあのゲームについて

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

荷物を指定の場所に運ぶあのゲームについて

#1

投稿記事 by Hashimoto » 10年前

私は先日、「ゲームプログラマになる前に覚えておきたい技術」という本を購入しゲームプログラミングを学んでいる者です。
そこで、分からないところが出てきたので質問させて頂きました。
コードは、

コード:

#include <iostream>
using namespace std;

//#壁 _空間 .ゴール oブロック p人
const char gStageData[] = "\
########\n\
# .. p #\n\
# oo   #\n\
#      #\n\
########";
const int gStageWidth = 8;
const int gStageHeight = 5;

enum Object{
	OBJ_SPACE,
	OBJ_WALL,
	OBJ_GOAL,
	OBJ_BLOCK,
	OBJ_BLOCK_ON_GOAL,
	OBJ_MAN,
	OBJ_MAN_ON_GOAL,

	OBJ_UNKNOWN,
};

//関数プロトタイプ
void initialize( Object* state, int w, int h, const char* stageData );
void draw( const Object* state, int w, int h );
void update( Object* state, char input, int w, int h );
bool checkClear( const Object* state, int w, int h );

int main(){
	//一次元配列である理由は本文参照
	Object* state = new Object[ gStageWidth * gStageHeight ]; //状態配列確保

	initialize( state, gStageWidth, gStageHeight, gStageData ); //ステージ初期化
	//メインループ
	while ( true ){
		//まず描画
		draw( state, gStageWidth, gStageHeight );
		//クリアチェック
		if ( checkClear(state, gStageWidth, gStageHeight ) ){
			break; //クリアチェック
		}
		//入力取得
		cout << "a:left s:right w:up z:down. command?" << endl; //操作説明
		char input;
		cin >> input;
		//更新
		update( state, input, gStageWidth, gStageHeight ); 	
	}
	//祝いのメッセージ
	cout << "Congratulation's! you won." << endl;
	//後始末
	delete[] state;
	state = 0;

	//Visual Studioから実行する人のために無限ループ。コマンドラインからはCtrl-Cで終えてください。
	while( true ){
		;
	} 
	return 0;
}

//---------------------以下関数定義------------------------------------------


//いつか使う日も来るだろうと高さも渡す仕様にしたが、現状使っていないので名前だけ(height)コメントアウトしてある。
void initialize( Object* state, int width, int /* height */, const char* stageData ){	
	const char* d = stageData; //読み込みポインタ
	int x = 0;
	int y = 0;
	while ( *d != '\0' ){ //NULL文字でない間
		Object t; //特に意味はないが使う回数が多い変数に私は良くtを使う。temporaryの略。たぶんよくない習慣だが、無駄に長い名前にして読みにくいのも困り物だろう。
		switch ( *d ){
			case '#': t = OBJ_WALL; break;
			case ' ': t = OBJ_SPACE; break;
			case 'o': t = OBJ_BLOCK; break;
			case 'O': t = OBJ_BLOCK_ON_GOAL; break;
			case '.': t = OBJ_GOAL; break;
			case 'p': t = OBJ_MAN; break;
			case 'P': t = OBJ_MAN_ON_GOAL; break;
			case '\n': x = 0; ++y; t = OBJ_UNKNOWN; break; //改行処理
			default: t = OBJ_UNKNOWN; break;
		}
		++d;
		if ( t != OBJ_UNKNOWN ){ //知らない文字なら無視するのでこのif文がある
			state[ y*width + x ] = t; //書き込み
			++x;
		}
	}
}

void draw( const Object* state, int width, int height ){
	const char font[] = {' ', '#', '.', 'o', 'O', 'p', 'P'}; //Object列挙の順
	for ( int y = 0; y < height; ++y ){
		for ( int x=0; x < width; ++x ){
			Object o = state[ y*width + x ];
			cout << font[ o ];
		}
		cout << endl;
	}
}

//第一引数はほかの関数ではstateとしているが、あまりに頻繁に使うので
//短いsで済ませている。w,hもそれぞれwidth,heightである。
void update( Object* s, char input, int w, int h ){
	//移動差分に変換(dはdifferenceでもdeltaでもお好きな方の略だと思って欲しい)
	int dx = 0; 
	int dy = 0;
	switch ( input ){
		case 'a': dx = -1; break; //左
		case 's': dx = 1; break; //右
		case 'w': dy = -1; break; //上。Yは下がプラス
		case 'z': dy = 1; break; //下。
	}
	//人座標を検索
	int i = -1;
	for ( i = 0; i < w * h; ++i ){
		if ( s[ i ] == OBJ_MAN || s[ i ] == OBJ_MAN_ON_GOAL ){
			break;
		}
	}
	int x = i % w; //xは幅で割ったあまり
	int y = i / w; //yは幅で割った商

	//移動
	//移動後座標(tに意味はない。ごめんなさい)
	int tx = x + dx;
	int ty = y + dy;
	//座標の最大最小チェック。外れていれば不許可
	if ( tx < 0 || ty < 0 || tx >= w || ty >= h ){
		return;
	}
	//A.その方向が空白またはゴール。人が移動。
	int p = y*w + x; //人位置
	int tp = ty*w + tx; //ターゲット位置(TargetPosition)
	if ( s[ tp ] == OBJ_SPACE || s[ tp ] == OBJ_GOAL ){
		s[ tp ] = ( s[ tp ] == OBJ_GOAL ) ? OBJ_MAN_ON_GOAL : OBJ_MAN; //ゴールならゴール上の人に
		s[ p ] = ( s[ p ] == OBJ_MAN_ON_GOAL ) ? OBJ_GOAL : OBJ_SPACE; //もともとゴール上ならゴールに
	//B.その方向が箱。その方向の次のマスが空白またはゴールであれば移動。
	}else if ( s[ tp ] == OBJ_BLOCK || s[ tp ] == OBJ_BLOCK_ON_GOAL ){
		//2マス先が範囲内かチェック
		int tx2 = tx + dx;
		int ty2 = ty + dy; 
		if ( tx2 < 0 || ty2 < 0 || tx2 >= w || ty2 >= h ){ //押せない
			return;
		}

		int tp2 = ( ty + dy )*w + ( tx + dx ); //2マス先
		if ( s[ tp2 ] == OBJ_SPACE || s[ tp2 ] == OBJ_GOAL ){
			//順次入れ替え
			s[ tp2 ] = ( s[ tp2 ] == OBJ_GOAL ) ? OBJ_BLOCK_ON_GOAL : OBJ_BLOCK;
			s[ tp ] = ( s[ tp ] == OBJ_BLOCK_ON_GOAL ) ? OBJ_MAN_ON_GOAL : OBJ_MAN;
			s[ p ] = ( s[ p ] == OBJ_MAN_ON_GOAL ) ? OBJ_GOAL : OBJ_SPACE;
		}
	}
}

//ブロックのみがなければクリアしている。
bool checkClear( const Object* s, int width, int height ){
	for ( int i = 0; i < width*height; ++i ){
		if ( s[ i ] == OBJ_BLOCK ){
			return false;
		}
	}
	return true;
}
です。荷物を指定の場所に運ぶゲームです。

まず1、34行目の「Object* state = new Object[ gStageWidth * gStageHeight ]; //状態配列確保」の「Object」とは何なのでしょうか?
また、この一文は何をしているのでしょうか?
次に2、69行目~92行目のinitialize関数は何をしているのでしょうか?
次に3、88行目の「state[ y*width + x ] = t; 」がよくわかりません。教えて下さい。
次に4、107行目~158行目のupdate関数は何をしているのでしょうか?
最後に5、161行目~168行目のcheckClear関数は何をしているのでしょうか?
できれば、解説のように教えてもらえると嬉しいです。よろしくお願いします。

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

Re: 荷物を指定の場所に運ぶあのゲームについて

#2

投稿記事 by usao » 10年前

>分からないところが出てきたので質問させて頂きました。
なんというか,示された1~5を除くと,あとはほとんど何も残らないわけですが…

とりあえず1だけ答えておくと,「Object」は14行目~にありますよ.
その本からの情報だけで読み解けないのあれば,文法の方も別途本なりネットなりで学ぶ必要がありそうです.

non
記事: 1097
登録日時: 13年前

Re: 荷物を指定の場所に運ぶあのゲームについて

#3

投稿記事 by non » 10年前

私もusaoさんと同じように感じました。その本を持っていませんから、どのように説明されているのかわかりません。もっと、ポイントを絞って質問すべき
ではないでしょうか。

まあ、最初の質問はポイントが絞られているので、お手伝いしますと、
>「Object* state = new Object[ gStageWidth * gStageHeight ]; //状態配列確保」の「Object」とは何なのでしょうか?
enumは列挙型です。Object という名前の型を作ったのですね。中身は整数なのですが、整数では意味がわかりにくいので意味がわかりやすい
名前を整数に割り当てたと考えれば良いでしょうか。
この要素がObjectの配列を40個作ったということになります。
non

nil
記事: 428
登録日時: 12年前

Re: 荷物を指定の場所に運ぶあのゲームについて

#4

投稿記事 by nil » 10年前

一応「ゲームプログラマになる前に覚えておきたい技術」はC言語やC++についての最低限度の知識を持っていることが前提である、というようなことを、
まえがきの当たりに書かれていたはずです。
ですので、C言語についての知識(最低列挙体やポインタの簡単な使い方、クラスの基礎)程度はできていないと難しいと感じるはずです。

一度C言語の基礎について学ぶことをオススメします

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

Re: 荷物を指定の場所に運ぶあのゲームについて

#5

投稿記事 by Tatu » 10年前

英語の意味くらいは自分で調べてください。

1.
その場所にある物体の情報を表しています。
この情報を並べることでステージのデータになります。

2.
コードの一番上にあるような#とかpとか書かれたデータを読んでステージを初期化しています。

3.
読んだデータ(壁、空間、ブロックなど)を書き込んでいます。
y*width+xは書き込む場所を表しています。
右に進むと番号が1増え、下に進むと番号がwidth増えるというのはわかりますか?

4.
入力を受け取って更新しています。

5.クリアかどうかを調べています。
クリア状態なら全てのブロックがゴールの上にあるわけですから
ゴールの上にないブロックがあったらクリアでないという事になります。

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

Re: 荷物を指定の場所に運ぶあのゲームについて

#6

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

C++の基礎知識が圧倒的に足りていないようです。
「ゲームプログラマになる前に」であって「プログラマになる前に」に読む本ではないので、C++の入門書も勉強しておく必要があります。

前提スキルは次のように書かれています。
「ゲームプログラマになる前に覚えておきたい技術|セガの新人教育カリキュラムから生まれたゲームプログラミング解説書!」
http://www.shuwasystem.co.jp/gpro-sp/
◆C++言語
関数を作れる
クラスの作り方を知っている
変数、配列、制御構造などにある程度親しんでいる

※本文内では、C++言語の基本的な説明はしません。

◆本文内でのプログラミング解説

若干の補足くらいの説明
ポインタ、newとdeleteなどのメモリ操作やそれらの配列との関係
必要最低限の説明
constの使い方
名前空間
テンプレート
クラスの継承
演算子の定義
C/C++標準ライブラリ

◆他言語経験者について
C++は知らないがC#やJavaなら書ける、という人でもおそらく読めるでしょう。
初心者向けのC++の本を一冊用意しておけば問題ないでしょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Hashimoto

Re: 荷物を指定の場所に運ぶあのゲームについて

#7

投稿記事 by Hashimoto » 10年前

[quote="Hashimoto"]私は先日、「ゲームプログラマになる前に覚えておきたい技術」という本を購入しゲームプログラミングを学んでいる者です。
そこで、分からないところが出てきたので質問させて頂きました。
コードは、

コード:

#include <iostream>
using namespace std;

//#壁 _空間 .ゴール oブロック p人
const char gStageData[] = "\
########\n\
# .. p #\n\
# oo   #\n\
#      #\n\
########";
const int gStageWidth = 8;
const int gStageHeight = 5;

enum Object{
	OBJ_SPACE,
	OBJ_WALL,
	OBJ_GOAL,
	OBJ_BLOCK,
	OBJ_BLOCK_ON_GOAL,
	OBJ_MAN,
	OBJ_MAN_ON_GOAL,

	OBJ_UNKNOWN,
};

//関数プロトタイプ
void initialize( Object* state, int w, int h, const char* stageData );
void draw( const Object* state, int w, int h );
void update( Object* state, char input, int w, int h );
bool checkClear( const Object* state, int w, int h );

int main(){
	//一次元配列である理由は本文参照
	Object* state = new Object[ gStageWidth * gStageHeight ]; //状態配列確保

	initialize( state, gStageWidth, gStageHeight, gStageData ); //ステージ初期化
	//メインループ
	while ( true ){
		//まず描画
		draw( state, gStageWidth, gStageHeight );
		//クリアチェック
		if ( checkClear(state, gStageWidth, gStageHeight ) ){
			break; //クリアチェック
		}
		//入力取得
		cout << "a:left s:right w:up z:down. command?" << endl; //操作説明
		char input;
		cin >> input;
		//更新
		update( state, input, gStageWidth, gStageHeight ); 	
	}
	//祝いのメッセージ
	cout << "Congratulation's! you won." << endl;
	//後始末
	delete[] state;
	state = 0;

	//Visual Studioから実行する人のために無限ループ。コマンドラインからはCtrl-Cで終えてください。
	while( true ){
		;
	} 
	return 0;
}

//---------------------以下関数定義------------------------------------------


//いつか使う日も来るだろうと高さも渡す仕様にしたが、現状使っていないので名前だけ(height)コメントアウトしてある。
void initialize( Object* state, int width, int /* height */, const char* stageData ){	
	const char* d = stageData; //読み込みポインタ
	int x = 0;
	int y = 0;
	while ( *d != '\0' ){ //NULL文字でない間
		Object t; //特に意味はないが使う回数が多い変数に私は良くtを使う。temporaryの略。たぶんよくない習慣だが、無駄に長い名前にして読みにくいのも困り物だろう。
		switch ( *d ){
			case '#': t = OBJ_WALL; break;
			case ' ': t = OBJ_SPACE; break;
			case 'o': t = OBJ_BLOCK; break;
			case 'O': t = OBJ_BLOCK_ON_GOAL; break;
			case '.': t = OBJ_GOAL; break;
			case 'p': t = OBJ_MAN; break;
			case 'P': t = OBJ_MAN_ON_GOAL; break;
			case '\n': x = 0; ++y; t = OBJ_UNKNOWN; break; //改行処理
			default: t = OBJ_UNKNOWN; break;
		}
		++d;
		if ( t != OBJ_UNKNOWN ){ //知らない文字なら無視するのでこのif文がある
			state[ y*width + x ] = t; //書き込み
			++x;
		}
	}
}

void draw( const Object* state, int width, int height ){
	const char font[] = {' ', '#', '.', 'o', 'O', 'p', 'P'}; //Object列挙の順
	for ( int y = 0; y < height; ++y ){
		for ( int x=0; x < width; ++x ){
			Object o = state[ y*width + x ];
			cout << font[ o ];
		}
		cout << endl;
	}
}

//第一引数はほかの関数ではstateとしているが、あまりに頻繁に使うので
//短いsで済ませている。w,hもそれぞれwidth,heightである。
void update( Object* s, char input, int w, int h ){
	//移動差分に変換(dはdifferenceでもdeltaでもお好きな方の略だと思って欲しい)
	int dx = 0; 
	int dy = 0;
	switch ( input ){
		case 'a': dx = -1; break; //左
		case 's': dx = 1; break; //右
		case 'w': dy = -1; break; //上。Yは下がプラス
		case 'z': dy = 1; break; //下。
	}
	//人座標を検索
	int i = -1;
	for ( i = 0; i < w * h; ++i ){
		if ( s[ i ] == OBJ_MAN || s[ i ] == OBJ_MAN_ON_GOAL ){
			break;
		}
	}
	int x = i % w; //xは幅で割ったあまり
	int y = i / w; //yは幅で割った商

	//移動
	//移動後座標(tに意味はない。ごめんなさい)
	int tx = x + dx;
	int ty = y + dy;
	//座標の最大最小チェック。外れていれば不許可
	if ( tx < 0 || ty < 0 || tx >= w || ty >= h ){
		return;
	}
	//A.その方向が空白またはゴール。人が移動。
	int p = y*w + x; //人位置
	int tp = ty*w + tx; //ターゲット位置(TargetPosition)
	if ( s[ tp ] == OBJ_SPACE || s[ tp ] == OBJ_GOAL ){
		s[ tp ] = ( s[ tp ] == OBJ_GOAL ) ? OBJ_MAN_ON_GOAL : OBJ_MAN; //ゴールならゴール上の人に
		s[ p ] = ( s[ p ] == OBJ_MAN_ON_GOAL ) ? OBJ_GOAL : OBJ_SPACE; //もともとゴール上ならゴールに
	//B.その方向が箱。その方向の次のマスが空白またはゴールであれば移動。
	}else if ( s[ tp ] == OBJ_BLOCK || s[ tp ] == OBJ_BLOCK_ON_GOAL ){
		//2マス先が範囲内かチェック
		int tx2 = tx + dx;
		int ty2 = ty + dy; 
		if ( tx2 < 0 || ty2 < 0 || tx2 >= w || ty2 >= h ){ //押せない
			return;
		}

		int tp2 = ( ty + dy )*w + ( tx + dx ); //2マス先
		if ( s[ tp2 ] == OBJ_SPACE || s[ tp2 ] == OBJ_GOAL ){
			//順次入れ替え
			s[ tp2 ] = ( s[ tp2 ] == OBJ_GOAL ) ? OBJ_BLOCK_ON_GOAL : OBJ_BLOCK;
			s[ tp ] = ( s[ tp ] == OBJ_BLOCK_ON_GOAL ) ? OBJ_MAN_ON_GOAL : OBJ_MAN;
			s[ p ] = ( s[ p ] == OBJ_MAN_ON_GOAL ) ? OBJ_GOAL : OBJ_SPACE;
		}
	}
}

//ブロックのみがなければクリアしている。
bool checkClear( const Object* s, int width, int height ){
	for ( int i = 0; i < width*height; ++i ){
		if ( s[ i ] == OBJ_BLOCK ){
			return false;
		}
	}
	return true;
}
です。荷物を指定の場所に運ぶゲームです。

まず1、34行目の「Object* state = new Object[ gStageWidth * gStageHeight ]; //状態配列確保」の「Object」とは何なのでしょうか?
また、この一文は何をしているのでしょうか?
次に2、69行目~92行目のinitialize関数は何をしているのでしょうか?
次に3、88行目の「state[ y*width + x ] = t; 」がよくわかりません。教えて下さい。
次に4、107行目~158行目のupdate関数は何をしているのでしょうか?
最後に5、161行目~168行目のcheckClear関数は何をしているのでしょうか?
できれば、解説のように教えてもらえると嬉しいです。よろしくお願いします。[/code]

追記:
1,2,5はわかったのですが、3,4がわかりません。
3、88行目の「state[ y*width + x ] = t; //書き込み」の「[ y*width + x ]」がよくわかりません。
4、120行目の「if ( s[ i ] == OBJ_MAN || s[ i ] == OBJ_MAN_ON_GOAL )」は何を表しているのでしょうか?
  132行目~134行目の「if ( tx < 0 || ty < 0 || tx >= w || ty >= h ){return;}」とは何を返しているのでしょうか?
  135行目~158行目は全くわかりません。
特に135行目~158行目の解説は出来るだけ詳しく教えて下さい。よろしくお願いします。

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

Re: 荷物を指定の場所に運ぶあのゲームについて

#8

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

このコードは、動かしてデバッガで追いかけてみましたか?

自分で解析しないと身につかないので出来るだけ自力でコメントを書いてみてください。
その上で、間違っていないか質問して頂ければ、回答もすごく理解できると思います。

とありえず、C/C++は余り知識がなく、プログラムを組んだ経験もないと考えて良いですね?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

non
記事: 1097
登録日時: 13年前

Re: 荷物を指定の場所に運ぶあのゲームについて

#9

投稿記事 by non » 10年前

>3、88行目の「state[ y*width + x ] = t; //書き込み」の「[ y*width + x ]」がよくわかりません。
2次元配列を1次元配列に変換しているのですね。
non

non
記事: 1097
登録日時: 13年前

Re: 荷物を指定の場所に運ぶあのゲームについて

#10

投稿記事 by non » 10年前

>120行目の「if ( s[ i ] == OBJ_MAN || s[ i ] == OBJ_MAN_ON_GOAL )」は何を表しているのでしょうか?
人の場所(Pかp)がどこにあるか探してます。
non

non
記事: 1097
登録日時: 13年前

Re: 荷物を指定の場所に運ぶあのゲームについて

#11

投稿記事 by non » 10年前

>132行目~134行目の「if ( tx < 0 || ty < 0 || tx >= w || ty >= h ){return;}」とは何を返しているのでしょうか?
何も返してません。
non

Hashimoto

Re: 荷物を指定の場所に運ぶあのゲームについて

#12

投稿記事 by Hashimoto » 10年前

Hashimoto さんが書きました:
Hashimoto さんが書きました:私は先日、「ゲームプログラマになる前に覚えておきたい技術」という本を購入しゲームプログラミングを学んでいる者です。
そこで、分からないところが出てきたので質問させて頂きました。
コードは、

コード:

#include <iostream>
using namespace std;

//#壁 _空間 .ゴール oブロック p人
const char gStageData[] = "\
########\n\
# .. p #\n\
# oo   #\n\
#      #\n\
########";
const int gStageWidth = 8;
const int gStageHeight = 5;

enum Object{
	OBJ_SPACE,
	OBJ_WALL,
	OBJ_GOAL,
	OBJ_BLOCK,
	OBJ_BLOCK_ON_GOAL,
	OBJ_MAN,
	OBJ_MAN_ON_GOAL,

	OBJ_UNKNOWN,
};

//関数プロトタイプ
void initialize( Object* state, int w, int h, const char* stageData );
void draw( const Object* state, int w, int h );
void update( Object* state, char input, int w, int h );
bool checkClear( const Object* state, int w, int h );

int main(){
	//一次元配列である理由は本文参照
	Object* state = new Object[ gStageWidth * gStageHeight ]; //状態配列確保

	initialize( state, gStageWidth, gStageHeight, gStageData ); //ステージ初期化
	//メインループ
	while ( true ){
		//まず描画
		draw( state, gStageWidth, gStageHeight );
		//クリアチェック
		if ( checkClear(state, gStageWidth, gStageHeight ) ){
			break; //クリアチェック
		}
		//入力取得
		cout << "a:left s:right w:up z:down. command?" << endl; //操作説明
		char input;
		cin >> input;
		//更新
		update( state, input, gStageWidth, gStageHeight ); 	
	}
	//祝いのメッセージ
	cout << "Congratulation's! you won." << endl;
	//後始末
	delete[] state;
	state = 0;

	//Visual Studioから実行する人のために無限ループ。コマンドラインからはCtrl-Cで終えてください。
	while( true ){
		;
	} 
	return 0;
}

//---------------------以下関数定義------------------------------------------


//いつか使う日も来るだろうと高さも渡す仕様にしたが、現状使っていないので名前だけ(height)コメントアウトしてある。
void initialize( Object* state, int width, int /* height */, const char* stageData ){	
	const char* d = stageData; //読み込みポインタ
	int x = 0;
	int y = 0;
	while ( *d != '\0' ){ //NULL文字でない間
		Object t; //特に意味はないが使う回数が多い変数に私は良くtを使う。temporaryの略。たぶんよくない習慣だが、無駄に長い名前にして読みにくいのも困り物だろう。
		switch ( *d ){
			case '#': t = OBJ_WALL; break;
			case ' ': t = OBJ_SPACE; break;
			case 'o': t = OBJ_BLOCK; break;
			case 'O': t = OBJ_BLOCK_ON_GOAL; break;
			case '.': t = OBJ_GOAL; break;
			case 'p': t = OBJ_MAN; break;
			case 'P': t = OBJ_MAN_ON_GOAL; break;
			case '\n': x = 0; ++y; t = OBJ_UNKNOWN; break; //改行処理
			default: t = OBJ_UNKNOWN; break;
		}
		++d;
		if ( t != OBJ_UNKNOWN ){ //知らない文字なら無視するのでこのif文がある
			state[ y*width + x ] = t; //書き込み
			++x;
		}
	}
}

void draw( const Object* state, int width, int height ){
	const char font[] = {' ', '#', '.', 'o', 'O', 'p', 'P'}; //Object列挙の順
	for ( int y = 0; y < height; ++y ){
		for ( int x=0; x < width; ++x ){
			Object o = state[ y*width + x ];
			cout << font[ o ];
		}
		cout << endl;
	}
}

//第一引数はほかの関数ではstateとしているが、あまりに頻繁に使うので
//短いsで済ませている。w,hもそれぞれwidth,heightである。
void update( Object* s, char input, int w, int h ){
	//移動差分に変換(dはdifferenceでもdeltaでもお好きな方の略だと思って欲しい)
	int dx = 0; 
	int dy = 0;
	switch ( input ){
		case 'a': dx = -1; break; //左
		case 's': dx = 1; break; //右
		case 'w': dy = -1; break; //上。Yは下がプラス
		case 'z': dy = 1; break; //下。
	}
	//人座標を検索
	int i = -1;
	for ( i = 0; i < w * h; ++i ){
		if ( s[ i ] == OBJ_MAN || s[ i ] == OBJ_MAN_ON_GOAL ){
			break;
		}
	}
	int x = i % w; //xは幅で割ったあまり
	int y = i / w; //yは幅で割った商

	//移動
	//移動後座標(tに意味はない。ごめんなさい)
	int tx = x + dx;
	int ty = y + dy;
	//座標の最大最小チェック。外れていれば不許可
	if ( tx < 0 || ty < 0 || tx >= w || ty >= h ){
		return;
	}
	//A.その方向が空白またはゴール。人が移動。
	int p = y*w + x; //人位置
	int tp = ty*w + tx; //ターゲット位置(TargetPosition)
	if ( s[ tp ] == OBJ_SPACE || s[ tp ] == OBJ_GOAL ){
		s[ tp ] = ( s[ tp ] == OBJ_GOAL ) ? OBJ_MAN_ON_GOAL : OBJ_MAN; //ゴールならゴール上の人に
		s[ p ] = ( s[ p ] == OBJ_MAN_ON_GOAL ) ? OBJ_GOAL : OBJ_SPACE; //もともとゴール上ならゴールに
	//B.その方向が箱。その方向の次のマスが空白またはゴールであれば移動。
	}else if ( s[ tp ] == OBJ_BLOCK || s[ tp ] == OBJ_BLOCK_ON_GOAL ){
		//2マス先が範囲内かチェック
		int tx2 = tx + dx;
		int ty2 = ty + dy; 
		if ( tx2 < 0 || ty2 < 0 || tx2 >= w || ty2 >= h ){ //押せない
			return;
		}

		int tp2 = ( ty + dy )*w + ( tx + dx ); //2マス先
		if ( s[ tp2 ] == OBJ_SPACE || s[ tp2 ] == OBJ_GOAL ){
			//順次入れ替え
			s[ tp2 ] = ( s[ tp2 ] == OBJ_GOAL ) ? OBJ_BLOCK_ON_GOAL : OBJ_BLOCK;
			s[ tp ] = ( s[ tp ] == OBJ_BLOCK_ON_GOAL ) ? OBJ_MAN_ON_GOAL : OBJ_MAN;
			s[ p ] = ( s[ p ] == OBJ_MAN_ON_GOAL ) ? OBJ_GOAL : OBJ_SPACE;
		}
	}
}

//ブロックのみがなければクリアしている。
bool checkClear( const Object* s, int width, int height ){
	for ( int i = 0; i < width*height; ++i ){
		if ( s[ i ] == OBJ_BLOCK ){
			return false;
		}
	}
	return true;
}
です。荷物を指定の場所に運ぶゲームです。

まず1、34行目の「Object* state = new Object[ gStageWidth * gStageHeight ]; //状態配列確保」の「Object」とは何なのでしょうか?
また、この一文は何をしているのでしょうか?
次に2、69行目~92行目のinitialize関数は何をしているのでしょうか?
次に3、88行目の「state[ y*width + x ] = t; 」がよくわかりません。教えて下さい。
次に4、107行目~158行目のupdate関数は何をしているのでしょうか?
最後に5、161行目~168行目のcheckClear関数は何をしているのでしょうか?
できれば、解説のように教えてもらえると嬉しいです。よろしくお願いします。[/code]

追記:
1,2,5はわかったのですが、3,4がわかりません。
3、88行目の「state[ y*width + x ] = t; //書き込み」の「[ y*width + x ]」がよくわかりません。
4、120行目の「if ( s[ i ] == OBJ_MAN || s[ i ] == OBJ_MAN_ON_GOAL )」は何を表しているのでしょうか?
  132行目~134行目の「if ( tx < 0 || ty < 0 || tx >= w || ty >= h ){return;}」とは何を返しているのでしょうか?
  135行目~158行目は全くわかりません。
特に135行目~158行目の解説は出来るだけ詳しく教えて下さい。よろしくお願いします。
追記の追記:
皆様回答者様のおかでなんとなくわかりました。
ありがとうございました。
そこで、次なんですが、この「荷物を指定の場所に運ぶゲーム」にステージ読み込み機能をつけたいんですが、サンプルでは、

コード:

#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ifsteam inputFile("stageData.txt", ifstream::binary);
inputFile.seekg(0,ifstream::end);
int fileSize = static_cast<int>(inputFile.tellg();
inputFile.seekg(0,ifstream::beg);
char * fileImage = new char [fileSize];
inputFile.read(fileImage,fileSize());
cout.write(fileImage,fileSize);
}
[\code]
となっています。
1、7行目の「static_cast<int>(inputFile.tellg());」はどうなっているのでしょうか?
2、11行目の「cout.write」とは何なのでしょうか?

non
記事: 1097
登録日時: 13年前

Re: 荷物を指定の場所に運ぶあのゲームについて

#13

投稿記事 by non » 10年前

まずは、自分で調べて、それでもわからないことを質問しよう。
static_cast は http://www.geocities.jp/ky_webid/cpp/language/024.html
C++の入出力は http://www.cppll.jp/cppreference/cppio_details.html
non

Hashimoto

Re: 荷物を指定の場所に運ぶあのゲームについて

#14

投稿記事 by Hashimoto » 10年前

追記の追記:
皆様回答者様のおかでなんとなくわかりました。
ありがとうございました。
そこで、次なんですが、この「荷物を指定の場所に運ぶゲーム」にステージ読み込み機能をつけたいんですが、サンプルでは、

コード:

#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ifsteam inputFile("stageData.txt", ifstream::binary);
inputFile.seekg(0,ifstream::end);
int fileSize = static_cast<int>(inputFile.tellg();
inputFile.seekg(0,ifstream::beg);
char * fileImage = new char [fileSize];
inputFile.read(fileImage,fileSize());
cout.write(fileImage,fileSize);
}
[\code]
となっています。
1、7行目の「static_cast<int>(inputFile.tellg());」はどうなっているのでしょうか?
2、11行目の「cout.write」とは何なのでしょうか?

追記の追記の追記:
7行目の「static_cast<int>(inputFile.tellg());」は、調べてわかったのですが11行目の「cout.write」は調べてもわかりません。どなたか教えて下さい。

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

Re: 荷物を指定の場所に運ぶあのゲームについて

#15

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

ocdeタグは、プレビューして確認してください。ずっと間違っています。

> 7行目の「static_cast<int>(inputFile.tellg());」は、調べてわかったのですが11行目の「cout.write」は調べてもわかりません。どなたか教えて下さい。
クラスのメンバ関数がわからないでしょうか?
それもファイル入出力がわからないんでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Hashimoto

Re: 荷物を指定の場所に運ぶあのゲームについて

#16

投稿記事 by Hashimoto » 10年前

「cout.write」そのものがわかりません(意味)。

non
記事: 1097
登録日時: 13年前

Re: 荷物を指定の場所に運ぶあのゲームについて

#17

投稿記事 by non » 10年前

writeはバイナリ出力します。出力先はcoutすなわち標準出力です。
non

Hashimoto

Re: 荷物を指定の場所に運ぶあのゲームについて

#18

投稿記事 by Hashimoto » 10年前

ご回答ありがとうございました。これからも、プログラミング精進したいと思います。

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

Re: 荷物を指定の場所に運ぶあのゲームについて

#19

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

coutオブジェクトのwriteメンバ関数を呼び出しています。
coutはostreamクラスですので、ostreamのwriteメンバ関数を調べましょう。
「C++入出力」
http://www.cppll.jp/cppreference/cppio_details.html
「C++編(標準ライブラリ) 第30章 入出力ストリーム②」
http://www.geocities.jp/ky_webid/cpp/library/030.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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