一瞬で消えてしまいます

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

一瞬で消えてしまいます

#1

投稿記事 by zyf » 16年前

以前の投稿と同じような内容で申し訳ありません。
ショットを打たせることはできるようになったのですが、時期から発射された直後に消えてしまいます。
#include "DxLib.h"
 
typedef struct{//キャラクターの構造体
	int x,y,img;
}ch_t;

struct shot{//ショットの構造体
        int x,y;
        int flag;
};
 
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
        ChangeWindowMode( TRUE ) ;          // ウインドウモードに変更
        if( DxLib_Init() == -1 ) return -1; //DXライブラリ初期化 エラーが起きたら終了 
/////定義
        int na_shot[3],i,counter=0; //counter=発射してからのカウントをする変数。
		int nanoha0[1];
		int back0[1];
        char Key[256];
		ch_t ch;
        struct shot tama[20];               //tamaを10個作る。

		ch.x=132;
		ch.y=240;
 

 
        SetDrawScreen( DX_SCREEN_BACK ) ;//描画先を裏画面に設定
 
        LoadDivGraph( "na_shot.png" , 3 , 1 , 3 , 36 , 36 , na_shot ) ;//画像を分割してimage配列に保存
		LoadDivGraph( "nanoha00.png" , 1 , 1 , 1 , 64 , 64 , nanoha0 );//キャラクター
		LoadDivGraph( "back00.bmp" , 1 , 1 , 1 , 640 , 480 , back0 );//背景01




        while(1){
                ClearDrawScreen();                   //裏画面のデータを全て削除
                GetHitKeyStateAll( Key ) ;           // すべてのキーの状態を得る
 
                if( ProcessMessage() == -1 ) break ; //異常がおきたら終了
/////背景
		DrawGraph( 0 , 0 , back0[0] ,TRUE);


/////移動
		if(Key[KEY_INPUT_RIGHT]==1)//右
			ch.x+=2;
		if(Key[KEY_INPUT_LEFT]==1)//左
			ch.x-=2;
		if(Key[KEY_INPUT_UP]==1)//上
			ch.y-=2;
		if(Key[KEY_INPUT_DOWN]==1)//下
			ch.y+=2;
//移動の限界
		if(ch.x<-15)
			ch.x=-15;
		if(ch.y<-15)
			ch.y=-15;
		if(ch.x>620)
			ch.x=620;
		if(ch.y>450)
			ch.y=450;

		ch.img=nanoha0[0];

		DrawGraph(ch.x,ch.y,ch.img,TRUE);


/////ショット
        for(i=0;i<20;i++){                  //初期化処理
                tama.x=ch.x;
				tama.y=ch.y; //座標代入
                tama.flag=0;                 //飛んでいない事を示すフラグ=0
        }

                if(counter<5)                        //前にエンターを押してから5カウント未満なら
                        counter++;                       //カウントアップ
 
                else if( Key[ KEY_INPUT_Z ]  == 1 ){//5カウント以上たっていたら
                        counter=0;                       //カウンターを戻す
                        for(i=0;i<20;i++){             
                                if(tama.flag==0){     //発射していない玉を探し、
                                        tama.flag=1;  //発射フラグを立てる
                                        break;
                                }
                        }
                }
                for(i=0;i<20;i++){
                        if(tama.flag==1){              //発射している玉なら
                                tama.x+=5;             //座標を8増やす
                                DrawGraph( tama.x+18 , tama.y+18 , na_shot[0] , TRUE );//玉を描画
                                if(tama.x > 650){      //もし画面外まで来たら
									tama[i].x=ch.x;    //初期値に戻し、
									tama[i].x=ch.y;
                                        tama[i].flag=0;   //発射フラグを戻す
                                }
                        }
                }
/////////////////////////////////////////////////終了              
                if( Key[ KEY_INPUT_ESCAPE ]  == 1 ) break;//Escボタンが押されたらブレイク
 
                ScreenFlip() ;//裏画面データを表画面へ反映
        }
        DxLib_End() ;// DXライブラリ使用の終了処理
        return 0 ;// ソフトの終了
}

自分に力不足のため、原因がわかりませんでした。
わかる方いましたら、どうか教えてください。

noob

Re:一瞬で消えてしまいます

#2

投稿記事 by noob » 16年前

ショットの初期化処理をループからはずせばいいと思います。

kazuoni

Re:一瞬で消えてしまいます

#3

投稿記事 by kazuoni » 16年前

インデントが少しみにくいので、次からはプレビューで確認してから、
コードを載せるようにすると、他の方が見やすくなるかと思います。

>時期(自機)から発射された直後に消えてしまいます。

毎ループ初期化をしているので、
弾がDrawされた後、すぐ弾の存在フラグtama.flag=0;
としているので、消えてしまう(自らフラグを下げている)のではないかと。

zyf

Re:一瞬で消えてしまいます

#4

投稿記事 by zyf » 16年前

初期化処理の
flag=0;
をループから外すということは、
for(i=0;i<20;i++){ //初期化処理                 
                tama.x=ch.x;
        tama.y=ch.y; //座標代入
                tama.flag=0;//飛んでいない事を示すフラグ=0                 
        }

for(i=0;i<20;i++){//初期化処理
                tama.x=ch.x;
        tama.y=ch.y; //座標代入
        }
    tama.flag=0;

とすればいいということでしょうか?
こうすると、時期の位置がおかしくなってショットが表示されなくなるのですが何故でしょうか?

夢夢

Re:一瞬で消えてしまいます

#5

投稿記事 by 夢夢 » 16年前

whileの中で初期化処理を入れているので、
毎回初期化されることになってしまっています。
初期化処理をwhileの前に記述してください。

zwi

Re:一瞬で消えてしまいます

#6

投稿記事 by zwi » 16年前

C言語の理解が不十分なのだと思いますが、今後のためにも一文ごとの意味を理解してください。
for(i=0;i<20;i++){ //初期化処理                 
                tama.x=ch.x;
        tama.y=ch.y; //座標代入
                tama.flag=0;//飛んでいない事を示すフラグ=0                 
}

for(i=0;i<20;i++)で20個の弾を初期化します。
tama.x=ch.x;で弾のX座標を自キャラのX座標と一致させています。
tama.y=ch.y;で弾のY座標を自キャラのY座標と一致させています。
tama.flag=0;は弾の存在を消す(0)と言う意味です。
iは弾の番号ですね。

何が問題かというと弾の存在フラグやら座標を毎回初期化していたら弾はちゃんと飛んでくれません。
発射されてから消えるまでは独自に移動するのが弾ですから。
なので、弾の初期化はループに入る前の最初だけで良いとみなさんが言っているわけです。

もしちゃんと思うままに自分でゲームを作りたいなら、今は不十分な命令の一文毎の意味を自分で理解出来る必要があります。なぜwhileループの中に書くとだめなのか?ここでちゃんと理解せず言われたまま直すと後でまたつまずきますから、ここでしっかり理解してくださいね。
疑問があったら聞いてください。

zyf

Re:一瞬で消えてしまいます

#7

投稿記事 by zyf » 16年前

すみません。ショット部分はゲームプログラミングの館の26章を書き写しただけで、意味をよく理解していませんでした。
今のところやりたいことは、19章のキャラクターの移動と、26章のショットを組み合わせて、シューティングゲームの移動とショットを作るということです。

今のところ、移動の部分は理解できているので、ショットのところがよくわからないだけです。
玉の初期化、カウンター、打っていない玉を探す、のところがよくわからないので、どなたか詳しく教えていただけないでしょうか?

zwi

Re:一瞬で消えてしまいます

#8

投稿記事 by zwi » 16年前

じゃあ、細かい解説の前に気になる事があるので質問します。
・for文の使い方は理解されていますか?
・配列の添え字の意味を理解されていますか?
・先ほど書いた
for(i=0;i<20;i++){//初期化処理
              tama.x=ch.x;
       tama.y=ch.y; //座標代入
        }
    tama.flag=0;

でtama.flag=0;の代入文でiは何の値を指していますか?
そしてそのiの値には問題がありますが何でしょうか?

以上の理解度で、説明が変わってくるので答えをお待ちしています。

zyf

Re:一瞬で消えてしまいます

#9

投稿記事 by zyf » 16年前

返信が遅くなってすいません。

>・for文の使い方は理解されていますか?
>・配列の添え字の意味を理解されていますか?
全く理解していませんでした…

tama.flag=0;のiは、事前に作っておいたtama[20]のうちのどれかを指すと考えているのですがあっているでしょうか?
iの値の問題についてはこれもわかりません。

conio

Re:一瞬で消えてしまいます

#10

投稿記事 by conio » 16年前

>>tama.flag=0;のiは、事前に作っておいたtama[20]のうちのどれかを指すと考えているのですがあっているでしょうか?
違います。
ポインタではないので、"指す"という表現も適切ではないでしょう。
「iにどんな数値が入っているのか?」と考えたほうが良いと思います。

あと、for文の外に出したら 
構造体のメンバ"flag"が初期化されず不定値が入ることになりますよ。

--------------------------------------------------------
#include<stdio.h>
int main(void)
{
  int i;

  for(i=0;i<20;i++){
     printf("iの値は、%2dです。\n",i);
  }
  printf("for文から抜けました。iの値は%dです。\n",i);
  return(0);
}
--------------------------------------------------------
とりあえず、上記のコードを実行してiの値を確認してみてはどうでしょうか?
そして、そのiの値がどのような問題を発生させるなるのかを考えてみてください。
(コレ ⇒ tama.flag=0;)

zyf

Re:一瞬で消えてしまいます

#11

投稿記事 by zyf » 16年前

例となるプログラムまで書いてくださって本当にありがとうございます。
実行してみて、iの値は、0です。から、for文から抜けました。iの値は20です。という文字が表示されたということは、for(i=0;i<20;i++)というのは、iは最初は0で、それが20以下の間i++を実行し続けるといった感じでよいでしょうか?

そして、tama.flag=0;の問題は、20発の発射する玉を準備する段階で、発射フラグを0にしてしまっているということですか?

pooka

Re:一瞬で消えてしまいます

#12

投稿記事 by pooka » 16年前

>for(i=0;i<20;i++)というのは、iは最初は0で、それが20以下の間i++を実行し続けるといった感じでよいでしょうか?
一応こちらを参考に確認してみてください。
ttp://homepage3.nifty.com/mmgames/c_guide/09-02.html#S1

>そして、tama.flag=0;の問題は、20発の発射する玉を準備する段階で、発射フラグを0にしてしまっているということですか?
例えば
struct shot tama[20];
とすると、指定できる添え字は0~19までの20個です。
conioさんのプログラムを実行したということなので、for文から抜けたときiの値は20であるとわかると思います。
ここで
tama.flag=0;

tama[20].flag=0;
ということなので、範囲を超えて0を代入しようとしていることがわかると思います。

suzume

Re:一瞬で消えてしまいます

#13

投稿記事 by suzume » 16年前

noobさんの”ショットの初期化処理をループからはずせばいい”
というのは
for(i=0;i<20;i++){  //初期化処理
    tama.x=ch.x;
  tama.y=ch.y; //座標代入
    tama.flag=0; //飛んでいない事を示すフラグ=0
}

全部をwhileの上に持っていけばいいと言っているんだと思います。
tamaの座標も初期化処理ですから。

conio

Re:一瞬で消えてしまいます

#14

投稿記事 by conio » 16年前

>>for(i=0;i<20;i++)というのは、iは最初は0で、
それが20以下の間i++を実行し続けるといった感じでよいでしょうか?

厳密に言うと、20以下(0~20)ではなく20未満(0~19)です。
で、最後にiがインクリメントされた時、20<20となり、条件を満たさなくなるので
for文を抜けます。

ついでに、「iが20以下の場合実行する」という条件だとfor(i=0;i<=20;i++)となります。
(for文を抜けたときのiの値は21です。)


>>そして、tama.flag=0;の問題は、20発の発射する玉を準備する段階で、発射フラグを0にしてしまっているということですか?
違います。
メモリの概念は分かりますか?
PC上では、様々なデータを保存する場合などは当然「データを保存する領域」が必要となります。
プログラムでも同じことで、通常変数や配列などもメモリ上に配置されます。

で、とりあえず、配列の範囲外アクセスのプログラムを実行してみてください。
-----------------------------------------------------------------
#include<stdio.h>
int main(void)
{
	int test[3][3] = {0};
	int i, j;

	test[0][0] = 1;
	test[0][5] = 1;//範囲外アクセス!
	
	for(i = 0; i < 3; i++){
		for(j = 0; j < 3; j++){
			if(test[j] == 0)
				printf("○");
			else if(test[j] == 1)
				printf("●");
		}
		puts(" ");
	}
	return(0);
}
-----------------------------------------------------------------

実行結果は以下の通りになる筈です。
------------
●○○
○○●
○○○
------------

上記では、3×3の2次元配列を定義しているのですが、
test[0][5]に1を代入しています。

「この場合はどうなるのか?」というのは上記の実行結果を見ても分かるとおり、
test[1][2]の値が変更されてます。

何故、こんなことになるのかというと、
今回の2次元配列を定義した場合、メモリ上は下記の様に並んでいます。
-------------
┃test[0][0]
┃test[0][1]
┃test[0][2]
┃test[1][0]
┃test[1][1]
┃test[1][2]
┃test[2][0]
┃test[2][1]
▼test[2][2]
-------------
添え字に5としてしまうと、メモリ上で3つ余分に進んだ2次元配列"test"にアクセスすることになります。

-------------
┃test[0][0]
┃test[0][1]
┃test[0][2]
┃test[1][0]
┃test[1][1]
┃test[1][2] = test[0][5]
┃test[2][0]
┃test[2][1]
▼test[2][2]
-------------

で、今回はたまたま2次元配列の範囲内でしたが、もし「配列が存在しなかった場合はどうなるのか?」というと
------------
┃test[2][0]
┃test[2][1]
┃test[2][2]
▼????????? = test[2][3]
------------
全然関係の無い場所にアクセスすることになります。
当然、何らかの値を入れようとした場合は、その場所にあるデータが破壊されます。
特に影響は無いかもしれませんし、重要なデータが格納されていれば、PCの動作が不安定になったり
致命的なエラーが発生するかもしれません。

なので、添え字をオーバーした場所にアクセスするような事は起こらないようにして下さい。
(今回の場合は、tama[0]~tama[19]までしかないのに、tama[20]に値を入れてます。)

閉鎖

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