ページ 11

弾の発射位置に魔法陣を描画したい

Posted: 2014年10月26日(日) 11:43
by 青成
こんばんは、私は龍神録プログラミングの館でプログラミングの勉強をさせて頂いている者です。
現在、妖夢の通常弾幕を説明してる15章を拝見させて頂いてます。
そこで永夜抄のように弾の発射位置(発射源)に魔法陣を描画したいのですが、どのようにすればよいでしょうか?
この場合、弾が発射されるタイミングだけ描画されるのではなく常に表示されるようにしたいです。
自分の方でも考えてみたのですが、上手くいきませんでした。

shotH.cpp(値は多少変えてます)

コード:

void shot_bullet_H007(int n){
	
		
        int t=shot[n].cnt;
        int k;

		
	
	    if(t>=0 && t<=500 && t%15==0){

                for(int i=0;i<10;i++){
                        if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
							 
                                shot[n].bullet[k].knd   =8;
                                shot[n].bullet[k].angle =PI2/20*i;
                                shot[n].bullet[k].flag  =1;
                                shot[n].bullet[k].x     =enemy[shot[n].num].x+cos(PI/2+PI/100*t)*100;
                                shot[n].bullet[k].y     =enemy[shot[n].num].y+sin(PI/2+PI/200*t)*100;
                                shot[n].bullet[k].col   =2;
                                shot[n].bullet[k].cnt   =0;
                                shot[n].bullet[k].spd   =1.2;
				se_flag[0]=1;
	        DrawRotaGraph(shot[n].bullet[k].x,shot[n].bullet[k].y,1.0f,0.0,shotE,TRUE);   //shotEは魔法陣の画像が入ってるハンドル			
							
						}
                }
                for(int i=0;i<10;i++){
                        if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
                                shot[n].bullet[k].knd   =8;
                                shot[n].bullet[k].angle =PI2/20*i;
                                shot[n].bullet[k].flag  =1;
                                shot[n].bullet[k].x     =enemy[shot[n].num].x+cos(PI/2-PI/100*t)*100;
                                shot[n].bullet[k].y     =enemy[shot[n].num].y+sin(PI/2-PI/200*t)*100;
                                shot[n].bullet[k].col   =4;
                                shot[n].bullet[k].cnt   =0;
                                shot[n].bullet[k].spd   =1.2;
                                se_flag[0]=1;
              
						
								
                        }
					
                }
        }
実行した結果魔法陣が描画されませんでした。
たとえ描画されたとしてもt%15となっているので常に表示されないとは思いますが・・・
またこれだと魔法陣も弾の軌道と同じように飛んでいきそうです。

自分一人では解決できそうになかったので質問させていただきました。よろしくお願いします。

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年10月26日(日) 12:24
by Tatu
魔法陣を「魔法陣の画像を用いる弾」として考えてみてはどうでしょうか。

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年10月26日(日) 12:29
by 顔芸
魔方陣自体は当たり判定を持たず,前進もしないと思うのでそもそも弾として扱わないほうがいいと思います.
自分だったらプレイヤー,敵,弾といったオブジェクトと同列に"エフェクト"オブジェクトを定義します.

敵が弾を発射するということは,何らかのタイミングで敵の位置情報等を用いて弾オブジェクトを設置するという
ことですが,このタイミングで同時にエフェクトオブジェクト,つまり魔方陣も設置します.

エフェクトオブジェクトには位置情報と生存期間を持たせます.

位置情報は,エフェクトの設置時に,設置時の位置(敵が発射するならその時の敵の位置)で初期化しておきます.
位置情報を毎フレーム更新する必要はありません(魔方陣を動かしたいなら更新すればいいです).

生存期間は,エフェクトの設置時に,エフェクトの生存期間を適当な値(例えば500フレーム)で初期化しておきます.
あとはエフェクトの生存期間を毎フレームデクリメントして,0になったときに消去するといった実装が考えられそうです.

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年10月26日(日) 13:31
by 青成
皆様返信ありがとうございます。
というかそもそもグラフィック関数を書く場所を間違えてましたね^^;
書く場所はgraph.cppでした。

コード:

void graph_bullet(){
        int i,j;
        SetDrawMode( DX_DRAWMODE_BILINEAR ) ;//線形補完描画
        for(i=0;i<SHOT_MAX;i++){//敵の弾幕数分ループ
                if(shot[i].flag>0){//弾幕データがオンなら
                        for(j=0;j<SHOT_BULLET_MAX;j++){//その弾幕が持つ弾の最大数分ループ
                                if(shot[i].bullet[j].flag!=0){//弾データがオンなら
                                        if(shot[i].bullet[j].eff==1)
                                                SetDrawBlendMode( DX_BLENDMODE_ADD, 255) ;
										
					DrawRotaGraph(enemy[shot[i].num].x+FIELD_X,enemy[shot[i].num].y+FIELD_Y,1.0f,0.0,shotE,TRUE);
                                        DrawRotaGraphF(
                                                shot[i].bullet[j].x+FIELD_X, shot[i].bullet[j].y+FIELD_Y,
                                                1.0, shot[i].bullet[j].angle+PI/2,
                                                img_bullet[shot[i].bullet[j].knd][shot[i].bullet[j].col],TRUE);

                                        if(shot[i].bullet[j].eff==1)
                                                SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0) ;
                                }
                        }
                }
        }
        SetDrawMode(DX_DRAWMODE_NEAREST);//描画形式を戻す
}
これで敵の位置を取得する事はできましたが、今回弾の発射源は敵の位置ではないので別の場所を発射源とする必要があります・・・
またDrawRotaGraphの第一引数と第二引数を shot[n].bullet[k].x、 shot[n].bullet[k].yとしてみましたが魔法陣が弾と同じ軌道で飛んでいきました。
理想は
画像
のような軌道に沿って魔法陣を動かしたいです。
今回の弾の発射源の取得はshot[n].bullet[k].x、 shot[n].bullet[k].yとしていましたが、弾の動きと同じになってしまいました。
画像のような動きにするにはどうすればよいでしょうか?

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年10月26日(日) 16:23
by 顔芸
画像が見えないのは自分の環境だけだろうか・・
ローカルのパスを貼ったりしてませんか?

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年10月26日(日) 16:29
by 青成
あら、私は表示されていますが・・・
直リン貼ります。
画像

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年10月26日(日) 17:30
by 顔芸
見えました,というか右クリから飛べば開けました.お騒がせしました;

エフェクトの動きを弾の動きと分離したいならやはり別のオブジェクトとして扱うのが自然でしょう.
弾オブジェクトにエフェクトの座標まで持たせるのは不自然です.

見たところ楕円軌道ですかね?
となると楕円の媒介変数表示が使えそうです.

x = a * cos(t)
y = b * sin(t)
(0 ≤ t < 2π)

(x, y)はエフェクトの座標です.
tは三角関数の位相で,実際には適当にスケールされたフレームカウントです.
つまり楕円軌道上に,フレームカウントに連動して点をプロットしていくイメージです.
a, bは長辺と短辺の長さになるので好きなバランスで値を指定して下さい.

縦長の楕円の下端からエフェクトの移動を開始するなら,三角関数の初期位相に
注意して下さい.実際に動かしてないので定かではないですが多分初期位相は
t = (3 / 2)πです.

それと,エフェクトが二手に分かれているのでtの更新の仕方を少し工夫しないと
いけませんね.

一旦切ります.

参考URL
http://ja.wikipedia.org/wiki/%E6%A5%95%E5%86%86

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年10月27日(月) 23:31
by Tatu
[youtube][/youtube]
この動画の大弾の画像を魔法陣に差し替えたようなものを作りたいという事でいいでしょうか?

それならば魔法陣の画像を持つ弾の動きを先に作り
その弾の位置から弾を発射させるようにすればいいとおもいます

16章「ミシャグジさま弾幕を作ってみよう」に
stateによって弾の回転する方向を変える例がありますが

今回の場合、画像が魔法陣でstateがそれぞれ1と2である2つの弾を最初に発生させる
そして、全ての弾を調べて
flagが0でなく、かつstateが1の弾があればその弾は時計回りに動き、その弾の位置から弾を撃つ
flagが0でなく、かつstateが2の弾があればその弾は反時計回りに動き、その弾の位置から弾を撃つ
というようにしてはどうでしょうか

弾用の構造体と別に魔法陣用の構造体を作るかはその後で考えてもよいでしょう。

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年10月31日(金) 02:31
by 青成
返信が遅れて申し訳ございません。

顔芸さんの意見を参考に楕円の描画の仕組みは分かりましたが、既存のプログラムの発射位置に上手くそれを配置することはできなかったです。
示したソースコードの値を利用する、という方法であれば・・・
三角関数は学校で習いたてだったので理解を深める事ができました。ありがとうございます。

>>Tatuさん
そうです、そのような感じです。
言い忘れていましたが、魔法陣という事ですが画像の回転はしないものとします。
「魔法陣の画像を用いる弾」との考えで組ませて頂きました。
ステータスを他の弾と同様にして、スピードをゼロ、(t%15==0)の範囲外にしてやってみた結果、

コード:

 if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
							
                                shot[n].bullet[k].knd   =10; //魔法陣
                                shot[n].bullet[k].angle =PI2;
                                shot[n].bullet[k].flag  =1;
                                shot[n].bullet[k].x     =enemy[shot[n].num].x+cos(PI/2+PI/100*t)*100;
                                shot[n].bullet[k].y     =enemy[shot[n].num].y+sin(PI/2+PI/200*t)*100;
                                shot[n].bullet[k].col   =0;
                                shot[n].bullet[k].cnt   =0;
                                shot[n].bullet[k].spd   =0;
								shot[n].bullet[k].till  =100;  // ここに入れるとは・・・?
								se_flag[0]=1;
							
								
							
						}
のようになり弾の発射位置にshot[n].bullet[k].knd =10(魔法陣のグラフィック)を描画することができましたが、前描いたグラフィックがずっと残ったままです。
2つ以上描画した画像が残らないようにしたい(もしくはフレーム数によって画像を消去)です。
講座を見ると、shot[n].bullet[k].till というステータスがあり、「少なくとも消さない時間」となっています。
それでshot[n].bullet[k].tillに色んな数値を入れてみましたが魔法陣の画像は消えませんでした。
どのようにしてなめらかに移動してるように見せることができるのでしょうか?
またshot[n].bullet[k].tillはどのような時に使うのでしょう?

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年10月31日(金) 20:59
by Tatu
tillは画面外に出ても弾が消えない時間を表しています。
画面外から弾を出す弾幕などに使えます。


動画の弾幕については
「毎フレーム弾の発射位置で魔法陣を発生・消去をする」という考えではなく、
「魔法陣は最初に1度だけ発生させ、魔法陣の位置から弾を発射する」という考えで作成しました。

以下のように考えてみてはどうでしょうか

(1)時計回りの動きをする魔法陣のみを考える

(1)-1 最初のフレームで魔法陣の弾を発生させます。

(1)-2 全ての弾を調べ、flagが1である弾があったら時計回りに動くというように書きます
動かす時はshot[n].bullet[k].x =enemy[shot[n].num].x+cos(PI/2+PI/100*t)*100;
のように代入すればいいです。

(1)-3 弾が上に来る時にflagを0にし、弾を消去するようにします。


(2)それぞれ時計回り、反時計回りに動く2つの魔法陣を考える

(2)-1 最初のフレームでstateが1の魔法陣の弾、stateが2の魔法陣の弾を発生させます。
stateが異なるのはそれぞれの弾の動きを変えられるようにするためです。

(2)-2 全ての弾を調べ、flagが1でかつstateが1である弾があったら
時計回りに動き、上に来る時に弾を消去するようにします。

(2)-3 全ての弾を調べ、flagが1でかつstateが2である弾があったら
反時計回りに動き、上に来る時に弾を消去するようにします。


(3)2つの魔法陣から弾を発射するようにする

(2)のコードに対し、(2)-2と(2)-3のそれぞれの処理に魔法陣が弾を撃つ時間ならば
魔法陣の位置から弾を発射するという処理を追加します。
発射する弾のstateは魔法陣とは違う値にしてください。

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年11月04日(火) 01:22
by 青成
うおお!できました!ありがとうございます!

コード:

if( t == 0){
			 if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
							
                                shot[n].bullet[k].knd   =10;
                                shot[n].bullet[k].angle =PI2;
                                shot[n].bullet[k].flag  =1;
                                shot[n].bullet[k].x     =enemy[shot[n].num].x+cos(PI/2+PI/100)*100;
                                shot[n].bullet[k].y     =enemy[shot[n].num].y+sin(PI/2+PI/200)*100;
                                shot[n].bullet[k].col   =0;
                                shot[n].bullet[k].cnt   =0;
                                shot[n].bullet[k].spd   =0;
			        shot[n].bullet[k].state  =1;
								
							
								
							
						}
		}

		 for(int i=0;i<SHOT_BULLET_MAX;i++){
        if(shot[n].bullet[i].flag>0 && shot[n].bullet[i].state == 1 ){
             shot[n].bullet[i].x     =enemy[shot[n].num].x+cos(PI/2+PI/100*t)*100;
             shot[n].bullet[i].y     =enemy[shot[n].num].y+sin(PI/2+PI/200*t)*100;
              
            }
        
    }


	
	    if(t>=0 && t<=500 && t % 15 == 0){

			

			for(int i=0;i<13;i++){
                        if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
							
                                shot[n].bullet[k].knd   =8;
                                shot[n].bullet[k].angle =PI2/20*i;
                                shot[n].bullet[k].flag  =1;
                                shot[n].bullet[k].x     =enemy[shot[n].num].x+cos(PI/2+PI/100*t)*100;
                                shot[n].bullet[k].y     =enemy[shot[n].num].y+sin(PI/2+PI/200*t)*100;
                                shot[n].bullet[k].col   =0;
                                shot[n].bullet[k].cnt   =0;
                                shot[n].bullet[k].spd   =1.2;
								se_flag[0]=1;
							
								
							
						}
                }
                for(int i=0;i<13;i++){
                        if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
                                shot[n].bullet[k].knd   =8;
                                shot[n].bullet[k].angle =PI2/20*i;
                                shot[n].bullet[k].flag  =1;
                                shot[n].bullet[k].x     =enemy[shot[n].num].x+cos(PI/2-PI/100*t)*100;
                                shot[n].bullet[k].y     =enemy[shot[n].num].y+sin(PI/2-PI/200*t)*100;
                                shot[n].bullet[k].col   =4;
                                shot[n].bullet[k].cnt   =0;
                                shot[n].bullet[k].spd   =1.2;
                                se_flag[0]=1;
						
								
                        }
					
                }
        }
	
今回僕が作ってるのは弾が絶え間なく発射されるものですので魔法陣を消す処理はしていません。
この調子でもう片方も作ってみます。ありがとうございました。

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年11月04日(火) 07:19
by Tatu
魔法陣の位置から発射するというのは無視したんですね。
解決したのならいいですが。

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年11月05日(水) 19:49
by 青成
結果的に魔法陣の位置から弾が発射されていますが何か不備がありますかね・・・?

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年11月05日(水) 20:50
by Tatu
今回の弾幕ならば問題はないでしょう。

では、以下の動画のように乱数を用いて弾を発射し、
発射された弾の位置から自機狙いの弾を発射させるような弾幕ではどうでしょうか?
[youtube][/youtube]

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年11月05日(水) 23:50
by 青成
なるほど、今回のように軌道が決まっていれば問題ないが乱数を発生させるとなると魔法陣の軌道と弾の発射される位置がズレるということですか。

自分の求めている結果が得られましたので解決済みとしていますが今後このような弾幕を作る機会があるかもしれないのでもう暫くお付き合い頂けると嬉しいです。

コード:

       if(t>=0 && t<=500){
	         if( t == 0){
			 if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
							
                                shot[n].bullet[k].knd   =10;
                                shot[n].bullet[k].angle =PI2;
                                shot[n].bullet[k].flag  =1;
                                shot[n].bullet[k].x     =enemy[shot[n].num].x+cos(PI/2+PI/100)*100;
                                shot[n].bullet[k].y     =enemy[shot[n].num].y+sin(PI/2+PI/200)*100;
                                shot[n].bullet[k].col   =0;
                                shot[n].bullet[k].cnt   =0;
                                shot[n].bullet[k].spd   =0;
			     shot[n].bullet[k].state  =1;
							}

			 if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
							
                                shot[n].bullet[k].knd   =10;
                                shot[n].bullet[k].angle =PI2;
                                shot[n].bullet[k].flag  =1;
                                shot[n].bullet[k].x     =enemy[shot[n].num].x+cos(PI/2+PI/100)*100;
                                shot[n].bullet[k].y     =enemy[shot[n].num].y+sin(PI/2+PI/200)*100;
                                shot[n].bullet[k].col   =1;
                                shot[n].bullet[k].cnt   =0;
                                shot[n].bullet[k].spd   =0;
			    shot[n].bullet[k].state  =2;
								
							
			 }	
							
						
		}

		 for(int i=0;i<SHOT_BULLET_MAX;i++){//全弾分
        if(shot[n].bullet[i].flag>0 && shot[n].bullet[i].state == 1){//登録されている弾があれば
             shot[n].bullet[i].x     =enemy[shot[n].num].x+cos(PI/2+PI/100*t)*100;
             shot[n].bullet[i].y     =enemy[shot[n].num].y+sin(PI/2+PI/200*t)*100;
			 int ax= shot[n].bullet[i].x ;
			 int ay= shot[n].bullet[i].y;
			if(t % 15 == 0 ){
			 for(int i=0;i<13;i++){
                           if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
							
                                shot[n].bullet[k].knd   =8;
                                shot[n].bullet[k].angle =PI2/20*i;
                                shot[n].bullet[k].flag  =1;
                                shot[n].bullet[k].x     =ax;
                                shot[n].bullet[k].y     =ay;
                                shot[n].bullet[k].col   =0;
                                shot[n].bullet[k].cnt   =0;
                                shot[n].bullet[k].spd   =1.2;
				se_flag[0]=1;
						}
                          }
			}

		}
		  if(shot[n].bullet[i].flag>0 && shot[n].bullet[i].state == 2){//登録されている弾があれば
                    shot[n].bullet[i].x     =enemy[shot[n].num].x+cos(PI/2-PI/100*t)*100;
                    shot[n].bullet[i].y     =enemy[shot[n].num].y+sin(PI/2-PI/200*t)*100;
			  int ax1= shot[n].bullet[i].x ;
			  int ay2= shot[n].bullet[i].y;
			    if(t % 15 == 0 ){
					for(int i=0;i<13;i++){
                                    if(shot[n].flag!=2 && (k=shot_search(n))!=-1){
							
                                shot[n].bullet[k].knd   =8;
                                shot[n].bullet[k].angle =PI2/20*i;
                                shot[n].bullet[k].flag  =1;
                                shot[n].bullet[k].x     =ax1;
                                shot[n].bullet[k].y     =ay2;
                                shot[n].bullet[k].col   =0;
                                shot[n].bullet[k].cnt   =0;
                                shot[n].bullet[k].spd   =1.2;
				se_flag[0]=1;
								}
                                  }
		         	}
                  }
			 }

		}
}
このように書けば魔法陣のx、y座標と発射位置のx、y座標が統一されるのではないかと思います。
実行してみた結果、前と同じ正しい実行結果が得られました。

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年11月05日(水) 23:52
by 青成
あれインデントがぐちゃぐちゃに・・・見辛いですがご了承ください。

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年11月06日(木) 01:35
by Tatu
魔法陣の座標から弾を撃つコードになっていますね。

ax,ay,ax1,ay2の型はdoubleではないでしょうか?

Re: 弾の発射位置に魔法陣を描画したい

Posted: 2014年11月06日(木) 02:37
by 青成
他のコードを見返してみてもこの場合実数なのでdoubleと書くべきでした。


細かいことまで教えて下さりありがとうございました。