ページ 11

スペルカードの表示について

Posted: 2012年3月13日(火) 21:06
by にゅうぼーろ
C初心者です。
 今、龍神録プログラムとhttp://dixq.net/forum/viewtopic.php?t=9388&p=75893を参考にさせていただいて、スペルカード発動時のエフェクトを作成しています。

 まずはソースをコピペして動作を確認してみようと思い、自分のソースに配置して実行してみました。
すべての関数の宣言が書いていなかったので自分で宣言してみたところうまく動きません。(他にも多発したエラーを消そうとちょこちょこいじってしまいました)

なんとかエラーは回避したもの、肝心のエフェクトは起こらない上、ボス弾幕までおかしくなりました。
宣言方法とか配列や関数の使い方を間違っていたり、足りなかったりしているかもしれないと思うのですが、まだ勉強中なのでよくわかりません。(すいません、理解力の無い脳みそで)

お手数ですが以下のソースをチェックしていただいて悪いところを直してていただければ幸いです。

GV.h(追加分)

コード:

GLOBAL int spell_num[DANMAKU_MAX];
GLOBAL int img_boss_spell[10];//ボス・スペルエフェクト時画像用
function.h(追加分)

コード:

    GLOBAL void enter_spell_graph(int);
    GLOBAL void enter_spell_name(int);
    GLOBAL void make_spell_graph(int);
]
struct.h

コード:

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

load.cpp(追加分)

コード:

img_boss_spell[1] = LoadGraph("../dat/img/back/effect/a.png");


ini.cpp

コード:

    
    strcpy(spell_name.spell_card[0], "弾幕「未設定01」");
    strcpy(spell_name.spell_card[1], "弾幕「未設定02」");
    strcpy(spell_name.spell_card[2], "弾幕「未設定03」");

//スペル名の番号を格納する。 通常弾幕の場合は-1にする
    spell_num[0] =  0;
    spell_num[1] =  0;
    spell_num[2] = -1;
    spell_num[3] =  1;
    spell_num[4] =  2;
    SetDrawValidAlphaChannelGraphCreateFlag(TRUE);
    MakeScreen(300, 20);    //spell_name_handle = MakeScreen(300, 20);のようにすると左辺値どうのこうのとエラーが出る。
    SetDrawValidAlphaChannelGraphCreateFlag(FALSE);
}
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] || stage_count==boss.appear_count[2])
		&& 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_boss_spell[0]);//ここ、これでいいのか不明
            }
        }
        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.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 spell_num){//boss_shot_main()からスペルカード名が渡されてくる
    int k;
    spell_name.flag=1;
    make_spell_graph(spell_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 = MakeScreen(300, 20);//←iniで変更したやつ
        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){//この類はintがないとエラー。(一つの変数を指定できない)
    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 0://敵の消滅エフェクト
                    effect[i].cnt++;
                    effect[i].r+=0.08;//エフェクトの大きさを段々大きくする
                    if(effect[i].cnt>10)//10カウント以上になったら
                        effect[i].brt-=25;//明るさを少なくする
                    if(effect[i].cnt>20)//20カウント以上になったら
                        effect[i].flag=0;//消す
                    break;
                case 1://ボムのエフェクト
                    //スピード計算
                    if(effect[i].cnt<60)
                        effect[i].spd-=(0.2+effect[i].cnt*effect[i].cnt/3000.0);
                    if(effect[i].cnt==60){
                        effect[i].spd=0;
                        se_flag[15]=1;
						enter_dn(11,20);//(45)
                    }
                    //明るさと大きさ計算
                    effect[i].r+=0.015;
                    if(effect[i].cnt<51)
                        effect[i].brt+=5;
                    if(effect[i].cnt>=60){
                        effect[i].r+=0.04;
                        effect[i].brt-=255/30.0;
                    }
                    //カウントアップと消去計算
                    effect[i].cnt++;
                    if(effect[i].cnt>=90)
                        effect[i].flag=0;
                    break;
                case 2://ボムエフェクト(キャラ)
                    //明るさ計算
                    if(effect[i].cnt<51)
                        effect[i].brt+=4;
                    if(effect[i].cnt>130-51)
                        effect[i].brt-=4;
                    //カウントアップと消去計算
                    effect[i].cnt++;
                    if(effect[i].cnt>=130)
                        effect[i].flag=0;
                    break;
                case 3://ボムのエフェクト(ライン)
                    //明るさ計算
                    if(effect[i].cnt<51)
                        effect[i].brt+=2;
                    if(effect[i].cnt>130-51)
                        effect[i].brt-=2;
                    //カウントアップと消去計算
                    effect[i].cnt++;
                    if(effect[i].cnt>=130)
                        effect[i].flag=0;
                    break;                
                case 4://喰らいボムエフェクト
                    //明るさ計算
                    if(effect[i].cnt>=6)
                        effect[i].brt-=255/6;
                    effect[i].r+=0.12;
                    effect[i].cnt++;
                    if(effect[i].cnt>=12 || ch.flag!=1)
                        effect[i].flag=0;
                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){
    if(spell_name.flag>0){
        SetDrawScreen (MakeScreen(300, 20));//iniで変更している。
        ClearDrawScreen();
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
        ChangeFont("MS ゴシック");
        DrawString(5, 2.5, spell_name.spell_card[k], color[0]);//画像に対して、スペルカード名を描画する
        SetDrawScreen(DX_SCREEN_BACK);
    }
}

Re: スペルカードの表示について

Posted: 2012年3月14日(水) 03:10
by jay
なんだか自分が参加したやりとりを参考にされた上で間違えられたのなら僕が悪いんじゃないかって思えてしまいました(笑) 
協力はしますが、あのコードをコピペしたなら僕よりクラバックさんが解説した方がいいような…?
まぁいいですか(いいのか?)

ただ、こういうのは人の真似をするより自分で0から作った方がいい経験になりますよ?
その方が後で改造やメンテナンスがやりやすいですしね
できるなら最初から自分で作ってみることをオススメします、僕もできる限りはお手伝いしますから頑張ってみてください
というかその方がこちらとしてもアドバイスしやすいので助かるんですけど(苦笑)

さてここからが本題ですが
まずあの処理の流れを簡単にまとめるとこんな感じになります
①ボスの弾幕を登録

②その弾幕がスペルカードかどうか判断する

③スペルカードだったら弾幕名の登録関数に弾幕の番号を渡す
  登録関数では必要な初期化(文字やボスの立ち絵の表示位置など)を行い、また文字列もあらかじめ用意しておいた弾幕の名前に設定する
  そしてエフェクトを登録する

④実際にエフェクトを再生(ボスの立ち絵と弾幕の名前を表示する)

⑤エフェクトが終わったら弾幕開始


クラバックさんの場合はエフェクトが少し特殊なのか少々ややこしい手順を踏んでいますが
これだけの事なのであまり難しく考えないでくださいね

この流れにそって1から作って行くことができればいいのですが…
一応にゅうぼーろさんのコードを強引に使う場合の簡単な解説

①と②についてはboss_shot_main関数が相当しますね

コード:

void boss_shot_main(){
    static int i=0;
    if((stage_count==boss.appear_count[0] || stage_count==boss.appear_count[1] || stage_count==boss.appear_count[2])
        && 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_boss_spell[0]);//ここ、これでいいのか不明
            }
        }
        i++;    
    }
これについては恐らくそのままでいいでしょう
ただenter_spell_graph関数は不要なんじゃないかと思います。
spell_numの辺りは説明はしなくても大丈夫…かな?

③について
enter_spell_name関数が登録関数に相当しますね

コード:

void enter_spell_name(int spell_num){//boss_shot_main()からスペルカード名が渡されてくる
    int k;
    spell_name.flag=1;
    make_spell_graph(spell_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 = MakeScreen(300, 20);//←iniで変更したやつ
        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;
 
    }
    //必要な情報があれば登録したり処理したりしておく 
   //文字列を表示させるときの初期座標とか書いておくといいかも?
}
これで実際にエフェクトの登録を行う訳ですね。 これも不要な物は削除してしまいましょう
make_spell_graph関数は要りません、MakeScreen関数もよくわからないので削除
ここでやるべきことは2つ
・表示するボスの画像の用意
・表示する文字列の用意

これだけです。
effect[k].imgに入れるべきモノは”表示するボスの立ち絵の画像ハンドル”です、難しいことは考えなくてOK
文字列(スペル名)に関しては適当な構造体でも用意してやって、その中にspell_name.spell_cardで宣言したスペル名、描画座標等を入れてあげてください
後はそれぞれの初期描画位置等の値の初期化処理をしてやればOKです。

④について
③の工程で表示する画像と文字列は用意できたので、後は自分が思うように表示するだけです
これについてはcalc_effect関数でご自分が好きなように処理してください
但しgraph.cppの中でスペルカードエフェクトが登録されていたらスペル名を表示する処理を作ってあげてくださいね。
じゃないとスペル名は表示されませんので

⑤については…
説明は不要ですね

にゅうぼーろさんのコードを強引に使うならこんな感じですね
どうでしょうか? 完璧に僕の解説の通りにすればちゃんとエフェクトは表示されるハズですが、かなりややこしいんじゃないかと思います。
クラバックさんのコードを使うには修正すべき点が多すぎる(間違ってるんじゃなくて情報が足りないから)ので
やはり出来るならにゅうぼーろさんが1から作って行った方がいいと思います。

Re: スペルカードの表示について

Posted: 2012年3月14日(水) 19:57
by にゅうぼーろ
jayさんお返事ありがとうございます。
まずは教えていただいた方法を理解して、自分で思考錯誤しようと思います。
行き詰ったらまた質問するかもしれませんがその時はよろしくお願いします。