ページ 11

C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 00:44
by samusu0905
C/C++で縦スクロールゲームを作ってます。そこでですが、敵の数をループさせる処理をしたいのですが、
敵の数は複数発生してはいるものの、敵の数がループしてくれなくて困ってます。
ここにコードを載せます

コード:

//発生-------------------------------------------------------------------------------------
void EnemySet(void)
{
	int i;

	for(i=0; i<ENEMY1_MAX; i++)
	{
		//敵が存在していなければ
		if(gEnemy1[i].flg == OFF)
		{
			EnemySetOne(i);			//発生の実施を行う
		}
	}
}


//発生の実施--------------------------------------------------------------------------
void EnemySetOne(int i)
{
  for(i=0; i<ENEMY1_MAX; i++)
  {
	if(rand()%40 == 0)
	{
		gEnemy1[i].flg = ON;
		gEnemy1[i].y = 0;                           //Y座標を設定
		gEnemy1[i].x = rand()%GS_WINDOW_WIDTH;      //X座標を設定

		if( rand()%2 == 0)
		{
		gEnemy1[i].dir = 2;      //右向き
		}else
		{
		gEnemy1[i].dir = -2;    //左向き
		}
	}
  }
}
こんな感じのコードです。
付けたし・間違い等々あればよろしくお願いします。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 09:55
by softya(ソフト屋)
存在していなければとガードをしているにもかかわらずEnemySetOne()で無条件に全キャラを再発生させています。
これが原因ではないでしょうか?

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 10:34
by みけCAT
「敵の数をループさせる処理」とは、具体的にどのような処理でしょうか?

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 11:56
by samusu0905
敵を10体発生させた後、for文で敵の数10体を無限ループさせる処理です。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 11:58
by みけCAT
samusu0905 さんが書きました:敵を10体発生させた後、for文で敵の数10体を無限ループさせる処理です。
ごめんなさい。まだ私には意味がよくわかりません。
「敵の数を無限ループさせる」とはどういうことですか?

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 12:03
by samusu0905
プログラムに間違いがあれば、正しいプログラムを書いていただくとありがたいです。
お願いします。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 12:06
by みけCAT
samusu0905 さんが書きました:プログラムに間違いがあれば、正しいプログラムを書いていただくとありがたいです。
お願いします。
提示されている範囲では定義されていない変数や定数がある以外、文法エラーは無さそうです。
仕様がわからなければ、「間違いがある」かどうかは判定できません。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 12:14
by Ryo
18行目で、iを引数にして値をもらっているのに
20行目でi=0としているのは、何を意図しているのでしょうか?

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 12:26
by samusu0905
敵の数を無限ループさせるのですから、敵の数を無限に発生させるということです。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 12:36
by samusu0905
ああ、EnemySetOne(int i)
for(i=0; i<ENEMY1_MAX; i++)
ここの部分ですか?
ここはただの間違いだと思います。
さっき、直しました。
直したコード載せます。

コード:

//発生-------------------------------------------------------------------------------------
void EnemySet(void)
{
	int i;

	for(i=0; i<ENEMY1_MAX; i++)
	{
		if(gEnemy1[i].flg == OFF)
		{
			EnemySetOne(i);			//発生の実施を行う
		}
	}
}


//発生の実施--------------------------------------------------------------------------
void EnemySetOne(int i)
{
	if(rand()%50 == 0)
	{
		gEnemy1[i].flg = ON;
		gEnemy1[i].y = GS_WINDOW_HEIGHT;            //Y座標を設定
		gEnemy1[i].y = rand()%-1;
		gEnemy1[i].x = rand()%GS_WINDOW_WIDTH;      //X座標を設定

		if( rand()%2 == 0)
		{
		gEnemy1[i].dir = 2;      //右向き
		}
		else
		{
		gEnemy1[i].dir = -2;    //左向き
		}
	}
}
[code]

修正しました。敵は複数発生しますが、ループして発生してくれないんです。
多分自分でもどこか間違いがあると思いますが、色々とやっても中々思いつきませんでした;;

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 12:42
by みけCAT
このコードの中には「10体」という条件は含まれていませんね。
EnemySetをどのようなタイミングで呼んでいるかもわからないですが、
まずこれを「敵をn体発生させる」という処理に書き換えますか?

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 12:44
by samusu0905
はい、お願いします。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 12:46
by みけCAT
1. 空いている(gEnemy1.flg == OFFである)添字iのリスト(配列)を作る
2-1. 空いている添字がn個以下なら、それら全てに対して敵を発生させる
2-2. 空いている添字がn個を超えるなら、1で作ったリストをシャッフルして、最初のn個の添字に対して敵を発生させる
という方針でいいと思います。
そのために、EnemySetOneを呼んだら必ず敵が発生するようにしましょう。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 12:52
by みけCAT
書いてみました。
よく考えたら、シャッフルしなくてもいいかもしれませんね。

コード:

//発生-------------------------------------------------------------------------------------
void EnemySet(int n)
{
	int i;
	int emptyIndexList[ENEMY1_MAX];
	int emptyIndexCount=0;

	for(i=0; i<ENEMY1_MAX; i++)
	{
		if(gEnemy1[i].flg == OFF)
		{
			enptyIndexList[emptyIndexCount++]=i; //空きの場所を登録する
		}
	}
	if(emptyIndexCount<=n)
	{
		n=emptyIndexCount;
	}
	else
	{
		//シャッフルを行う
		for(i=emptyIndexCount-1; i>0; i--)
		{
			int pos=rand()%(i+1);
			int tmp=emptyIndexList[i];
			emptyIndexList[i]=emptyIndexList[pos];
			emptyIndexList[pos]=tmp;
		}
	}
	for(i=0; i<n; i++)
	{
		EnemySetOne(emptyIndexList[i]); //発生の実施を行う
	}
}


//発生の実施--------------------------------------------------------------------------
void EnemySetOne(int i)
{
	gEnemy1[i].flg = ON;
	gEnemy1[i].y = GS_WINDOW_HEIGHT; //Y座標を設定
	gEnemy1[i].y = rand()%-1;
	gEnemy1[i].x = rand()%GS_WINDOW_WIDTH; //X座標を設定

	if( rand()%2 == 0)
	{
		gEnemy1[i].dir = 2; //右向き
	}
	else
	{
		gEnemy1[i].dir = -2; //左向き
	}
}

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 12:56
by N.R
想像するなら
EnemySet() を毎フレーム呼んで敵が死ぬとすぐに発生するようにしているのを「敵の数を無限に発生」と言っているのではないでしょうか

if( rand()%50 == 0 )
の意図がいまひとつ分かりませんが
いきなり再生するのもなんなので、少し時間が空くのを期待した処理という所でしょうか

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 13:56
by samusu0905
上記のプログラムを参考に書きましたが、正常に動いたと思ったら、プレイ画面でエラーがでました。
敵は発生したものの、プレイ画面に移動して直ぐにゲームが止まってしまいました;;
ENEMY1_MAXなんですが、このプログラムで、この関数は敵の数が10体定義されています。
ですから、int nは定義不要だと思います。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 14:18
by みけCAT
samusu0905 さんが書きました:上記のプログラムを参考に書きましたが、正常に動いたと思ったら、プレイ画面でエラーがでました。
敵は発生したものの、プレイ画面に移動して直ぐにゲームが止まってしまいました;;
テストしていないので、自分のプログラムにバグがあったかもしれません。
…と思ったら、「参考に書きました」ですか。では、そのプログラムを貼っていただけますか?
samusu0905 さんが書きました:ENEMY1_MAXなんですが、このプログラムで、この関数は敵の数が10体定義されています。
ですから、int nは定義不要だと思います。
では、「EnemySet関数を呼んだら必ず発生させられるだけ敵を発生させる」という仕様でいいですか?

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 14:41
by samusu0905
はい、それで構いません。お願いします。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 14:54
by samusu0905
さっきのプログラムですが、参考と言ってもほとんど同じように書いて、少し変えて書き込んだだけです。
変えた場所は、 int nとなっているところをvoidのままにして、nを使っているところをENMEY1_MAXに変えたりした
だけです。n個って言いましたよね?あれはこのプログラムでは多分不要かと思います。さっきまでの文章にも書きましたが、ENEMY1_MAXが敵の数が10体であることを他のヘッダファイルで定義されているので、
nは書かなくても問題ないかと思います。色々と世話を焼かせて申し訳ございません。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 14:58
by みけCAT
では、とりあえずシンプルにこれでいいと思います。

コード:

//発生-------------------------------------------------------------------------------------
void EnemySet(void)
{
	int i;

	for(i=0; i<ENEMY1_MAX; i++)
	{
		if(gEnemy1[i].flg == OFF)
		{
			EnemySetOne(i); //発生の実施を行う
		}
	}
}


//発生の実施--------------------------------------------------------------------------
void EnemySetOne(int i)
{
	gEnemy1[i].flg = ON;
	gEnemy1[i].y = 0; //Y座標を設定
	gEnemy1[i].x = rand()%GS_WINDOW_WIDTH; //X座標を設定

	if( rand()%2 == 0)
	{
		gEnemy1[i].dir = 2; //右向き
	}
	else
	{
		gEnemy1[i].dir = -2; //左向き
	}
}

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 15:10
by samusu0905
[EnemySet関数を呼んだら必ず発生させられるだけ敵を発生させ、敵の数の分だけループさせる]という処理にできればしてもらえませんか? [敵の数の分だけループさせる]ということですから、敵10体をループして発生させるという処理をできればお願いします。わがまま言ってすみません。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 15:42
by samusu0905
上記のプログラムは以前、僕が書いたプログラムと同じですよ。結果は発生してもループしませんでした。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 16:01
by usao
No20のコードにはとりあえずループが存在しているわけですが,それに対して
>ループしませんでした
とのことですから,
あなたの言う「ループ」とは,それとはまったく違うものであるということですよね.
だとしたら,(最初に説明を求められて,うやむやになってる感のある)
>敵の数をループ
という言葉の真の意味が,おそらく誰にも伝わってないものと推測します.

まず,自分にしか通じない言葉を繰り返すのをやめて
まともな日本語で説明するところから初めてみてはいかがでしょうか.
「数をループ」とは何か,
一体あなたは何を観測して「ループしていない」と言っているのか,
全体として何をしたいのか.

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 16:12
by みけCAT
EnemySetを呼んでいる部分のソースコードは提示できますか?
可能であれば提示していただけるとありがたいです。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 16:17
by samusu0905
敵10体を単純に無限ループさせたいだけです。[ループしていない]というのは、つまり敵が10体発生していて、
それがfor文によってループされていないということです。 まともな日本語で説明できていなくてすみませんでした。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 16:23
by samusu0905

コード:

//メイン処理-------------------------------------------------------------------------
void GamePlayMain(void)
{
	//各ファイルのメイン処理
	DragonMain();
	FireMain();
	EnemyMain();
	CollisionMain();


	if( gDragonLife.HP <= 0)
	{
		gSceneMode = MODE_GAMEOVER;
		gsStopSound( sGamePlayBGM1);
		return;
	}
}
[code]
ここで呼んでいます。ゲームプレイのコードの部分です。

そして先ほどのコードがこれです。一応、敵のソースコードを全部提示します↓ 
そうすればわかりやすいですか?
[code]
//*******************************************************************
//  敵処理
//*******************************************************************
#include <stdio.h>			//C言語
#include "gs.h"				//学内ライブラリィ
#include "def.h"			//共通定義
#include "Enemy.h"			//敵


//宣言--------------------------------------------
OBJ  gEnemy1[ENEMY1_MAX];				//敵1の構造体

//参照--------------------------------------------
extern gsTexture sEnemy1;	//敵
extern int gScore;			//スコア


//開始-----------------------------------------------------------------------------
void EnemyStart(void)
{
	int i;

	//敵の数ループ
	for(i=0; i<ENEMY1_MAX; i++)
	{
		gEnemy1[i].flg = OFF;			//存在しない(初期設定)
	}
}


//メイン処理------------------------------------------------------------------------
void EnemyMain(void)
{
	EnemySet();					//発生
	EnemyMove();				//移動
	EnemyInScreen();			//移動範囲の制限
}


//表示------------------------------------------------------------------------------------
void EnemyDraw(void)
{
	int i;

	//敵の数ループ
	for(i=0; i<ENEMY1_MAX; i++)
	{
		//存在すれば
		if( gEnemy1[i].flg == ON)
		{
			gsDraw2D( sEnemy1, gEnemy1[i].x, gEnemy1[i].y );			//敵
		}
	}
}


//発生-------------------------------------------------------------------------------------
void EnemySet(void)
{
	int i;

	for(i=0; i<ENEMY1_MAX; i++)
	{
		//敵が存在していなければ
		if(gEnemy1[i].flg == OFF)
		{
			gEnemy1[i].flg = ON;
			
			EnemySetOne(i);			//発生の実施を行う
		}
	}
}


//発生の実施--------------------------------------------------------------------------
void EnemySetOne(int i)
{
	if(rand()%50 == 0)
	{
		gEnemy1[i].flg = ON;
		gEnemy1[i].y = GS_WINDOW_HEIGHT;            //Y座標を設定
		gEnemy1[i].y = rand()%-1;
		gEnemy1[i].x = rand()%GS_WINDOW_WIDTH;      //X座標を設定
	}


	if( rand()%2 == 0)
	{
		gEnemy1[i].dir = 2;      //右向き
	}
	else
	{
		gEnemy1[i].dir = -2;    //左向き
	}
}


//移動--------------------------------------------------------------------------------
void EnemyMove(void)
{
	int i;

	//敵1の数ループ
	for(i=0; i<ENEMY1_MAX; i++)
	{
		if( gEnemy1[i].flg == ON)
		{
			gEnemy1[i].y += 2;							//下に移動
			if( gEnemy1[i].y >= 350)
			{
				gEnemy1[i].x += gEnemy1[i].dir;			//左右に移動
			}
		}
	}
}


//移動範囲の制限----------------------------------------------------------------------------
void EnemyInScreen(void)
{
	int i;

	//敵1の数ループ
	for(i=0; i<ENEMY1_MAX; i++)
	{
		//存在すれば
		if( gEnemy1[i].flg == ON)
		{
			EnemyInScreenOne(i);		//移動範囲の制限の実施
		}
	}
}


//移動範囲の制限の実施----------------------------------------------------------------------
void EnemyInScreenOne(int i)
{
	if( gEnemy1[i].flg == ON)
	{
		//下向き
		if(gEnemy1[i].y < -ENEMY1_YSIZE)
		{
			gEnemy1[i].flg = OFF;		//存在しなくする
		}

		//右向き
		if( gEnemy1[i].x < 20)
		{
			gEnemy1[i].dir = 3;
		}

		//左向き
		if( gEnemy1[i].x > 330)
		{
			gEnemy1[i].dir = -3;
		}

	}
}
[code]
長いですが、こんな感じです。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 16:29
by samusu0905
インデントがわかりずらいですね;; 見えずらくてすみません。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 16:29
by みけCAT
samusu0905 さんが書きました:敵10体を単純に無限ループさせたいだけです。[ループしていない]というのは、つまり敵が10体発生していて、
それがfor文によってループされていないということです。 まともな日本語で説明できていなくてすみませんでした。
「敵の数を無限ループさせたい」から「敵を無限ループさせたい」に言い直されたようですが、
申し訳ありませんがまだ私には理解できません。
こんな感じでしょうか?

コード:

//メイン処理------------------------------------------------------------------------
void EnemyMain(void)
{
	for(;;){
		EnemySet();					//発生
		EnemyMove();				//移動
		EnemyInScreen();			//移動範囲の制限
	}
}

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 16:30
by みけCAT
samusu0905 さんが書きました:インデントがわかりずらいですね;; 見えずらくてすみません。
インデント自体はわかりやすいので、BBcodeを有効にした状態できちんとcodeタグで囲んでください。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 16:33
by samusu0905
[敵10体を無限に発生させたい]とでも言えばわかりますか?

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 16:37
by hide
samusu0905 さんが書きました:敵10体を単純に無限ループさせたいだけです。[ループしていない]というのは、つまり敵が10体発生していて、
それがfor文によってループされていないということです。 まともな日本語で説明できていなくてすみませんでした。
○○をループする と書くときは大抵○○には何らかの処理が入るはずだと思います。
例 変数aに1を足す処理をループする。
で、敵という単語は処理では無いので、敵をループでは伝わらないのですよ。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 16:39
by みけCAT
samusu0905 さんが書きました:[敵10体を無限に発生させたい]とでも言えばわかりますか?
わかった気がします。
EnemyInScreenOne関数、141行目の条件式が怪しいと思います。
他に敵の消滅条件が無ければ、敵は(gEnemy1.yの型によって、事実上または本当に)消滅することはありません。

ENEMY1_YSIZEが正の整数であると仮定した場合、
事実上:gEnemy1.yの型が例えばintの場合、オーバーフローして負の値になれば消滅します。
本当に:gEnemy1.yの型が例えばunsigned intの場合、gEnemy1.yは常に0以上なので消滅することはありません。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 16:52
by N.R
要約すると

画面上に敵が最大10体まで発生する
敵が画面外に出ると消滅
消滅した敵はすぐに再発生する
という仕様で

結果は
敵が再発生せず
最初に発生させた10体が消滅すると全ていなくなってしまう <- 敵がループしない

という事ですかね

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 17:18
by samusu0905
はい、そのとおりです。
説明不足で本当にすみませんでした。
もっとちゃんとした説明をします。
N.Rさんの言うとおりです。画面上に敵が最大10体まで発生して、敵が画面の下に移動して画面から消滅したらまた画面上から発生する処理がしたかったんです。
あれですかね、やはり移動範囲が可笑しかったですかね?

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 17:33
by みけCAT
予想ですが、

コード:

		if(gEnemy1[i].y < -ENEMY1_YSIZE)
という行(141行目)を、

コード:

		if(gEnemy1[i].y > GS_WINDOW_HEIGHT+ENEMY1_YSIZE)
としてみてください。

Re: C/C++縦スクロールゲーム

Posted: 2014年3月20日(木) 17:39
by samusu0905
移動範囲の制限実施のところを自分なりに工夫したらループできました!!
色々と教えていただき有難うございました^^
これからはもっと説明を分かりやすくします。