14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

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

14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#1

投稿記事 by kyonkyon » 5年前

「14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編」からの質問です。今このテキスト内のRPG風のアクションパズルゲームを作っているのですがモンスターの配置がうまくいきません。ピンクのデベソモンスターが3体、ドラゴンが1体出現するようにしているのですがデベソモンスターが1体でドラゴンは出現せずドラゴンの攻撃である炎のみが残っているというよくわからない状況になっています。以下が現状の実行結果です。
実際は

以下「14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編」から引用したコードを載せます。(本を見ながらプログラムしました)gamemain.cppでマップ描画、主人公、モンスターの処理を行っています。上記のようなバグが出たのはドラゴンに炎を吐かせるようにプログラムしてから発生したのでおそらくgamemain.cppのInitStage関数、DrawDragonFire関数、DrawEnemy関数のいずれかにおかしいところがあるのかなーっと思い考えてみたのですが解決しません。すいませんが間違いを見つけていただけると嬉しいです。

main.cpp

コード:

#include"main.h"

//グローバル変数
//時間計測用変数
int g_lasttime = 0;    //直前の計測時間
float g_frametime = 0; //1ループにかかった時間
int g_timerstart;

GameState g_gamestate;
int g_gametitling;  //タイトルイメージ
int g_heroimg;      //画像
float g_hx=0, g_hy=0;   //座標
//ボタン
BOOL g_akey_prev;   //直前のAボタンの状態
//フォント
int g_middlefont;   //中サイズフォントハンドル
int g_largefont;    //大サイズフォントハンドル

int WINAPI WinMain(HINSTANCE h1, HINSTANCE hP, LPSTR lpC, int nC){
	//ウィンドウモードにする
	ChangeWindowMode(TRUE);
	//ウィンドウサイズを変更する
	SetGraphMode(800, 600, 32);
	//DXライブラリ初期化
	if(DxLib_Init() == -1) return -1;

	//画像を読み込み
	if(LoadGameImage() == FALSE) return -1;
	g_gametitling = LoadGraph("media\\smp1_title.png");
	g_heroimg = LoadGraph("media\\smp1_chara01.png");
	g_middlefont = CreateFontToHandle("メイリオ", 42, -1, DX_FONTTYPE_ANTIALIASING);
	g_largefont = CreateFontToHandle("メイリオ", 90, -1, DX_FONTTYPE_ANTIALIASING); 

	SetDrawScreen(DX_SCREEN_BACK);
	g_lasttime = GetNowCount()&INT_MAX; //現在時刻の記録
	while(ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0){
		//1ループにかかった時刻を計測
		int curtime = GetNowCount();
		g_frametime = (float)(curtime - g_lasttime)/1000.0f;
		g_lasttime = curtime;

		ClearDrawScreen();
		//画面描画関数に切り替え
		switch(g_gamestate)
		{
		case GAME_TITLE:
			DrawGameTitle();
			break;
		case GAME_MAIN:
			DrawGameMain();
			break;
		case GAME_CLEAR:
			DrawGameClear();
			break;
		case GAME_OVER:
			DrawGameOver();
			break;
		default:
			break;
		}
		ScreenFlip();
	}

	WaitKey();

	DxLib_End();
	return 0;
}

//タイトル画面描画
void DrawGameTitle(){
	DrawBox(0, 0, 800, 600, GetColor(255, 255, 255), TRUE);
	DrawGraph(0, 0, g_gametitling, TRUE);
	//テキストを表示
	DrawStringToHandle(100, 400, "Zキーでゲームスタート", GetColor(255, 0, 255), g_middlefont);
	DrawStringToHandle(100, 460, "カーソルキーで上下左右に移動", GetColor(0, 0, 0), g_middlefont);
	//キーチェックをして画面を切り替え
	int key = GetJoypadInputState(DX_INPUT_KEY_PAD1);
	if(IsAKeyTrigger(key) == TRUE) g_gamestate = GAME_MAIN;
	InitStage();
}

//ゲーム本編描画
void DrawGameMain(){
	GameMain();
}

void DrawGameClear(){
	
}

//ゲームオーバー画面描画
void DrawGameOver(){
	//テキスト表示
	DrawStringToHandle(100, 400, "ゲームオーバー", GetColor(255, 0, 0), g_largefont);
	//5秒たったらタイトル画面へ
	if(g_lasttime - g_timerstart >5000) g_gamestate = GAME_TITLE;
}

//キートリガー処理
BOOL IsAKeyTrigger(int key){
	if(key & PAD_INPUT_A){
		if(g_akey_prev == FALSE){
			g_akey_prev = TRUE;
			return TRUE;
		}
	}
	else{
		g_akey_prev = FALSE;
	}
	return FALSE;
}

main.h

コード:

#ifndef _MAIN_H_
#define _MAIN_H_

#include<DxLib.h>
#include"gamemain.h"
#include"loading.h"

//グローバル変数
//時間計測用変数
extern int g_lasttime;    //直前の計測時間
extern float g_frametime; //1ループにかかった時間
extern int g_timerstart;  //タイマー用変数

enum GameState{				//ゲーム状態
	GAME_TITLE, GAME_MAIN,
	GAME_CLEAR, GAME_OVER
};

extern GameState g_gamestate;
extern int g_gametitling;  //タイトルイメージ
extern int g_heroimg;      //画像
extern float g_hx, g_hy;   //座標
//ボタン
extern BOOL g_akey_prev;   //直前のAボタンの状態
//フォント
extern int g_middlefont;   //中サイズフォントハンドル
extern int g_largefont;    //大サイズフォントハンドル

//関数プロトタイプ宣言
void DrawGameTitle();
void DrawGameMain();
void DrawGameClear();
void DrawGameOver();
BOOL IsAKeyTrigger(int key);

#endif 
gamemain.cpp

コード:

#include "gamemain.h"

int g_mapdata[MAP_HEIGHT][MAP_WIDTH]={
	//0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, //0
	{ 1, 7, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ,4}, //1
	{ 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 9}, //2
	{ 1, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1}, //3
	{ 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 3, 1, 0, 0, 0, 1}, //4
	{ 1, 0, 1, 0, 0, 1, 0, 8, 1, 0, 0, 1, 0, 1, 0, 1}, //5
	{ 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1}, //6
	{ 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}, //7
	{ 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1}, //8
	{ 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1}, //9
	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1}, //10
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, //11
};

StageData g_stagedata;

//ステージ初期化
void InitStage(){
	int enemy=0;
	for(int y=0; y<MAP_HEIGHT; y++){
		for(int x=0; x<MAP_WIDTH; x++){
			int c = g_mapdata[y][x];
			switch(c)
			{
			case MPITEM_HEROPOS:
				g_stagedata.herox = x;
				g_stagedata.heroy = y;
				g_mapdata[y][x] = 0;
				break;
			case MPITEM_HMONSTER:
			case MPITEM_VMONSTER:
			case MPITEM_DRAGON:
				g_stagedata.enemies[enemy].x=x;
				g_stagedata.enemies[enemy].y=y;
				g_stagedata.enemies[enemy].type=(MonsterType)c;
				g_stagedata.enemies[enemy].living=TRUE;
				g_stagedata.enemies[enemy].direction=-1;
				g_mapdata[y][x]=0;
				enemy++;
				break;
			default:
				break;
			}
		}
	}
	//ドラゴンの炎のために予約
	for(int i=0; i<=MAXENEMY; i++){
		//ドラゴンを探す
		if(g_stagedata.enemies[i].type == MT_DRAGON){
		   g_stagedata.enemies[i].fireidx = enemy;
		   g_stagedata.enemies[i].firetimer = 0;
		   enemy += FIREEXPAND;
		}
	}
}


void GameMain(){
	//移動制限
	g_stagedata.movecounter++;
	g_stagedata.movecounter %= MOVERATE;

	DrawMap();
	DrawEnemy();
	//自キャラ移動
	int key =GetJoypadInputState(DX_INPUT_KEY_PAD1);
	if(g_stagedata.movecounter==0){
		int hx = g_stagedata.herox;
		int hy = g_stagedata.heroy;
		if(key&PAD_INPUT_UP) hy -= 1;
		if(key&PAD_INPUT_DOWN) hy += 1;
		if(key&PAD_INPUT_LEFT) hx -= 1;
		if(key&PAD_INPUT_RIGHT) hx += 1;
		//障害物チェック
		if(g_mapdata[hy][hx]==MPITEM_NO){
		g_stagedata.herox = hx;
		g_stagedata.heroy = hy;
		}
	}
	DrawGraph(g_stagedata.herox*IMG_CHIPSIZE,
		g_stagedata.heroy*IMG_CHIPSIZE,
		g_imghandles.mapitems[MPITEM_HEROPOS], TRUE);
	//Zキーをチェックして画面を切り替え
	if(IsAKeyTrigger(key) ==TRUE){
		g_gamestate = GAME_OVER;
		g_timerstart = g_lasttime; //タイマーセット
	}
}

void DrawMap(){
	for(int y=0;y<MAP_HEIGHT;y++){
		for(int x=0;x<MAP_WIDTH;x++){
			DrawGraph(x*IMG_CHIPSIZE, y*IMG_CHIPSIZE, g_imghandles.field, FALSE);
			//マップアイテム描画
			int c = g_mapdata[y][x];
			if(c>0){
				DrawGraph(x*IMG_CHIPSIZE, y*IMG_CHIPSIZE,
					g_imghandles.mapitems[c], TRUE);
			}
		}
	}
}

void DrawEnemy(){
	for(int i=0; i<MAXENEMY; i++){
		if(g_stagedata.enemies[i].living == FALSE)continue;
		MonsterType c = g_stagedata.enemies[i].type;
		if(g_stagedata.movecounter == 0){
			int ex = g_stagedata.enemies[i].x;
			int ey = g_stagedata.enemies[i].y;
			//移動処理
			if(c == MT_HOLI)ex += g_stagedata.enemies[i].direction;
			if(c == MT_VERT)ey += g_stagedata.enemies[i].direction;
			if(c == MT_DRAGON)DrawDragonFire(i);
			if(g_mapdata[ey][ex] == MPITEM_NO){
				g_stagedata.enemies[i].x = ex;
				g_stagedata.enemies[i].y = ey;
			}
			else{
				//方向反転
				g_stagedata.enemies[i].direction *= -1;
			}
			//当たり判定
			if((g_stagedata.enemies[i].x == g_stagedata.herox)&&
			   (g_stagedata.enemies[i].y == g_stagedata.heroy)){
			   g_gamestate = GAME_OVER;
			   g_timerstart = g_lasttime; //タイマーセット
			}
		}
		DrawGraph(g_stagedata.enemies[i].x*IMG_CHIPSIZE,
			g_stagedata.enemies[i].y*IMG_CHIPSIZE,
			g_imghandles.mapitems[(int)c], TRUE);
	}
}

void DrawDragonFire(int idx){
	int t = g_stagedata.enemies[idx].firetimer;
	int f = g_stagedata.enemies[idx].fireidx;
	if(t < FIREEXPAND){
		//炎を伸ばす
		for(int i=0; i<FIREEXPAND; i++){
			if(i <= t){
				g_stagedata.enemies[f+i].living=TRUE;
				g_stagedata.enemies[f+i].type=MT_FIRE;
				g_stagedata.enemies[f+i].x=g_stagedata.enemies[idx].x-i-1;
				g_stagedata.enemies[f+i].y=g_stagedata.enemies[idx].y;
			}
			else{
				g_stagedata.enemies[f+i].living=FALSE;
			}
		}
	}
	else if(t < FIRESHRINK){
		//炎を縮める
		for(int i=0; i<FIREEXPAND; i++){
			if(i <= (FIRESHRINK-t-1)){
				g_stagedata.enemies[f+i].living=TRUE;
				g_stagedata.enemies[f+i].type=MT_FIRE;
				g_stagedata.enemies[f+i].x=g_stagedata.enemies[idx].x-i-1;
				g_stagedata.enemies[f+i].y=g_stagedata.enemies[idx].y;
			}
			else{
				g_stagedata.enemies[f+i].living=FALSE;
			}
		}
	}
	else{
		for(int i=0; i<FIREEXPAND; i++){
				g_stagedata.enemies[f+i].living=FALSE;
		}
	}
	g_stagedata.enemies[idx].firetimer++;
	g_stagedata.enemies[idx].firetimer %= FIRESTOP;
}
gamemain.h

コード:

#ifndef _GAMEMAIN_H_
#define _GAMEMAIN_H_

#include <DxLib.h>
#include"main.h"

#define IMG_CHIPSIZE 50
#define MAP_WIDTH 16
#define MAP_HEIGHT 12
#define MOVERATE 15
#define MAXENEMY 20
#define FIREEXPAND 3
#define FIRESHRINK 6
#define FIRESTOP 12

extern int g_mapdata[MAP_HEIGHT][MAP_WIDTH];

enum MapItem{
	MPITEM_NO, MPITEM_ROCK, MPITEM_HMONSTER, MPITEM_VMONSTER, MPITEM_DRAGON,
	MPITEM_HEROPOS = 7, MPITEM_KEY, MPITEM_GOAL
};

enum MonsterType{
	MT_HOLI=2, MT_VERT, MT_DRAGON, MT_FIRE
};
struct CharaData{
	int x, y;
	BOOL living;
	MonsterType type;
	int direction;
	int fireidx;
	int firetimer;
};

struct StageData{
	int herox, heroy;
	int movecounter;
	CharaData enemies[MAXENEMY];
};
extern StageData g_stagedata;

void GameMain();
void DrawMap();
void InitStage();
void DrawEnemy();
void DrawDragonFire(int idx);

#endif

loading.cpp

コード:

#include "loading.h"

ImageHandles g_imghandles;

BOOL LoadGameImage(){
	g_imghandles.field = LoadGraph("media\\smp1_back.png");
	if(g_imghandles.field == -1)return FALSE;

	g_imghandles.mapitems[1] = LoadGraph("media\\smp1_rock.png");
	if(g_imghandles.mapitems[1] == -1) return FALSE;
	g_imghandles.mapitems[2] = LoadGraph("media\\smp1_chara02.png");
	if(g_imghandles.mapitems[2] == -1) return FALSE;
	g_imghandles.mapitems[3] = g_imghandles.mapitems[2];
	g_imghandles.mapitems[4] = LoadGraph("media\\smp1_chara03.png"); 
	if(g_imghandles.mapitems[4] == -1) return FALSE;
	g_imghandles.mapitems[5] = LoadGraph("media\\smp1_chara04.png");
	if(g_imghandles.mapitems[5] == -1) return FALSE;
	g_imghandles.mapitems[7] = LoadGraph("media\\smp1_chara01.png"); 
	if(g_imghandles.mapitems[7] == -1) return FALSE;
	g_imghandles.mapitems[8] = LoadGraph("media\\smp1_key.png"); 
	if(g_imghandles.mapitems[8] == -1) return FALSE;
	g_imghandles.mapitems[9] = LoadGraph("media\\smp1_goal.png");	
	if(g_imghandles.mapitems[9] == -1) return FALSE;

	return TRUE;
}

loading.h

コード:

#ifndef _LOADING_H_
#define _LOADING_H_

#include <DxLib.h>

struct ImageHandles{
	int field;		  //背景の草原
	int mapitems[10]; //マップ上のアイテム
};
extern ImageHandles g_imghandles;

BOOL LoadGameImage();

#endif



Rittai_3D
記事: 525
登録日時: 7年前

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#2

投稿記事 by Rittai_3D » 5年前

ご自分でデバッグはされましたか?
していないのなら、printfDx() で怪しいと思われる変数の数値を見てみましょう。おかしい部分があるはずです。

softyaさんのデバッグ講座が参考になると思います。ぜひ一度目を通してみてください。
http://dixq.net/forum/blog.php?u=114&b=982&c=2
本を読み直し間違っている部分を考えてみたのですがよくわかりません・・(>_<)
考えるだけでなく、原因を調べてみましょう。
すいませんが間違いを見つけていただけると嬉しいです。
間違いを見つけるのはご自分でないと、今後の力にならないと思います。
オフトピック

コード:

DrawGraph(g_stagedata.herox*IMG_CHIPSIZE,
        g_stagedata.heroy*IMG_CHIPSIZE,
        g_imghandles.mapitems[MPITEM_HEROPOS], TRUE);
これって g_imghandles.mapitems[MPITEM_HEROPOS] の部分が範囲外アクセスになっていませんか?
初心者です

kyonkyon
記事: 7
登録日時: 5年前

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#3

投稿記事 by kyonkyon » 5年前

>> Rittai_3Dさん
返信ありがとうございます!!デバッグをしながらバグを探していくのが常なのですね!勉強になりました。

初心者ながらデバッグをしながらどこの変数がおかしいか調べてみたところgamemain.cppの56行目の変数enemyがどのような挙動を示すか見てみたところ値が7で止まらないといけないところ・・・デバッグを続けるとenemyの値が3に減少してしまいました。これが原因かなと思ったのですがどうして減少するのか原因が特定できません・・・でした・・なぜでしょうか・・?

Rittai_3D
記事: 525
登録日時: 7年前

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#4

投稿記事 by Rittai_3D » 5年前

おかしいところ(バグ)があるからデバッグするのでは?デバッグをするのはバグが出たときだけでよいと思います。
kyonkyon さんが書きました:初心者ながらデバッグをしながらどこの変数がおかしいか調べてみたところgamemain.cppの56行目の変数enemyがどのような挙動を示すか見てみたところ値が7で止まらないといけないところ・・・デバッグを続けるとenemyの値が3に減少してしまいました。これが原因かなと思ったのですがどうして減少するのか原因が特定できません・・・でした・・なぜでしょうか・・?
質問を質問で返して申し訳ありませんが、kyonkyon さんは何が原因だと思いますか?
ここで直接の答えを教えてしまうと、他人に教えてもらうのが癖になって、自分で考えなくなるかもしれませんので、直接は教えません。
おかしいところの原因を考えるのがデバッグです。そして、それを考えるのはあなた自身です。他人ではありません。
56行目の値がおかしいなら、その周辺で変数enemyの値を変更している部分が怪しいのでは。
値が7で止まらないといけないところ・・・デバッグを続けるとenemyの値が3に減少してしまいました
「値が7で止まらなければならないが、デバッグを続けるとenemyの値が3になってしまった」と読みましたか、意味はこれでよろしいでしょうか?
もしくは、「値が7で止まらなければならないが、デバッグを続けるとenemyの値がだんだんと減っていき3になってしまった」でしょうか?
状況をしっかり説明してくださらないと、原因が分かりません。
初心者です

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

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#5

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

kyonkyonさんは、ゲームをプログラミングできるように「わくわくゲームプログラミング教室」 で学習されているわけですよね。
つまり自力でゲームを作りたいわけですから、デバッグできなかったらプログラムは完成しません。
間違えた原因が書籍に有るのか、kyonkyonさんが間違えたのかは分かりませんが、逆に考えればデバッグの方法を知ったり、プログラムをより深く理解するチャンスでも有るわけです。
自分で作るためには、プログラムの隅から隅まで把握することが出来ないといけないので、このチャンスに理解を深めましょう。

>初心者ながらデバッグをしながらどこの変数がおかしいか調べてみたところgamemain.cppの56行目の変数enemyがどのような挙動を示すか見てみたところ値が7で止まらないといけないところ・・・デバッグを続けるとenemyの値が3に減少してしまいました。これが原因かなと思ったのですがどうして減少するのか原因が特定できません・・・でした・・なぜでしょうか・・?

ここで伝えるべき所は、「変数enemyがどのような挙動を示すか見てみたところ値が7で止まらないといけない」と思った根拠というかememyの理想値の背景説明と「デバッグを続けるとenemyの値が3に減少してしまいました。」と言う部分の加算しかしてないのに減少した不思議現象の、enemy値の変化のパターンを書いてもらうことでしょうか。
私は書籍を持っているわけではないので追試が出来ませんので、kyonkyonさんの情報が全てになります。がんばりましょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

kyonkyon
記事: 7
登録日時: 5年前

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#6

投稿記事 by kyonkyon » 5年前

>> Rittai_3Dさん
言い方が悪かったですね(^_^;)デバッグしながらバグの原因を探すの間違いです。
原因は敵モンスターを格納する配列enemies[20]がおかしなことになっているためモンスターが表示されないかと考えて今デバッグを実行しています。また、プログラムを実行した際、フィールドに一瞬ちゃんと配置されたモンスターが出てきてすぐさま消えるという現象が起こっているのでそこの原因も考えます。またenemyの値の解釈ですが言葉足らずですいません。その通りです。gamemain.cppの56行目でenemyについてデバッグすると4→0と推移しその後0のままです。softyaさんのおっしゃるように加算しかしていないのに減算されているためどこのせいで減算されているかも究明中です。57行目にprintf("%d", enemy);を入れてデバッグするとenemyは7→3と推移しました。

>>softyaさん
激励の言葉ありがとうございます。調べるとプログラミングのかなりの時間はデバッグに費やされると書いてありました。なるほどデバッグの重要性が分かりました。またsoftyaさんのサイト参考にさせていただきました。ありがとうございます。ここですこしでもデバッグの基礎がわかるように頑張ります。変数enemyに関しては言葉足らずでした。enemyの値が7でなくてはならないと考えた理由はモンスター4体(ドラゴン1体とデベソモンスター3体)とドラゴンの炎(モンスターと扱う)3マス分を敵とみなし配列に格納させようとしているためです。しかし結局は3になってしまっているのでそのせいでモンスターが消失しているのかと考えました。また変数enemyの値の推移は上述したとおりです。

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

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#7

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

for(int i=0; i<=MAXENEMY; i++){のループ内で4→0って変化すると言うことでしょうか?
InitStage関数を抜ける寸前にenemies配列に最終的に入っている値をprintfなどで確認してもらったほうが良さそうですね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

free
記事: 29
登録日時: 5年前

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#8

投稿記事 by free » 5年前

はじめまして。freeです。
私も、その本でプログラミングの練習をやっていました。

質問をよく見ていると、恐らく本の4章目の内容だと思いましたので、回答しました。

そのバグですが、たぶん製作者側(著者)のミスだと思います。私も試してみたら確かに、ドラゴンが炎を吹くはずが、
画像がドラゴンと炎で入れ替わっているというわけのわからないことになっていました。が、最後までやっていくとなぜか
ちゃんと完成するんです。

順序的に4-7「鍵を拾ったらゴールできるようにする」の182ページから186ページにあるコードを先に書いてから、
ドラゴンや鍵、ゴールの処理をすると良いと思われます。(多分、そのやり方が正解かと)

途中でデバッグするとわけのわからないことになりますがこのように進めると良いでしょう。(多分)

gamemain.h

コード:

#ifndef __GAMEMAIN_H__
#define __GAMEMAIN_H__

#include <DxLib.h>
#include "Main.h"

#define IMG_CHIPSIZE 50
#define MAP_WIDTH 16
#define MAP_HEIGHT 12
#define MOVERATE 15
#define MAXENEMY 20
#define FIREEXPAND 3
#define FIRESHRINK 6
#define FIRESTOP 12
#define MAXSTAGE 2

extern int g_mapdata[MAP_HEIGHT][MAP_WIDTH];

enum MapItem{
	MPITEM_NO, MPITEM_ROCK, MPITEM_HMONSTER, MPITEM_VMONSTER, MPITEM_DRAGON,
	MPITEM_HEROPOS = 7, MPITEM_KEY, MPITEM_GOAL
};

enum MonsterType{
	MT_HOLI=2, MT_VERT, MT_DRAGON,MT_FIRE
};

struct CharaData{
	int x, y;
	BOOL living;
	MonsterType type;
	int direction;
	int fireidx;
	int firetimer;
};

struct StageData{
	int herox, heroy;
	int movecounter;
	CharaData enemies[MAXENEMY];
	BOOL getkey;
	int stagenum;
};
extern StageData g_stagedata;

void GameMain();
void DrawMap();
void InitStage();
void DrawEnemy();
void DrawDragonFire(int idx);

#endif

gamemain.cppのInitStage関数

コード:

void InitStage(){
	ZeroMemory(g_stagedata.enemies, sizeof(g_stagedata.enemies));
	char buf[256];
	sprintf_s(buf, 256, "media\\stage%d.txt", g_stagedata.stagenum + 1);
	int fh = FileRead_open(buf);
	for (int y = 0; y < MAP_HEIGHT; y++){
		FileRead_gets(buf, 256, fh);
		for (int x = 0; x < MAP_WIDTH; x++){
			g_mapdata[y][x] = (int)(buf[x] - '0');
		}
	}
	FileRead_close(fh);
main.cppのDrawGameClear関数

コード:

void DrawGameClear(){
	DrawBox(0, 0, 800, 600, GetColor(255, 255, 255), TRUE);
	//テキスト表示
	DrawStringToHandle(100, 200, "ゲームクリア",
		GetColor(80, 128, 255), g_largefont);
	//5秒経ったらタイトル画面へ
	if (g_lasttime - g_timerstart > 5000) {
		g_stagedata.stagenum++;
		g_stagedata.stagenum %= MAXSTAGE;
		if (g_stagedata.stagenum == 0) {
			g_gamestate = GAME_TITLE;
		}else{
			g_gamestate = GAME_MAIN;
			InitStage();
		}
	}
}
これを先に各ファイルの正しい場所に書けば良いと思います。
あと、本の最初の方に『しっかり勉強し直す人は別の本で学習を~』って書いてあったと思うんですけど、
この本では流れを掴むための本、と私は思います。

・・・とは言いましたが、ちゃんと買ったからには最後までやってくださいね。

free
記事: 29
登録日時: 5年前

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#9

投稿記事 by free » 5年前

さっきの文に追加です。

この先もし、読んでみて順序的におかしい、確認してみておかしい、と思ったら(気づけばの話です)、
まず、質問せずに自分でこうかな?といろいろ試してみるのが一番いい方法だと思います。

kyonkyon
記事: 7
登録日時: 5年前

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#10

投稿記事 by kyonkyon » 5年前

>>softyaさん
はい!ループ内で4→0と変化しました。
ループを抜けた地点で配列enemiesについてデバッグしたところと配列に格納されている値に関しては問題は見当たりませんでした。
g_stagedata.enemies[0] {x=15 y=1 living=1 ...}
g_stagedata.enemies[1] {x=5 y=3 living=1 ...}
g_stagedata.enemies[2] {x=10 y=4 living=1 ...}
g_stagedata.enemies[3] {x=12 y=10 living=1 ...}
g_stagedata.enemies[4] {x=0 y=0 living=0 ...}
以降ずっと{x=0 y=0 living=0}となっており問題ありませんでした。ただ、g_stagedata.enemies.fireidxに関しては変数enemyが4→0と推移するせいでループ内では同様の推移をしました。

>>freeさん
返信ありがとうございます!ほんとでした!InitStage関数の最初に仰られたとおりに打ち込むとモンスターがちゃんと出てくれました。助言のほどありがとうございます!!しかしとなると原因は配列内を初期化してなかったから・・なのでしょうか・・難しい(´Д` )wwこの本は僕もゲーム作りの流れをおおまかに捉えるために使わせてもらっています。これを改造したりして色々遊んでみたいと思います!!^^

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

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#11

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

変数の寿命とかスコープの問題でenemyが0に成る所が無さそうなんですよね。
ただしデバッグビルドではなくリリースビルドしていた場合はデバッガが完全に変数の変化をトレースできませんので、誤表示する場合があります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

kyonkyon
記事: 7
登録日時: 5年前

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#12

投稿記事 by kyonkyon » 5年前

>>softyaさん
リリースビルドは行なっておらずデバッグビルドしてますのでおそらく間違いはないと思います!
いくら探してもenemyがゼロになる理由が分かりませんので不本意ではありますがこの疑問についてはここで諦めます(^^;;

回答くださった方ありがとうございました!

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

Re: 14歳からはじめるC言語わくわくゲームプログラミング教室 VS2013編

#13

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

kyonkyon さんと私の間でイメージのすれ違いがあると思います。
私のデバッグ法でenemyを表示するprintfを組み込んでもらって、その直したソースコードとprintfの実行結果をコピペ貼ってもらえばお互いにズレは埋まると思うんですよ。
無理にとは言いませんので、よかったらご検討下さい。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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