STGでグレイズを作成中なのですが・・・

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

STGでグレイズを作成中なのですが・・・

#1

投稿記事 by Fank » 8年前

縦スクロールのSTGでグレイズ(かすり)を作成していて
ビルドは通るのですがデバックを開始すると

例外がスローされました:読み取りアクセス違反。
this が nullptr でした。
この例外のハンドラーがある場合は、プログラムを安全に続行できます。

と、エラーが出てしまい
graze.cppの

コード:

bool GRAZE::GetSound()
{
	return s_graze;//
}

コード:

return s_gtaze;
の右に黄色の矢印が出てきました。
分かる方いましたら教えていただきたいです。

全体のコードは以下のようになっています。

コード:

[graze.h]
#pragma once

class GRAZE {
public:

	//グラフィックハンドル
	static int gh;

	//座標
	double x, y;

	//角度
	double rad;

	//アルファ値
	int alpha;

	//拡大率
	double rate;

	//カウント
	int count;

	//グレイズクラス消滅
	//bool endflag;


	//実行中かどうかのフラグ
	bool flag;

	bool s_graze;

private:
	void Move();
	void Draw();

public:
	GRAZE();
	void SetFlag(double x, double y);
	bool GetFlag();
	void All();
	bool GetSound();

};

コード:

[graze.cpp]
#include "pch.h"
#include "control.h"

#include<ctime>
#include<cstdlib>
#include<math.h>

int GRAZE::gh;

GRAZE::GRAZE()
{
	x = y = 0;

	//初回だけ読み込む
	if (gh == 0)
	{
		gh = LoadGraph("graze.png");
	}

	rad = rate = 0;
	alpha = 255;
	flag = false;
	s_graze = false;

	count = 0;

	srand((unsigned int)time(NULL));

}

void GRAZE::Move()
{
	//初回だけ角度設定
	if (count == 0)
	{
		rad = rand() % 628 / 100;
	}

	alpha = 255 - (255 / 20)*count;

	rate = 1.0 - 0.05*count;

	x += cos(rad) * 6;
	y += sin(rad) * 6;

	if (count == 20)
	{
		count = 0;
		flag = false;
	}

}

void GRAZE::Draw()
{
	SetDrawBlendMode(DX_BLENDMODE_ALPHA, alpha);

	DrawRotaGraph(x, y, rate, 1, gh, TRUE);

	SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
}

void GRAZE::All()
{
	if (flag)
	{
		Move();
		Draw();
	}
	//return endflag;
}

bool GRAZE::GetFlag()
{
	return flag;
}

void GRAZE::SetFlag(double x, double y)
{
	this->x = x;
	this->y = y;
	
	flag = true;
}

bool GRAZE::GetSound()
{
	return s_graze;//
}

コード:

[control.h]
#pragma once

#include "graze.h"
#include"playereffect.h"
#include "player.h"
#include"back.h" 
#include"enemyefect.h"
#include"enemy.h"

class CONTROL{
private:
	//プレイヤークラス
	PLAYER *player;
	
	//背景クラス
	BACK *back;

	//エネミークラス
	ENEMY *enemy[ENEMY_NUM];
	
       //グレイズクラス
	GRAZE *graze[GRAZE_NUM];

	//敵消滅エフェクトクラス
	EFFECT_EDEAD *effect_edead[EFFECT_EDEADNUM];

	EFFECT_PDEAD *effect_pdead[EFFECT_PDEADNUM];

	//サウンドハンドル
	int s_eshot;
	int s_pshot;
	int s_edead;
	int s_pdead;
	int s_graze;

	//サウンドを鳴らすかどうかのフラグ
	bool eshot_flag;
	bool pshot_flag;


	//敵死亡
	bool edead_flag;

	//プレイヤー死亡
	bool pdead_flag;

	//グレイズSE
	bool graze_flag;

private:
	CONTROL();
	~CONTROL();
	void SoundAll();
	void CollisionAll();
	bool CircleCollision(double c1, double c2, double cx1, double cx2, double cy1, double cy2);
	void EnemyDeadEffect(double x, double y);
	void PlayerDeadEffect(double x, double y);

public:
	void All();
	void GetPlayerPosition(double *x, double *y);
	void GetEnemyPosition(int index, double *x, double *y);
	static CONTROL& GetInstance() {
		static CONTROL control;
		return control;
	}


};

コード:

[control.cpp]
#include "pch.h"
#include "control.h"


//***********************************************************************************************
//
//		コンストラクタ(初期設定)
//
//***********************************************************************************************

CONTROL::CONTROL()
{
	player = new PLAYER;

	back = new BACK;

	//エフェクトクラスのインスタント生成
	for (int i = 0; i < EFFECT_EDEADNUM; i++)
	{
		effect_edead[i] = new EFFECT_EDEAD;
	}

	for (int i = 0; i < EFFECT_PDEADNUM; i++)
	{
		effect_pdead[i] = new EFFECT_PDEAD;
	}

	FILE *fp;
	ENEMY_DATA data[ENEMY_NUM];
	char buf[100];
	int c;
	int col = 1;
	int row = 0;

	memset(buf, 0, sizeof(buf));
	fp = fopen("enemydata.csv", "r");

	//ヘッダ読み飛ばし
	while (fgetc(fp) != '\n');

	while (1)
	{
		while (1) 
		{

			c = fgetc(fp);

			//末尾ならループを抜ける。
			if (c == EOF)
				goto out;

			//カンマか改行でなければ、文字としてつなげる
			if (c != ',' && c != '\n')
				strcat(buf, (const char*)&c);
			//カンマか改行ならループ抜ける。
			else
				break;
		}

		//ここに来たということは、1セル分の文字列が出来上がったということ
		switch (col) 
		{
			//1列目は敵種類を表す。atoi関数で数値として代入。
		case 1:	data[row].type = atoi(buf); break;
			//2列目は弾種類。以降省略。
		case 2: data[row].stype = atoi(buf); break;
		case 3: data[row].m_pattern = atoi(buf); break;
		case 4: data[row].s_pattern = atoi(buf); break;
		case 5: data[row].in_time = atoi(buf); break;
		case 6: data[row].stop_time = atoi(buf); break;
		case 7: data[row].shot_time = atoi(buf); break;
		case 8: data[row].out_time = atoi(buf); break;
		case 9: data[row].x = atoi(buf); break;
		case 10: data[row].y = atoi(buf); break;
		case 11: data[row].speed = atoi(buf); break;
		case 12: data[row].hp = atoi(buf); break;
		case 13: data[row].item = atoi(buf); break;
		}
		//バッファを初期化
		memset(buf, 0, sizeof(buf));
		//列数を足す
		++col;

		//もし読み込んだ文字が改行だったら列数を初期化して行数を増やす
		if (c == '\n') 
		{
			col = 1;
			++row;
		}
	}
out:

	//敵クラス生成
	for (int i = 0; i<ENEMY_NUM; ++i) 
	{
		enemy[i] = new ENEMY(data[i].type, data[i].stype, data[i].m_pattern, data[i].s_pattern, data[i].in_time, data[i].stop_time, data[i].shot_time,
			data[i].out_time, data[i].x, data[i].y, data[i].speed, data[i].hp, data[i].item);
	}

	//サウンドファイル読み込み
	s_eshot = LoadSoundMem("enemyshot.wav");
	s_pshot = LoadSoundMem("playershot.mp3");

	s_edead = LoadSoundMem("enemydead.wav");
	s_pdead= LoadSoundMem("playerdead.mp3");

	s_graze = LoadSoundMem("graze.wav");


	eshot_flag = false;
	pshot_flag = false;
	edead_flag = false;
	pdead_flag = false;
	graze_flag = false;
}



bool CONTROL::CircleCollision(double c1, double c2, double cx1, double cx2, double cy1, double cy2)
{

	double hlength = c1 + c2;
	double xlength = cx1 - cx2;
	double ylength = cy1 - cy2;

	if (hlength*hlength >= xlength*xlength + ylength*ylength)
	{
		return true;
	}
	else 
	{
		return false;
	}
}

//***********************************************************************************************
//
//		プレイヤー位置
//
//***********************************************************************************************

void CONTROL::GetPlayerPosition(double *x, double *y)
{
	double tempx, tempy;

	player->GetPosition(&tempx, &tempy);

	*x = tempx;
	*y = tempy;
}


//***********************************************************************************************
//
//		敵位置
//
//***********************************************************************************************

void CONTROL::GetEnemyPosition(int index, double *x, double *y)
{
	double tempx, tempy;

	//指定した添字の敵の座標を取得
	enemy[index]->GetPosition(&tempx, &tempy);

	//代入
	*x = tempx;
	*y = tempy;
}


//***********************************************************************************************
//
//		All関数
//
//***********************************************************************************************

void CONTROL::All()
{
	//サウンドフラグを初期化
	eshot_flag = pshot_flag = edead_flag = pdead_flag = graze_flag = false;

	//描画領域を指定
	SetDrawArea(MARGIN, MARGIN, MARGIN + 380, MARGIN + 460);

	back->All();

	player->All();

	//title->All();

	//プレイヤーサウンドフラグチェック
	if (player->GetShotSound()) 
	{
		pshot_flag = true;
	}

	if (player->GetDeadSound()) 
	{
		pdead_flag = true;
	}

	for (int i = 0; i<ENEMY_NUM; i++) 
	{
		if (enemy[i] != NULL) 
		{
			//敵ショットサウンドフラグチェック
			if (enemy[i]->GetShotSound()) 
			{
				eshot_flag = true;
			}

			if (enemy[i]->GetDeadSound()) 
			{
				edead_flag = true;
			}

			if (enemy[i]->All()) 
			{
				delete enemy[i];
				enemy[i] = NULL;
			}
		}
	}

	//当たり判定
	CollisionAll();

	//敵消滅エフェクト
	for (int i = 0; i < EFFECT_EDEADNUM; i++)
	{
		if (effect_edead[i]->GetFlag())
		{
			effect_edead[i]->All();
		}
	}

	//プレイヤー消滅エフェクト
	for (int i = 0; i < EFFECT_PDEADNUM; i++)
	{
		if (effect_pdead[i]->GetFlag())
		{
			effect_pdead[i]->All();
		}
	}

	//グレイズ
	for (int i = 0; i < GRAZE_NUM; i++)
	{
		//サウンドフラグチェック
		if (graze[i]->GetSound())
		{
			graze_flag = true;
		}
		graze[i]->All();
	}



	SoundAll();

	++g_count;
}


//***********************************************************************************************
//
//		SE再生(バックグラウンド)
//
//***********************************************************************************************
void CONTROL::SoundAll()
{

	if (pshot_flag) 
	{
		PlaySoundMem(s_pshot, DX_PLAYTYPE_BACK);
	}  

	if (eshot_flag) 
	{
		PlaySoundMem(s_eshot, DX_PLAYTYPE_BACK);
	}

	if (edead_flag) 
	{ 
		PlaySoundMem(s_edead, DX_PLAYTYPE_BACK);
	}

	if (pdead_flag)
	{
		PlaySoundMem(s_pdead, DX_PLAYTYPE_BACK);
	}

	if (graze_flag)
	{
		PlaySoundMem(s_graze, DX_PLAYTYPE_BACK);
	}

}




//***********************************************************************************************
//
//		敵消滅エフェクト
//
//***********************************************************************************************

void CONTROL::EnemyDeadEffect(double x, double y)
{
	//エフェクトセット
	for (int z = 0; EFFECT_EDEADNUM; z++)
	{
		if (!effect_edead[z]->GetFlag())
		{
			effect_edead[z]->SetFlag(x, y);
			break;
		}
	}
}

//***********************************************************************************************
//
//		プレイヤー消滅エフェクト
//
//***********************************************************************************************

void CONTROL::PlayerDeadEffect(double x, double y)
{
	//エフェクトセット
	for (int z = 0; EFFECT_PDEADNUM; z++)
	{
		if (!effect_pdead[z]->GetFlag())
		{
			effect_pdead[z]->SetFlag(x, y);
			break;
		}
	}
}


//***********************************************************************************************
//
//		当たり判定
//
//***********************************************************************************************

void CONTROL::CollisionAll()
{
	double px, py, ex, ey;

	bool tempflag = false;
	bool gtempflag = false;

	//操作キャラの弾と敵との当たり判定
	for (int i = 0; i<PSHOT_NUM; ++i)
	{
		if (player->GetShotPosition(i, &px, &py))
		{
			for (int s = 0; s<ENEMY_NUM; ++s)
			{
				//敵クラスのポインタがNULLじゃない、かつdeadflagがfalse(死んでない&帰還してない)
				if (enemy[s] != NULL && !enemy[s]->GetDeadFlag())
				{
					enemy[s]->GetPosition(&ex, &ey);
					//当たり判定
					if (CircleCollision(PSHOT_COLLISION, ENEMY1_COLLISION, px, ex, py, ey))
					{
						//当たっていれば、deadflagを立てる
						enemy[s]->SetDeadFlag();
						//当たった弾のフラグを戻す
						player->SetShotFlag(i, false);
						//敵消滅音フラグセット
						edead_flag = true;
						//敵消滅エフェクトセット
						EnemyDeadEffect(ex, ey);
					}
				}
			}
		}
	}


	//敵の弾と操作キャラとの当たり判定
	//プレイヤーが生きていれば
	if (!player->GetDamageFlag())
	{
		player->GetPosition(&px, &py);
		for (int i = 0; i < ENEMY_NUM; i++)
		{
			if (enemy[i] != NULL)
			{
				for (int s = 0; s < ENEMY_SNUM; s++)
				{
					//弾フラグが立っていればtrueを返す
					if (enemy[i]->GetShotPosition(s, &ex, &ey))
					{
						//弾によって当たり判定が違うのでswitch文で分岐
						switch (enemy[i]->GetShotType())
						{
						case 0:
							//グレイズ判定
							if (CircleCollision(GRAZE_COLLISION, ESHOT0_COLLISION, px, ex, py, ey))
							{
								gtempflag = true;
							}
							//当たっていれば
							if (CircleCollision(PLAYER_COLLISION, ESHOT0_COLLISION, px, ex, py, ey))
							{
								tempflag = true;
							}
							break;

						case 1:

							if (CircleCollision(GRAZE_COLLISION, ESHOT1_COLLISION, px, ex, py, ey))
							{
								gtempflag = true;
							}
							if (CircleCollision(PLAYER_COLLISION, ESHOT1_COLLISION, px, ex, py, ey))
							{
								tempflag = true;
							}
							break;

						case 2:
							if (CircleCollision(GRAZE_COLLISION, ESHOT2_COLLISION, px, ex, py, ey))
							{
								gtempflag = true;
							}
							if (CircleCollision(PLAYER_COLLISION, ESHOT2_COLLISION, px, ex, py, ey))
							{
								tempflag = true;
							}
							break;

						}

						//グレイズ当たり判定フラグがtrueなら
						if (gtempflag) 
						{
							//まだ
							if (!enemy[i]->GetGrazeFlag(s))
							{
								enemy[i]->SetGrazeFlag(s);
								//グレイズのインスタンス検索
								for (int z = 0; z<GRAZE_NUM; ++z)
								{
									if (!graze[z]->GetFlag()) 
									{
										graze[z]->SetFlag(px, py);
										break;
									}
								}
								//グレイズ音セット
								graze_flag = true;
							}
							gtempflag = false;
						}

						if (tempflag)
						{
							//操作キャラのdamageflagを立てる
							player->SetDamageFlag();
							//弾を消す
							enemy[i]->SetShotFlag(s, false);
							//プレイヤー消滅音フラグを立てる
							pdead_flag = true;
							//一時フラグを戻す
							tempflag = false;
							//プレイヤー消滅エフェクトセット
							PlayerDeadEffect(ex, ey);
						}
					}
				}
			}
		}
	}

}


//***********************************************************************************************
//
//		デストラクタ
//
//***********************************************************************************************

CONTROL::~CONTROL()
{
	delete player;
	delete back;
	delete effect_edead[EFFECT_EDEADNUM];
	delete effect_pdead[EFFECT_PDEADNUM];
	delete graze[GRAZE_NUM];

	for (int i = 0; i<ENEMY_NUM; ++i)
	{
		if (enemy[i] != NULL)
		{
			delete enemy[i];
		}
	}
}

コード:

[pch.h]
//警告を消すための記述
#pragma once
#pragma warning(disable:4244)
#define _CRT_SECURE_NO_WARNINGS

//DXライブラリとdefine.hの取り込み
#include "DxLib.h"
#include "define.h"

コード:

[define.h]
#pragma once

#include <windows.h>

//プレイヤーの歩くスピード
#define PLAYER_SPEED 4

//プレイヤー初期位置
#define PLAYER_INITX 180
#define PLAYER_INITY 400
//x = 180;
//y = 400;

//座標取得
#define MARGIN 10

//背景スクロールスピード
#define SCROLL_SPEED 2

//弾処理
#define PSHOT_NUM 20
#define PSHOT_SPEED 14

//当たり判定用半径定義
#define PLAYER_COLLISION 4
#define ENEMY1_COLLISION 14

#define PSHOT_COLLISION 3
#define ESHOT0_COLLISION 10
#define ESHOT1_COLLISION 3
#define ESHOT2_COLLISION 2

//敵消滅エフェクト
#define EFFECT_EDEADNUM 20

//プレイヤー消滅エフェクト
#define EFFECT_PDEADNUM 20

//グレイズ
#define EFFECT_GRAZENUM	20

#define GRAZE_COLLISION 10

#define GRAZE_NUM		20

//メッセージボックス
#define MSG(m) {\
	MessageBox(NULL,m,"メッセージ",MB_OK);}

//extern宣言してkey配列にどこからでもアクセスできるようにする
extern char key[256];

extern int g_count;

//プレイヤー弾
struct SHOT
{
	bool		flag;			//弾が発射中かどうか
	double		x;				//x座標
	double		y;				//y座標
	int			gh;				//グラフィックハンドル
	int			width, height;	//画像の幅と高さ

};

//エネミー弾
struct E_SHOT
{
	bool	flag;			//弾が発射中かどうか 
	double	x;				//x座標 
	double	y;				//y座標 
	double	rad;			//角度(ラジアン)
	int		gh;				//グラフィックハンドル 
	int		width, height;	//画像の幅と高さ 
	int		pattern;		//ショットパターン 
	int		speed;			//弾スピード 
	bool	gflag;			//グレイズ判定用フラグ
};
#define ENEMY_SNUM 50 


//エネミーデータ
struct ENEMY_DATA 
{
	int		type;			//敵種類
	int		stype;			//弾種類
	int		m_pattern;		//移動パターン
	int		s_pattern;		//発射パターン
	int		in_time;		//出現時間
	int		stop_time;		//停止時間
	int		shot_time;		//弾発射時間
	int		out_time;		//帰還時間
	int		x;				//x座標
	int		y;				//y座標
	int		speed;			//弾スピード
	int		hp;				//HP
	int		item;			//アイテム
};
#define ENEMY_NUM 20
こちらのサイトを参考にしながら
制作しています。(http://bituse.info/game/shot/)

Math

Re: STGでグレイズを作成中なのですが・・・

#2

投稿記事 by Math » 8年前

プロジェクト・ファイルを提示して下さい。(.vcxprojという拡張子のファイルです。)

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

Re: STGでグレイズを作成中なのですが・・・

#3

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

CONTROLクラス内のgrazeを初期化している部分が無いので、オブジェクトがない変な場所にオブジェクトがあると仮定してアクセスしている、というエラーですね。
grazeの定義を変えない場合、使用前のどこかでgrazeの各要素に有効なオブジェクトへのポインタを代入しなければいけません。
effect_edeadおよびeffect_pdeadの各要素についてはインスタント(原文ママ)の作成と代入をしているようなので、同じようにすればいいでしょう。

また、
Fank さんが書きました:

コード:

//***********************************************************************************************
//
//		デストラクタ
//
//***********************************************************************************************

CONTROL::~CONTROL()
{
	delete player;
	delete back;
	delete effect_edead[EFFECT_EDEADNUM];
	delete effect_pdead[EFFECT_PDEADNUM];
	delete graze[GRAZE_NUM];

	for (int i = 0; i<ENEMY_NUM; ++i)
	{
		if (enemy[i] != NULL)
		{
			delete enemy[i];
		}
	}
}
これもダメですね。
effect_edead[EFFECT_EDEADNUM]、effect_pdead[EFFECT_PDEADNUM]、graze[GRAZE_NUM]は全て確保された領域の範囲外(1個次)なので、
アクセス(読み書き)をしてはいけません。
このようにdelete演算子に渡すのもいけないはずです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Fank

Re: STGでグレイズを作成中なのですが・・・

#4

投稿記事 by Fank » 8年前

グレイズクラスのインスタンスを生成すると
デバッグを開始できるようになったのですが

敵の弾にプレイヤーが、かすっても(グレイズ)何も起きなかったです
当たり判定がおかしいのでしょうか?

閉鎖

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