ページ 11

東方のようなスペカ表示について

Posted: 2011年10月14日(金) 17:18
by クラバック
いつもお世話になっております。
特定の弾幕を発動する際に、画像とスペルカード名を表示してみたいと思い、プログラムを改造しているのですが、行き詰ってしまいました。下の動画の1分08秒に表れるようなエフェクトにしたいと思っています。[youtube][/youtube]
過去のトピックを参考にさせて頂いて、構造体のヘッダにcnt,x、y座標、弾幕名の配列を用意したものの、コードに描き表せません。
スペルカードのフラグ=1→boss_shotH.cpp内のそれぞれの弾幕で弾幕名の文字列を実引数として関数を呼ぶ という流れになるのは想像できるのですが・・・
ご指導、ご鞭撻のほど宜しくお願い致します。

struct.h

コード:

//スペカ名を格納する構造体
typedef struct{
	int flag,cnt,to_cnt;//表示するフラグ、カウンタ、何カウントで表現するか
	double x,y;//表示する座標
	char *supell_name[DANMAKU_MAX];//弾幕の名前を格納する配列
}spell_name_t;

Re: 東方のようなスペカ表示について

Posted: 2011年10月14日(金) 20:46
by jay
クラバック さんが書きました:スペルカードのフラグ=1→boss_shotH.cpp内のそれぞれの弾幕で弾幕名の文字列を実引数として関数を呼ぶ という流れになるのは想像できるのですが・・・
ここまで分かっているのならば後はそれをプログラムに書き起こすだけなのですけれどね
まぁ、ある程度経験を積むまではそれが難しいのですけど(苦笑)

そうですね、龍神録をベースにするならば
effect.cpp内のcalc_effect関数にエフェクト本体の仕様を書くとあとで分かりやすいと思います。

スペルカードのフラグが1になった時に、boss_shot.cpp内にあるboss_shot_main関数から最初の呼び出し(登録)をするようにします
boss_shot_main関数から呼び出す登録用の関数に弾幕の名前を文字列の引数として渡してやればいいでしょうね。
今回の場合spell_name_t構造体の中の文字列spell_nameに渡してやって、それを元に弾幕の名前を表示させてやればいいと思います。
calc_effect関数は毎フレーム毎に呼び出されるので、一度スイッチを入れてやれば自動的に処理してくれます(処理の内容は当然自分で書く必要がありますが)
あとはエフェクトが終了した時点で弾幕が開始されるようにしてやればいいと思います。


とりあえず全体の流れを書いてみましたが、これも一つの方法であって別のやり方もあると思います。
でももう少し具体的な事を聞きたければまた聞いてくださいね

Re: 東方のようなスペカ表示について

Posted: 2011年10月14日(金) 21:06
by クラバック
迅速なアドバイス有難う御座います。今一度思考してみます。

Re: 東方のようなスペカ表示について

Posted: 2011年10月17日(月) 13:48
by クラバック
ごめんなさい。考えたのですが、全くと言っていいほど分かりませんでした。
作成した弾幕を、通常攻撃とスペルカードとを区別させるやり方がまず分かりません。
また、boss_shot_main()関数で登録用の関数enter_spell(char name)を呼ぶようにしたのですが、enter_spell(char name)側で渡された文字列をどう扱えばいいのか、分かりません。
理解力に乏しくて申し訳御座いません。再び、ご指導頂けませんでしょうか。

スペカ名を格納する構造体のメンバ名をspell_nameからspell_cardへ変更しました。タグ名とメンバ名が同一だった為です。

struct.h

コード:

//スペカ名を格納する構造体
typedef struct{
	int flag,cnt,to_cnt;//表示するフラグ、カウンタ、何カウントで表現するか
	double x,y;//表示する座標
	char *spell_card[DANMAKU_MAX];//弾幕名を格納する配列
}spell_name_t;
GV.h

コード:

//構造体変数宣言部
GLOBAL spell_name_t spell_name;
ini.cpp void ini内

コード:

void ini(){
/*・・・*/
spell_name.spell_card[0] = "月符「サイレントセレナ」";
spell_name.spell_card[1] = "凍符「パーフェクトフリーズ」";
spell_name.spell_card[2] = "禁忌「恋の迷路」";
}
boss_shot.cpp void boss_shot_main()内

コード:

//ボスの弾幕メイン
void boss_shot_main(){
	if((stage_count==boss.appear_count[0] || stage_count==boss.appear_count[1]) && boss.flag==0){//開始時間なら
		
		enter_boss(0);//開始
		enter_spell(*spell_name.spell_card[0]);//登録用の関数。スペルカード名を渡す

    }
	if(boss.flag==0)//ボスが登録されて無ければ戻る
		return;
	calc_boss();
	if(boss.phy.flag==1)//物理演算移動オンなら
		calc_phy();//物理計算を
	if(boss.state==2 && (boss.hp<=0 || boss.endtime<=0)){//弾幕中で体力が無くなったら
        se_flag[1]=1;//敵のピチュリ音
        se_flag[11]=1;
        input_phy(30);//30カウントで定位置に戻す
        memset(&boss_shot,0,sizeof(boss_shot_t));//ボスの弾幕情報を初期化
        memset(&lazer,0,sizeof(lazer_t)*LAZER_MAX);//ボスのレーザー情報を初期化
        flash.flag=0;//フラッシュを消す
        if(boss.knd==boss.danmaku_num[0] || boss.knd==boss.danmaku_num[1]||boss.knd==boss.danmaku_num[2] || boss.knd==boss.danmaku_num[3] || boss.knd==boss.danmaku_num[4]){//弾幕をだしきったら
             boss.flag=0;//消す
             enter_dn(10,40);//(45)ドガーン処理
             se_flag[9]=1;//ボスが死んだ音
             return ;
        }else{
             enter_boss(1);//次の弾幕を登録
		}
	}
	if(boss.state==1){//弾幕間の待機時間
		waitandenter();
	}
	if(boss.state==2){//弾幕中なら
		boss_shot_bullet[boss.knd]();//弾幕関数へ
		boss_shot_calc();//弾幕計算
	}
	boss.cnt++;
}
effect.cpp

コード:

//スペルカードの名前を登録する関数
void enter_spell(char name){//boss_shot_main()からスペルカード名nameが渡されてくる
	int k;
	spell_name.flag=1;
	
}
//スペルカードの名前の計算
void spell_calc(){
	if(spell_name.flag>0){


	}
}

Re: 東方のようなスペカ表示について

Posted: 2011年10月17日(月) 21:12
by jay
聞きたいことがあれば聞いて
とか自分で言った手前助けない訳にはいきませんね!

一気に全部片付けようとするとごちゃごちゃするので一つずつやって行ってくださいね(←受け売り)


まず通常攻撃とスペルカードとの区別ですが
龍神録でも通常攻撃とスペルカードとで背景を変える仕様になっていましたね
詳しくはこちら参照http://dixq.net/rp/25.html

そんな訳でコレを利用させてもらえばいいと思います
boss.back_knd[boss.knd]==1ならばスペルカードのエフェクトを表示させる、といった具合ですね。


文字列の扱いに関しては、これもやり方がいくつかあります
どちらにしろ配列とかポインタとかある程度理解していないと扱いは難しいですね
今回の場合
spell_name構造体の中のspell_cardがchar型の配列なので、ここに画面上に表示させる名前を入れる訳ですね
でも配列のポインタとか考えるとややこしくなるので、宣言を
char spell_card[DANMAKU_MAX];//弾幕名を格納する配列

こう変えた方がいいと思います
そして文字列操作関数であらかじめ用意していた文字列をコピーしてやるのがいいでしょうね。

文字列操作関数に関してはこの辺りを
http://tkmakwins15.tuzikaze.com/contents/string1.htm

もちろん文字列のポインタを渡す方法でもいいのですが、読み解くのが難しいですからね(苦笑)

Re: 東方のようなスペカ表示について

Posted: 2011年10月18日(火) 17:54
by クラバック
ご指導有難う御座います・・・!
教えて頂いたのを元に、ソースコードを改変してみました。しかし、boss_shot.cppとeffect.cpp内のenter_spell()関数の引数に疑問を覚えます。また、enter_spell()関数の定義で未だに躓いています・・・申し訳御座いません。
引き続き教えて頂ければ幸いです。

struct.h

コード:

//スペカ名を格納する構造体
typedef struct{
	int flag,cnt,to_cnt;//表示するフラグ、カウンタ、何カウントで表現するか
	double x,y;//表示する座標
	char spell_card[31];//弾幕名を格納する配列 ひとまずスペカ名を30文字以内に収める
}spell_name_t;
GV.h

コード:

GLOBAL spell_name_t spell_name[DANMAKU_MAX];//弾幕の個数分構造体を用意する
ini.cpp void ini()内

コード:

void ini(){
/*・・・*/
strcpy(spell_name[0].spell_card, "月符「サイレントセレナ」");
strcpy(spell_name[1].spell_card, "凍符「パーフェクトフリーズ」");
strcpy(spell_name[2].spell_card, "禁忌「恋の迷路」");
}
boss_shot.cpp void boss_shot_main()内

コード:

//ボスの弾幕メイン
void boss_shot_main(){
	
static int i=0;//前回からの変更点

	if((stage_count==boss.appear_count[0] || stage_count==boss.appear_count[1]) && boss.flag==0){//開始時間なら
		enter_boss(0);//開始

		//前回からの変更点
		if(boss.back_knd[boss.knd]==1){
			enter_spell(spell_name[i].spell_card[31]);//登録用の関数。スペルカード名を渡す
			i++;
		}
	
	}
	if(boss.flag==0){//ボスが登録されて無ければ戻る
		return;
	}
	calc_boss();
	if(boss.phy.flag==1){//物理演算移動オンなら
		calc_phy();//物理計算を
	}
	if(boss.state==2 && (boss.hp<=0 || boss.endtime<=0)){//弾幕中で体力が無くなったら
        se_flag[1]=1;//敵のピチュリ音
        se_flag[11]=1;
        input_phy(30);//30カウントで定位置に戻す
        memset(&boss_shot,0,sizeof(boss_shot_t));//ボスの弾幕情報を初期化
        memset(&lazer,0,sizeof(lazer_t)*LAZER_MAX);//ボスのレーザー情報を初期化
        flash.flag=0;//フラッシュを消す
        if(boss.knd==boss.danmaku_num[0] || boss.knd==boss.danmaku_num[1]||boss.knd==boss.danmaku_num[2] || boss.knd==boss.danmaku_num[3] || boss.knd==boss.danmaku_num[4]){//弾幕をだしきったら
             boss.flag=0;//消す
             enter_dn(10,40);//(45)ドガーン処理
             se_flag[9]=1;//ボスが死んだ音
             return ;
        }else{
             enter_boss(1);//次の弾幕を登録

			 //前回からの変更点
			 if(boss.back_knd[boss.knd]==1){
				 enter_spell(spell_name[i].spell_card[31]);//登録用の関数。スペルカード名を渡す
				i++;
			 }

		}
	}
	if(boss.state==1){//弾幕間の待機時間
		waitandenter();
	}
	if(boss.state==2){//弾幕中なら
		boss_shot_bullet[boss.knd]();//弾幕関数へ
		boss_shot_calc();//弾幕計算
	}
	boss.cnt++;
}
effect.cpp

コード:

//スペルカードの名前を登録する関数
void enter_spell(char name){//boss_shot_main()からスペルカード名が渡されてくる。仮引数char name?
	int k;
//	spell_name.spell_flag=1;
	
}
//スペルカードの名前の計算
void spell_calc(){
	//if(spell_name.flag>0){


	//}
}

Re: 東方のようなスペカ表示について

Posted: 2011年10月18日(火) 19:12
by jay
う~ん…。
どうやらあの内容を文字だけで伝えようとした僕が間違っていたようですね(苦笑)

でも詳しいコードを書くのは面倒ですし(オイ)
もっと簡単に実装できそうな気もしたのでちょっとだけ書いてみます

いっそのこと登録関数で文字列渡すのはやめにしてしまいましょう

boss_shotH.cpp

コード:

//サイレントセレナ
void boss_shot_bulletH001(){
#define TM001 60
    int i,k,t=boss_shot.cnt%TM001,t2=boss_shot.cnt;
    static int cnum;
    double angle;
    strcpy(spell_name.spell_card,"月符「サイレントセレナ」");
    if(t2==0)//最初の初期化
        cnum=0;
    if(t==0){//1ターンの最初の初期化
//以下略
  }
こうして弾幕毎に名前を設定してやればどうでしょう?

これですでにchar型の配列spell_cardには、スペルカードの名前が格納されているのであとはエフェクトを表示させるだけです。
まぁこの方法にも登録関数を呼び出すタイミングなど問題があるのですけど
上手くやらないと最悪エフェクトが表示されてる間に弾幕が始まって、ボスの画像がいい感じに邪魔すると思います。 ちょっと細工すればそれも解決できますけど。
まぁ、これも一つの方法と言うことで


で、今までクラバックさんが頑張って来た方法についての補足はここからです
クラバックさんがやっているようにしても実装できるとは思いますが
spell_name_t構造体が必要以上に宣言されてしまっているので、無駄に容量を取ると思います。
どうで処理する内容はボスの画像と名前を表示させるだけなので、spell_name_t構造体の宣言は一つでいいと思いますね。
配列で宣言した方が分かりやすいと言えば分かりやすいですが…
まぁ、お好きなようにしてください

登録関数についてはこんな感じでいいと思いますね

コード:

//スペルカードの名前を登録する関数
void enter_spell(int num)   //表示するスペル名の番号を渡す
{  
   spell_name[num].spell_flag=1;

   //必要な情報があれば登録したり処理したりしておく 
   //文字列を表示させるときの初期座標とか書いておくといいかも?  
}
スペルの番号って何? となると思いますが
ini.cppにて

コード:

void ini()
{
/*・・・*/
strcpy(spell_name[0].spell_card, "月符「サイレントセレナ」");
strcpy(spell_name[1].spell_card, "凍符「パーフェクトフリーズ」");
strcpy(spell_name[2].spell_card, "禁忌「恋の迷路」");
}
と書いてますよね

つまりspell_name構造体型配列の0番にはサイレントセレナが1番にはパーフェクトフリーズが既に入っている訳ですね。
だからあとは0を渡せばサイレントセレナが、1を渡せばパーフェクトフリーズが、2を渡せば恋の迷路が、それぞれ呼び出されるようにすればいいと思いますよ。
3番はグレイソーマタージ辺りで(黙れ)

こんどはサイレントセレナの時にはちゃんと0という数字を渡すように呼び出す側(boss_shot_main関数)で仕込んで置かなければならない訳ですが
これもini.cppで

コード:

//スペル名の番号を格納する。 通常弾幕の場合は-1にする
int spell_num[DANMAKU_MAX]  =  {-1, 0, -1, 1, 2,};
こんな感じの配列を作ってやって、それぞれに合った処理をするようにしてやればいいでしょうね
0以上なら番号にあったスペル宣言のエフェクトを表示させる、-1なら通常弾幕なのでエフェクトはなし
といった具合に。

ふむ、前半に余計なこと書いたせいで無駄に長文になってしまいましたね。
失礼しました


追記:
10/19午前10時頃
学校からちょっぴり訂正しました

Re: 東方のようなスペカ表示について

Posted: 2011年10月19日(水) 17:48
by クラバック
お手を煩わせてしまい申し訳御座いません。
成程、登録関数を使わない方法もあるんですね・・・!
しかし、烏滸がましいのですが、登録関数を使って実装してみたいと思っています。
ご指摘頂いたとおり、構造体をスペカ分用意するのは無駄と思い直し、一つだけ宣言しました。
また、spell_name_t構造体のメンバをchar spell_card[DANMAKU_MAX][41]としました。
effect.cpp内部の各種関数、MakeScreen関数やSetDrawScreen関数等を殆どいじったことがないので、試行錯誤しながら実装していきます・・・!

struct.h

コード:

//スペカ名を格納する構造体
typedef struct{
	int flag,cnt,to_cnt;//表示するフラグ、カウンタ、何カウントで表現するか
	double x,y;//表示する座標
	char spell_card[DANMAKU_MAX][41];//弾幕名を格納する配列 弾幕の個数分×弾幕の名前の最大文字数用意する
}spell_name_t;
GV.h

コード:

GLOBAL spell_name_t spell_name;
//スペル名の番号を格納する。
GLOBAL int spell_num[DANMAKU_MAX];
ini.cpp void ini()内

コード:

/*省略・・・*/
    strcpy(spell_name.spell_card[0], "月符「サイレントセレナ」");
	strcpy(spell_name.spell_card[1], "凍符「パーフェクトフリーズ」");
	strcpy(spell_name.spell_card[2], "禁忌「恋の迷路」");

	//スペル名の番号を格納する。 通常弾幕の場合は-1にする
	spell_num[0] = -1;//通常弾幕
	spell_num[1] =  0;//
	spell_num[2] = -1;
	spell_num[3] =  1;
	spell_num[4] =  2;
boss_shot.cpp boss_shot_main()内

コード:

//ボスの弾幕メイン
void boss_shot_main(){
	static int i=0;
	if((stage_count==boss.appear_count[0] || stage_count==boss.appear_count[1]) && boss.flag==0){//開始時間なら
		enter_boss(0);//開始

		//前回からの変更点
		if(boss.back_knd[boss.knd]==1){//もし背景がスペカ用背景ならば、
			if(spell_num[i]!=-1){//もしi番目の弾幕が、通常弾幕でなければ
				enter_spell(spell_num[i]);//i番目の弾幕を登録。
			}
		}
		i++;	
	}
	if(boss.flag==0){//ボスが登録されて無ければ戻る
		return;
	}
	calc_boss();
	if(boss.phy.flag==1){//物理演算移動オンなら
		calc_phy();//物理計算を
	}
	if(boss.state==2 && (boss.hp<=0 || boss.endtime<=0)){//弾幕中で体力が無くなったら
        se_flag[1]=1;//敵のピチュリ音
        se_flag[11]=1;
        input_phy(30);//30カウントで定位置に戻す
        memset(&boss_shot,0,sizeof(boss_shot_t));//ボスの弾幕情報を初期化
        memset(&lazer,0,sizeof(lazer_t)*LAZER_MAX);//ボスのレーザー情報を初期化
        flash.flag=0;//フラッシュを消す
        if(boss.knd==boss.danmaku_num[0] || boss.knd==boss.danmaku_num[1]||boss.knd==boss.danmaku_num[2] || boss.knd==boss.danmaku_num[3] || boss.knd==boss.danmaku_num[4]){//弾幕をだしきったら
            boss.flag=0;//消す
            enter_dn(10,40);//(45)ドガーン処理
            se_flag[9]=1;//ボスが死んだ音
            return ;
        }else{
            enter_boss(1);//次の弾幕を登録

			//前回からの変更点
			if(boss.back_knd[boss.knd]==1){//もし背景がスペカ用背景ならば、
				if(spell_num[i]!=-1){//もしi番目の弾幕が通常弾幕でなければ、
					enter_spell(spell_num[i]);//i番目の弾幕を登録。
				}
		    }
			i++;
		}
	}
	if(boss.state==1){//弾幕間の待機時間
		waitandenter();
	}
	if(boss.state==2){//弾幕中なら
		boss_shot_bullet[boss.knd]();//弾幕関数へ
		boss_shot_calc();//弾幕計算
	}
	boss.cnt++;
}
effect.cpp

コード:

//スペルカードの名前を登録する関数
void enter_spell(int num){//boss_shot_main()からスペルカード名が渡されてくる
	int k;
	spell_name.flag=1;
	spell_name.spell_card[num];//←文字列が格納されている
	spell_name.x = FMX-50;//ひとまずの初期x座標
	spell_name.y = FMY-50;//ひとまずの初期y座標
	spell_name.cnt = 0;
	if((k=search_effect())!=-1){
        effect[k].flag=1;//エフェクトを登録
        effect[k].cnt=0;
        effect[k].knd=5;//スペルカード発動エフェクト(文字)
        effect[k].brt=0;
        effect[k].ang=0;
        effect[k].mvang=-PI/2;
        effect[k].spd=1;
        effect[k].r=1;
        effect[k].eff=2;
        effect[k].img=handle;//[s]たぶん文字列を画像にしてここにいれる[/s]
        effect[k].x=70;
        effect[k].y=300;
    }
	//必要な情報があれば登録したり処理したりしておく 
   //文字列を表示させるときの初期座標とか書いておくといいかも?
}
//スペルカードの名前の計算
void spell_calc(){
	//if(spell_name.flag>0){


	//}
}
//エフェクトを計算する
void calc_effect(){
    for(int i=0;i<EFFECT_MAX;i++){
        if(effect[i].flag>0){//エフェクトが登録されていたら
            effect[i].x+=cos(effect[i].mvang)*effect[i].spd;
            effect[i].y+=sin(effect[i].mvang)*effect[i].spd;
            switch(effect[i].knd){//エフェクトの種類によって分岐
/*省略・・・*/
case 5 ://スペルカード発動エフェクト(文字)
					if(effect[i].cnt>=10){
						effect[i].brt-=255/10;
					}
					effect[i].r+=0.12;
					effect[i].cnt++;
					if(effect[i].cnt>12 || ch.flag!=1){
						effect[i].flag=0;
					}
					break;
                default:
                    printfDx("effect設定エラー\n");
                    break;
            }
        }
    }
}

Re: 東方のようなスペカ表示について

Posted: 2011年10月23日(日) 03:14
by クラバック
無事、スペカ名と画像のエフェクト、両方の実装を終えることが出来ました・・・!
細部の再現は到底叶いませんが、ひとまず原型は出来たように思います。
エフェクトの使い方も大体は理解出来ましたし、これから更なる拡張に努めたいと思います。
jayさん、助けて頂いたこと深く御礼申し上げます。また機会が有りましたら、宜しくお願い致します。

ini.cpp

コード:

void ini(){
    strcpy(spell_name.spell_card[0], "月符「サイレントセレナ」");
	strcpy(spell_name.spell_card[1], "凍符「パーフェクトフリーズ」");
	strcpy(spell_name.spell_card[2], "禁忌「恋の迷路」");

	//スペル名の番号を格納する。 通常弾幕の場合は-1にする
	spell_num[0] =  0;//通常弾幕
	spell_num[1] =  0;//
	spell_num[2] = -1;
	spell_num[3] =  1;
	spell_num[4] =  2;
	SetDrawValidAlphaChannelGraphCreateFlag(TRUE);
	spell_name_handle = MakeScreen(300, 20);
	SetDrawValidAlphaChannelGraphCreateFlag(FALSE);
}
boss_shot.cpp

コード:

//ボスの弾幕メイン
void boss_shot_main(){
	static int i=0;
	if((stage_count==boss.appear_count[0] || stage_count==boss.appear_count[1]) && boss.flag==0){//開始時間なら
		enter_boss(0);//開始

		//前回からの変更点
		if(boss.back_knd[boss.knd]==1){//もし背景がスペカ用背景ならば、
			if(spell_num[i]!=-1){//もしi番目の弾幕が、通常弾幕でなければ
				enter_spell_name(spell_num[i]);//i番目の弾幕を登録。
				enter_spell_graph(img_dot_bossImage[4]);
			}
		}
		i++;	
	}
	if(boss.flag==0){//ボスが登録されて無ければ戻る
		return;
	}
	calc_boss();
	if(boss.phy.flag==1){//物理演算移動オンなら
		calc_phy();//物理計算を
	}
	if(boss.state==2 && (boss.hp<=0 || boss.endtime<=0)){//弾幕中で体力が無くなったら
        se_flag[1]=1;//敵のピチュリ音
        se_flag[11]=1;
        input_phy(30);//30カウントで定位置に戻す
        memset(&boss_shot,0,sizeof(boss_shot_t));//ボスの弾幕情報を初期化
        memset(&lazer,0,sizeof(lazer_t)*LAZER_MAX);//ボスのレーザー情報を初期化
        flash.flag=0;//フラッシュを消す
        if(boss.knd==boss.danmaku_num[0] || boss.knd==boss.danmaku_num[1]||boss.knd==boss.danmaku_num[2] || boss.knd==boss.danmaku_num[3] || boss.knd==boss.danmaku_num[4]){//弾幕をだしきったら
            boss.flag=0;//消す
            enter_dn(10,40);//(45)ドガーン処理
            se_flag[9]=1;//ボスが死んだ音
            return ;
        }else{
            enter_boss(1);//次の弾幕を登録

			//前回からの変更点
			if(boss.back_knd[boss.knd]==1){//もし背景がスペカ用背景ならば、
				if(spell_num[i]!=-1){//もしi番目の弾幕が通常弾幕でなければ、
					enter_spell_name(spell_num[i]);//i番目の弾幕を登録。
				}
		    }
			i++;
		}
	}
	if(boss.state==1){//弾幕間の待機時間
		waitandenter();
	}
	if(boss.state==2){//弾幕中なら
		boss_shot_bullet[boss.knd]();//弾幕関数へ
		boss_shot_calc();//弾幕計算
	}
	boss.cnt++;
}
effect.cpp

コード:

//スペルカードの名前を登録する関数
void enter_spell_name(int num){//boss_shot_main()からスペルカード名が渡されてくる
	int k;
	spell_name.flag=1;
	make_spell_graph(num);//画像作成
	if((k=search_effect())!=-1){
		effect[k].ang = 0;
		effect[k].brt = 0;
		effect[k].cnt = 0;
		effect[k].eff = 2;
		effect[k].flag = 1;//エフェクトを登録
		effect[k].img = spell_name_handle;
		effect[k].knd = 5;//スペルカード発動エフェクト(文字)
		effect[k].mvang = PI/2*3;//↑方向
		effect[k].r = 6.0;
		effect[k].spd = 0;
		effect[k].x = FMX-55;
		effect[k].y = FMY-10;
    }
	//必要な情報があれば登録したり処理したりしておく 
   //文字列を表示させるときの初期座標とか書いておくといいかも?
}
//スペルカードの画像を登録する関数
void enter_spell_graph(int graph){//ボスの画像graphが渡されてくる
	int k;
	if((k=search_effect())!=-1){
		effect[k].ang = 0;
		effect[k].brt = 125;
		effect[k].cnt = 0;
		effect[k].eff = 2;
		effect[k].flag = 1;
		effect[k].img = graph;
		effect[k].knd = 6;
		effect[k].mvang = PI/6*5;
		effect[k].r = 1;
		effect[k].spd = 7;
		effect[k].x = FMX+50;
		effect[k].y = FY+30;
	}
}

//エフェクトを計算する
void calc_effect(){
    for(int i=0;i<EFFECT_MAX;i++){
        if(effect[i].flag>0){//エフェクトが登録されていたら
            effect[i].x+=cos(effect[i].mvang)*effect[i].spd;
            effect[i].y+=sin(effect[i].mvang)*effect[i].spd;
            switch(effect[i].knd){//エフェクトの種類によって分岐
				case 5 ://スペルカード発動エフェクト(文字)
					if(effect[i].cnt<=25){
						effect[i].brt+=255/25;
						effect[i].r -= 0.192;//1.2倍へ
					}
					if(effect[i].cnt>=30 && effect[i].y > FY){
						effect[i].spd += 0.08;
					}
					if(effect[i].y <= FY){
						effect[i].spd = 0;
					}
					effect[i].cnt++;
					/*if(effect[i].cnt>12 || ch.flag!=1){
						effect[i].flag=0;
					}*/
					break;
				case 6 ://スペルカード発動エフェクト(画像)
					if(effect[i].x<FMX/6*4 && effect[i].x>FMX/6*3 ){
						effect[i].spd = 2;
					}
					if(effect[i].x<=FMX/6*3){
						effect[i].spd = 7;
					}
					break;
                default:
                    printfDx("effect設定エラー\n");
                    break;
            }
        }
    }
}
graph.cpp

コード:

//スペカ名が記述された画像作成
void make_spell_graph(int k){//strcpy(spell_name.spell_card[0], "月符「サイレントセレナ」");の[]内のこと
	if(spell_name.flag>0){
		SetDrawScreen(spell_name_handle);//ini()で作成した画像を描画対象にする
		ClearDrawScreen();
		ChangeFontType(DX_FONTTYPE_ANTIALIASING);
		ChangeFont("MS ゴシック");
		DrawString(5, 2.5, spell_name.spell_card[k], color[0]);//画像に対して、スペルカード名を描画する
		SetDrawScreen(DX_SCREEN_BACK);
	}
}