DxLibで作った以下のプログラム

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

DxLibで作った以下のプログラム

#1

投稿記事 by shuka » 5年前

DxLibというライブラリを使って以下のコードをかいたのですが、メニュー画面は意図通りの出力結果なのですがゲームスタートで画面が真っ暗になってしまいます
シューティングゲームです
原因がわからないのでご指摘のほどよろしくお願いします
一回クラスなしで書いてみたのを勉強のためにクラスを用いて書き直してるのですがクラスなしのときは動いたのでそちらも必要であればあげます
main.cppーーーーーーーーーーーーーーーーーー

コード:

#include"DxLib.h"
#include"CHECKKEY.h"
#include"FpS.h"
#include"Medjed.h"
#include"Bullet.h"
#include"MENU.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	CheckKey a; FpS fps; Medjed arbm; Bullet arbb; Menu arb;
	SetFullScreenResolutionMode(DX_FSRESOLUTIONMODE_DESKTOP);
	ChangeWindowMode(FALSE);
	if (DxLib_Init() == -1) return -1;
	SetDrawScreen(DX_SCREEN_BACK);
	int col = GetColor(255, 255, 255);
	if (arb.menu() == 0)
		while (1)
		{
			fps.Fpckg();
			ClearDrawScreen();
			a.checkkey();
			DrawFormatString(100, 100, col, "準備中です\n(escキーを押してください)");
			ScreenFlip();
			if (a.key(KEY_INPUT_ESCAPE))break;
			ProcessMessage();
		}
	if (arb.menu() == 2)
		return 0;
	const int time0 = GetNowCount();
	int eh[3], ph = LoadGraph("画像\\キャラクタ01.png"), MN = 0,EoE[mxenmy];
	CDSPACE plm(290, 220);
	eh[0] = LoadGraph("画像\\enmy1.png"); eh[1] = LoadGraph("画像\\enmy1.png");	eh[2] = LoadGraph("画像\\enmy1.png");
	while (1)
	{
		fps.Fpckg();
		a.checkkey();
		ClearDrawScreen();
		if (arbm.mcul() == TRUE && MN == 0)
			MN = arbb.bcul();
		else MN = 0;
		arbm.mdisp();
		arbb.bbhv();
		arbb.bdisp();
		ScreenFlip();
		ProcessMessage();
		if (a.key(KEY_INPUT_ESCAPE))break;
	}
	DxLib::DxLib_End();
	return 0;
}
menu.hーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

コード:

#pragma once
#include"CDSPACE.h"
class Menu:public CDSPACE
{
	static Menu item[3];
	char* itmnm;
	static int col[2];
	void cpy(const char* a);
	int len(const char* a);
public:
	Menu();
	~Menu();
	Menu(int a, int b,const char* c);
	int menu();
	int slct(int a);
};
menu.cppーーー

コード:

#include"DxLib.h"
#include"CHECKKEY.h"
#include"MENU.h"

int Menu::col[2] = { static_cast<int>(GetColor(255, 255, 255)),static_cast<int>(GetColor(255, 255, 0)) };

Menu Menu::item[3] = { Menu(100,100," チュートリアル"),Menu(100,150," ゲームスタート"),Menu(100,200," ゲーム終了") };

Menu::Menu(int a, int b, const char* c) :CDSPACE(a, b) { itmnm = new char[len(c) + 1]; cpy(c); }

Menu::Menu() {}

Menu::~Menu() { delete[]itmnm; }

int Menu::len(const char* a) { int n = 0; while (*(++a)) { ++n; }return n; }

void Menu::cpy(const char* a) { for (int i = 0; *(itmnm + i) = *(++a); ++i) { ; } }

int Menu::slct(int n)
{
	CheckKey a;
	a.checkkey();
	static int u = 0;
	if (a.key(KEY_INPUT_S))
	{
		if (u == 0)
			++n;
		++u;
	}else if (a.key(KEY_INPUT_W)){
		if (u == 0)
			n += 2;
		++u;
	}else u = 0;
	n %= 3;
	for (int i = 0, j = 0; i <= 2; ++i)
	{
		if (i == n) j = 1, item[i].x = 80;
		else j = 0, item[i].x = 100;
		DrawFormatString(item[i].x, item[i].y, col[j], item[i].itmnm);
	}
	return n;
}

int Menu::menu()
{
	CheckKey a;
	int n = 0;
	while (1)
	{
		a.checkkey();
		ClearDrawScreen();
		n = slct(n);
		ScreenFlip();
		if (a.key(KEY_INPUT_RETURN))break;
		if (a.key(KEY_INPUT_ESCAPE))return 2;
		ProcessMessage();
	}
	return n;
}
Bullet.hーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

コード:

#pragma once
#include"Medjed.h"
class Bullet :public CDSPACE
{
	static const int mxblt=27;
	static int bh, EoB[mxblt];
	static Bullet blt[mxblt];
	bool check(Bullet a);
public:
	Bullet();
	Bullet(int a, int b);
	Bullet(int a, int b, int c);
	Bullet operator=(Medjed);
	int bcul();
	void bbhv();
	void bdisp();
};
bullet.cppーーー

コード:

#include"DxLib.h"
#include"Bullet.h"

int Bullet::EoB[mxblt] = {},Bullet::bh = LoadGraph("画像\\Shot.png");

Bullet Bullet::blt[mxblt];

Bullet::Bullet():CDSPACE(){}

Bullet::Bullet(int a,int b):CDSPACE(a,b){}

Bullet::Bullet(int a, int b, int c) : CDSPACE(a, b) { d = c; }

Bullet Bullet::operator=(Medjed a)
{
	return Bullet(a.hx(), a.hy(),a.hd());
}

bool Bullet::check(Bullet blt)
{
	if (blt.y < -20 || blt.y>500 || blt.x < -20 || blt.x>660)
		return FALSE;
	else return TRUE;
}

int Bullet::bcul()
{
	Medjed mjd = mjd.hndm();
	for (int i = 0; i <= mxblt - 1; ++i)
	{
		if (EoB[i] == 0)
		{
			++EoB[i];
			blt[i] = mjd;
			blt[i].x += 16;
			break;
		}
	}
	return 1;
}

void Bullet::bbhv()
{
	for (int i = 0; i <= mxblt - 1; ++i)
	{
		if (EoB[i] == 1)
		{
			for (int j = 0; j <= 3; ++j)
				if (blt[i].d == j)blt[i] += blt[i];
			if (check(blt[i]) == FALSE)
				EoB[i] = 0;
		}
	}
}

void Bullet::bdisp()
{
	for (int i = 0; i <= mxblt - 1; ++i)
		if (EoB[i] == 1)DrawGraph(blt[i].x, blt[i].y, bh, TRUE);
}
Medjed.hーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

コード:

#pragma once
#include"CDSPACE.h"

class Medjed :public CDSPACE
{
	static int mh[4];
	static Medjed md;
	const static int AGI;
public:
	void mdisp();
	bool mcul();
	Medjed(int a, int b);
	Medjed();
	int hx();
	int hy();
	int hd();
	Medjed hndm();
};
medjed.cppーーー

コード:

#include"DxLib.h"
#include"Medjed.h"
#include"CHECKKEY.h"

Medjed Medjed::md(290, 220);

int Medjed::mh[4] = { LoadGraph("画像\\md0.png"), LoadGraph("画像\\md1.png"), LoadGraph("画像\\md2.png"), LoadGraph("画像\\md3.png") };

int Medjed::hx(){return x;}

int Medjed::hy(){return y;}

int Medjed::hd(){return d;}

Medjed::Medjed(int a, int b):CDSPACE(a, b){}

Medjed::Medjed():CDSPACE(){}

bool Medjed::mcul()
{
	CheckKey a;
	a.checkkey();
	if (a.key(KEY_INPUT_D)) {
		++md;
		md.d = 3;
	}if (a.key(KEY_INPUT_S)) {
		++md;
		md.d = 0;
	}if (a.key(KEY_INPUT_A)) {
		++md;
		md.d = 1;
	}if (a.key(KEY_INPUT_W)) {
		++md;
		md.d = 2;
	}
	if (md.x < 0)md.x=0;
	if (md.x > 593)md.x=593;
	if (md.y < 0)md.y = 0;
	if (md.y > 440)md.y = 440;
	if (a.key(KEY_INPUT_SPACE))
		return TRUE;
	return FALSE;
}

void Medjed::mdisp()
{
	for (int i = 0; i <= 3; ++i)
		if (md.d == i)DrawGraph(md.x, md.y, mh[i], TRUE);
}

Medjed Medjed::hndm()
{
	return md;
}
chckkey.hーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

コード:

#pragma once
class CheckKey {
	static int KEY[256];
public:
	void checkkey();
	bool key(int a);
};
ーーー
checkkey.cpp

コード:

#include"DxLib.h"
#include"CHECKKEY.h"

int CheckKey::KEY[256] = {};

void CheckKey::checkkey() 
{
	char tmpKey[256];
	GetHitKeyStateAll(tmpKey);
	for (int i = 0; i < 256; ++i) {
		if (tmpKey[i] != 0) {
			KEY[i] = 1;
		}
		else {
			KEY[i] = 0;
		}
	}
}

bool CheckKey::key(int a)
{
	return KEY[a];
}
cdspace.hーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

コード:

#pragma once
#define mxenmy 30

class CDSPACE
{
protected:
	int x, y, d;
public:
	CDSPACE();
	CDSPACE(int u, int v);
	CDSPACE(int u, int v, int w);
	CDSPACE operator+(CDSPACE p);
	CDSPACE operator++();
	CDSPACE operator--();
	CDSPACE operator+=(CDSPACE p);
};
cdspace.cppーーー

コード:

#include"CDSPACE.h"
#define AGI 5

CDSPACE CDSPACE::operator--()
{
	if (d == 3) {
		x -= AGI;
	}
	else if (d == 0) {
		y -= AGI;
	}
	else if (d == 1) {
		x += AGI;
	}
	else if (d == 2) {
		y += AGI;
	}
	return CDSPACE(x, y);
}

CDSPACE CDSPACE::operator++()
{
	if (d == 3) {
		x += AGI;
	}
	else if (d == 0) {
		y += AGI;
	}
	else if (d == 1) {
		x -= AGI;
	}
	else if (d == 2) {
		y -= AGI;
	}
	return CDSPACE(x, y);
}

CDSPACE CDSPACE::operator+=(CDSPACE p)
{
	if (d == 3) {
		x += 15;
	}
	else if (d == 0) {
		y += 15;
	}
	else if (d == 1) {
		x -= 15;
	}
	else if (d == 2) {
		y -= 15;
	}
	return CDSPACE(x, y);
}

CDSPACE CDSPACE::operator+(CDSPACE p)
{
	return CDSPACE(x + p.x, y + p.y);
}

CDSPACE::CDSPACE()
{
	x = 0; y = 0; d = 0;
}

CDSPACE::CDSPACE(int u, int v)
{
	x = u; y = v; d = 0;
}
CDSPACE::CDSPACE(int u, int v, int w)
{
	x = u; y = v; d = w;
}
fps.hーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

コード:

#pragma once
class FpS {
	int mStartTime;         //測定開始時刻
	int mCount;             //カウンタ
	float mFps;             //fps
	static const int FPS;	//設定したFPS
	static const int N;
public:
	FpS();
	bool Update();
	void Wait();
	void Fpckg();
};
fps.cppーーー

コード:

#include"DxLib.h"
#include"FpS.h"

const int FpS::FPS = 60;
const int FpS::N = 60;

FpS::FpS()
{
	mStartTime = 0;
	mCount = 0;
	mFps = 0;
}

bool FpS::Update()
{
	if (mCount == 0) { //1フレーム目なら時刻を記憶
		mStartTime = GetNowCount();
	}
	if (mCount == N) { //60フレーム目なら平均を計算する
		int t = GetNowCount();
		mFps = 1000.f / ((t - mStartTime) / (float)N);
		mCount = 0;
		mStartTime = t;
	}
	mCount++;
	return true;
}

void FpS::Wait()
{
	int tookTime = GetNowCount() - mStartTime;	//かかった時間
	int waitTime = mCount * 1000 / FPS - tookTime;	//待つべき時間
	if (waitTime > 0) {
		Sleep(waitTime);	//待機
	}
}

void FpS::Fpckg()
{
	Update();
	Wait();
}};

shuka

追記、補足

#2

投稿記事 by shuka » 5年前

補足情報と改善のためにやってみたことを追記します
補足:コンパイルエラーや、例外のスローなどは出ていません
環境はwindows10でvs2017c++を使ってます
メニュー画面でチュートリアル、ゲーム終了を選んだときは意図通りの処理が実行されています。
ゲームスタートを選択した場合に画面が真っ暗になり何も表示されなくなる感じです。
ただしエスケープキーなどは実装したとおりに反応するので、画像処理に何か問題があるのだとは思います。
主のprogram経験は2か月ちょっと程度で、C++とpythonを勉強しています。(Cも少しだけわかる)

追記:Medjed.cpp(動かすキャラの初期化)に問題があるのかと思ってMejed.cppを下のようにいじってみましたが結果は変わりませんでした。(これに伴ってほかのファイルでも渡す値や返す値を少しいじりました)

コード:

#include"DxLib.h"
#include"Medjed.h"
#include"CHECKKEY.h"

int Medjed::hx(){return x;}

int Medjed::hy(){return y;}

int Medjed::hd(){return d;}

Medjed::Medjed(int a, int b):CDSPACE(a, b){}

Medjed::Medjed():CDSPACE(){}

Medjed Medjed::intlz()
{
	Medjed md(290, 220);
	md.mh[0] = LoadGraph("画像\\md0.png"); md.mh[1] = LoadGraph("画像\\md1.png"); md.mh[2] = LoadGraph("画像\\md2.png"); md.mh[3] = LoadGraph("画像\\md3.png");
	return md;
}

bool Medjed::mcul(Medjed& md)
{
	CheckKey a;
	a.checkkey();
	if (a.key(KEY_INPUT_D)) {
		++md;
		md.d = 3;
	}if (a.key(KEY_INPUT_S)) {
		++md;
		md.d = 0;
	}if (a.key(KEY_INPUT_A)) {
		++md;
		md.d = 1;
	}if (a.key(KEY_INPUT_W)) {
		++md;
		md.d = 2;
	}
	if (md.x < 0)md.x=0;
	if (md.x > 593)md.x=593;
	if (md.y < 0)md.y = 0;
	if (md.y > 440)md.y = 440;
	if (a.key(KEY_INPUT_SPACE))
		return TRUE;
	return FALSE;
}

void Medjed::mdisp(Medjed md)
{
	for (int i = 0; i <= 3; ++i)
		if (md.d == i)DrawGraph(md.x, md.y, mh[i], TRUE);
}
/*
Medjed Medjed::hndm()
{
	return md;
}*/

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

Re: DxLibで作った以下のプログラム

#3

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

すごく問題の多いコードになってしまっています。
特に「やってはいけない処理」
https://dixq.net/g/h_11.html
を実装してしまっている箇所がいくつも見当たります。

まずは適切な設計で小さなプログラムを作ってみることをお勧めします。
https://dixq.net/g/
ここでゲームの簡単な設計方法について説明してあるので、一読されるとよいかと思います。

また、変数や関数の命名方法がよくないです。
パっと見て、何を意味するのか私にはわかりません。
一文字の変数名や短縮し過ぎて理解不能になった関数名はアンチパターンです。
Fpsクラスのように意味のある変数名にした方がいいでしょう。

このままだとスタート画面の真っ暗が解消されてもまた分からないことがでてきて何度も躓いてしまいそうです。
まず小さく綺麗に設計してみましょう。

アバター
shuka
記事: 5
登録日時: 5年前

Re: DxLibで作った以下のプログラム

#4

投稿記事 by shuka » 5年前

>>特に「やってはいけない処理」
>>https://dixq.net/g/h_11.html
>>を実装してしまっている箇所がいくつも見当たります。

どのあたりを指しているのでしょうか
裏画面処理は行っていると思います
メイン関数のループの中で初期化、計算描画を行っているつもりなのですが、、、
メニューとゲームの実装については確かにループを分けていますが、そこが問題になっているということでしょうか
してはいけないこと2,4についてはその関数を使っていないので1か3のことだとは思いますが

>>まずは適切な設計で小さなプログラムを作ってみることをお勧めします。
>>https://dixq.net/g/
>>ここでゲームの簡単な設計方法について説明してあるので、一読されるとよいかと思います。

そちらを参考に書いたクラスを一つだけ使ったプログラムがありまして、それをオブジェクトごとのクラスを実装してみようと思い今回のプログラムになってしまいました

>>また、変数や関数の命名方法がよくないです。
>>パっと見て、何を意味するのか私にはわかりません。
>>一文字の変数名や短縮し過ぎて理解不能になった関数名はアンチパターンです。
>>Fpsクラスのように意味のある変数名にした方がいいでしょう。

それは現在通っている学校の先生方からも言われましたので気を付けているつもりですがまだダメなのですね
気を付けます

にほ
記事: 17
登録日時: 6年前
連絡を取る:

Re: DxLibで作った以下のプログラム

#5

投稿記事 by にほ » 5年前

どのあたりを指しているのでしょうか
main.cppやmenu.cppに複数三大処理があるところでは?
メインとなるクラスにループ関数を作って、その中でだけ三大処理を呼ぶようにすればいいかと。条件分岐した先で呼ぶ必要はないはずです。

VisualStudioを使っているのであれば、問題ありそうなところにブレークポイントを設けてプログラムを一次止めながら問題を探すといいですよ。

アバター
shuka
記事: 5
登録日時: 5年前

Re: DxLibで作った以下のプログラム

#6

投稿記事 by shuka » 5年前

>>メインとなるクラスにループ関数を作って、その中でだけ三大処理を呼ぶようにすればいいかと。条件分岐し>>た先で呼ぶ必要はないはずです。

それを実現するにはどうすればいいのか考えてみたのですが、int MngFnctnのような変数を用意して(必要なら配列にして)それの値によって呼び出す関数を変えるように書けばよいということですか?

具体的に言うと
main.cpp

コード:

#include"DxLib.h"
#include"CHECKKEY.h"
#include"FpS.h"
#include"Medjed.h"
#include"Bullet.h"
#include"MENU.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	SetFullScreenResolutionMode(DX_FSRESOLUTIONMODE_DESKTOP);
	ChangeWindowMode(FALSE);
	if (DxLib_Init() == -1) return -1;
	SetDrawScreen(DX_SCREEN_BACK);
	CheckKey a; FpS fps; Medjed mjd = Medjed::intlz(); Bullet arbb; Menu item[3];
	Menu::MnIntlz(&item[0]);
	int col = GetColor(255, 255, 255), MngFnctn[2];
	const int time0 = GetNowCount();
	//int eh[3], ph = LoadGraph("画像\\キャラクタ01.png"), MN = 0,EoE[mxenmy];
	//CDSPACE plm(290, 220);
	//eh[0] = LoadGraph("画像\\enmy1.png"); eh[1] = LoadGraph("画像\\enmy1.png");	eh[2] = LoadGraph("画像\\enmy1.png");
	while (1)
	{
		if (MngFnctn[0] == -1)//configからメニュー画面に戻れるように設定できる
			MngFnctn[0] = item[0].slct(&item[0]);
		fps.Fpckg();
		a.checkkey();
		ClearDrawScreen();
		if (MngFnctn[0] == 0)
			DrawFormatString(100, 100, col, "準備中です\n(escキーを押してください)");
		else if (MngFnctn[0] == 1){
			if (mjd.mcul(mjd) == TRUE && MngFnctn[1] == 0)
				MngFnctn[1] = arbb.bcul(mjd);
			else MngFnctn[1] = 0;
			mjd.mdisp(mjd);
			arbb.bbhv();
			arbb.bdisp();
		}else if (MngFnctn[0] == 2)break;
		ScreenFlip();
		ProcessMessage();
		if (a.key(KEY_INPUT_ESCAPE))break;
	}
	DxLib::DxLib_End();
	return 0;
}
ということでしょうか

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

Re: DxLibで作った以下のプログラム

#7

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

https://dixq.net/g/
こちらの「メニュー画面の作り方」にそのすべてが書いてあるので一読いただければと思います。
C言語スタイルであれば変数を用いてスイッチします。
C++であればスイッチする必要すらありません。ポリモーフィズムを使って常に変数に対してUpdate、Drawするだけでよいです。
sp.3~sp.7に説明を書いています。

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

Re: DxLibで作った以下のプログラム

#8

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

>>また、変数や関数の命名方法がよくないです。
>>パっと見て、何を意味するのか私にはわかりません。
>>一文字の変数名や短縮し過ぎて理解不能になった関数名はアンチパターンです。

> それは現在通っている学校の先生方からも言われましたので気を付けているつもりですがまだダメなのですね。

気を付けているとのことですが
変数名にa,d,uなどの一文字が多いようです。
mcul()
hd()
等の関数は意味が分からないです。
mculはMedjedのCalculation的な意味でしょうか・・?
C++においてクラス名の一部をメソッド名に入れることは不要です。
また、「Calculation、Process、Check」のように具体的にそのメソッドで何をしているのかわかりにくい名前、コールした時何が返ってくるか返り値が予想できない名前もアンチパターンです。
あくまで一例ですが

コード:

if(container.isEmpty){
    enemy.add(bullet)
}
こんなコードだったとしましょう。
これを英語だと思って日本語に直訳したら意味の通る文章になると思いませんか?
ソースコードは日本語に直訳して物語になるようにコーディングしていくことを目指してみてください。

アバター
shuka
記事: 5
登録日時: 5年前

Re: DxLibで作った以下のプログラム

#9

投稿記事 by shuka » 5年前

Dixq (管理人) さんが書きました:
5年前
https://dixq.net/g/
こちらの「メニュー画面の作り方」にそのすべてが書いてあるので一読いただければと思います。
C言語スタイルであれば変数を用いてスイッチします。
C++であればスイッチする必要すらありません。ポリモーフィズムを使って常に変数に対してUpdate、Drawするだけでよいです。
sp.3~sp.7に説明を書いています。
なるほど、とても分かりやすいです、ありがとうございます。
Dixq (管理人) さんが書きました:
5年前
あくまで一例ですが

コード:

if(container.isEmpty){
    enemy.add(bullet)
}
こんなコードだったとしましょう。
これを英語だと思って日本語に直訳したら意味の通る文章になると思いませんか?
ソースコードは日本語に直訳して物語になるようにコーディングしていくことを目指してみてください。
こちらもとても参考になります。

教えていただいた内容をもとにプログラムを新規に組んでみようと思います。
そこで同様のバグが起こりましたら改めて質問させていただきます。

その際はトピックは新規で建てた方がよいのでしょうか

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

Re: DxLibで作った以下のプログラム

#10

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

はい、個別に新規作成していただいて構いません。

返信

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