Project Anthem(TCストライカーズ)

ぷろじぇくとあんせむ公式サイトであり雑記ブログ。当サイトはリンクフリーです。

ゲーム開発

念願だったHPタンクシステムを実装しました。私が勝手にそう読んでいるだけですが(❀╹◡╹)

 
 現在のシューティングゲームではボスのHPに応じて攻撃パターンが変化するものがほとんどです。様々な言語のチュートリアルサイトでその実装方法が掲載されています。しかしその全て(私が見た中では)が初期HPに対する割合で変化させるものでした。

 初期HPの80%〜100%の間 攻撃パターン1
 初期HPの60%〜 80%の間 攻撃パターン2
 ・・・
・・・

 これが基本的な手法ですが、後から攻撃パターンの持続時間を変更したくなった時に全部の数値を替えなければいけません。


 なので、各段階ごとにHPが設定されており、その段階のHPが0になった時点で次の段階に移る、というシステムがどうしても欲しかったのです。大きな格納容器とそこに流し込む液体を保存するポリタンクのようなイメージです。

 
hptank


 まあ、東方と一緒ですけど・・・


段階を管理するために int phase 
HPを格納する変数として int hptank
段階ごとのHP int[ ]  hp    
 と3つ変数を用意しました。


  switch (phase)
            {
                case 1:
                    if (hp[phase] > 0)
                    {
                        hptank = hp[phase];
                        hp[phase] = 0;
                    }
                    else if (hptank <= 0) phase++;
                    break;

                case 2:
                    if (hp[phase] > 0)
                    {
                        hptank = hp[phase];
                        hp[phase] = 0;
                    }
                    else if (hptank <= 0) phase++;
                    break;

                case 3:
                    if (hp[phase] > 0)
                    {
                        hptank = hp[phase];
                        hp[phase] = 0;
                    }
                    else if (hptank <= 0) phase++;
                    break;

                case 4:
                    if (hp[phase] > 0)
                    {
                        hptank = hp[phase];
                        hp[phase] = 0;
                    }
                    else if (hptank <= 0) phase++;
                    break;

                case 5:
                    Engine.Sound.Play(SE.bossexplosion);
                    Dispose();
                    break;
            } 


 これによってHPの管理と段階ごとの攻撃パターンの管理をわけることができました。

 
 switch (phase)
            {
                case 1:
                   
                    break;

                case 2:
              
                    break;

                case 3:
                   
                    break;

                case 4:
                 
                    break;
            } 

 
 各段階ごとに攻撃パターンを記述すればOKです。このおかげでテキストがずいぶん見やすくなりました。視認性は開発スピードに大きく影響します。


Altseedを使用しています
http://altseed.github.io/


ゲーム用の楽曲です。 2回ループになっています。



 明るくてノリの良い曲に仕上がっています。とても私らしい曲だと思います。

 この曲が私らしいという理由は、参考資料無しで作ったからです。大体の楽曲は何かの曲のオマージュとなってしまうため、その曲を参考にしながら構成や音色を練っています。例えば、前作♪Insane Distinationはmiddle modeさんのRebornを参考に作っています。


  

 大抵の曲は参考資料がないと完成まで至らないのです。メインメロディだけ作って放置というパターンがとても多いですorz。その点、本曲Canopusは最初から最後までスムーズに好き勝手作ることができました。もともとゲーム用に2分弱の構成だからかもしれません。ただ展開が早い気もしますが・・・



 この曲はもともと 昨年行ったパステル画展でとある絵を見て思いつきました。その絵は夕焼けのビーチを描いた作品で見た直後に主旋律が降りてきました。ただ、オリジナルキャラクターのテーマ曲が必要だったことと、カノープスのイメージと夕焼けビーチのイメージがマッチしたので、タイトルをCanopusにしました。なんででしょうね??
 
 nenga2013bass
 
 左:カノープス 右:アルティル

  

やっと実装できました。

音楽再生するだけだから簡単だろうと思っていましたが意外と難関でした。







 曲が流れている時に他の曲を流すためには前の曲を止めないといけないんですネ。それを止めるためには今流れているのがなんという曲かを把握(取得)しなければなりません。そして曲を止めるのですが、止まってから次の曲が再生される一瞬の間だけ曲が流れていない状態になるんです。その時にエラーが起きるorz///


 原因は曲を番号で管理するという点にあります。int型変数で流れている曲を把握するのですが、止まった瞬間に空っぽになってしまいます。その際に”それはだめだよ”っていうことでエラーとなるのです。

 プログラミングで初めて知ったことなのですが、ゼロ0と空っぽは違うんですね。

 
 intをNULL許容型にして解決しました。

 
 と思ったら今度は再生メソッドが”NULL型はだめだよ”と言ってきました。まあこれはキャストして解決です。



・EXITの実装


 これも簡単そうでやっかいでした。EXITを押して直接終了処理をしてしまうとメイン関数がもつ終了メソッドと重複してしまうためエラーを起こします。
 
 そこで
public static bool escape=false

 というグローバル変数を作り、EXITを押すと

escape=true

 となる仕様にしました。グローバル変数は使わないほうがいいと言われているのであとで不都合が起きないか不安なとこです。




・今後の課題

  • 起動時にタイトル曲が流れるようにしたい
  • プレイ中esc押下でポーズさせる
  • ポーズ画面には 続ける タイトルに戻る のセレクトを用意



DTM ブログランキングへ


 ゲームではお馴染みの残機表示を 実装します。
 
 blog3
 
 
 もうドット絵作るのがめんどくなってきたので
  1. フォトショップ
  2. テキスト”★”を入力
  3. トリミング 
 とやって作りました。カーソルも同じように△をそのまま使います。お手軽にハイクオリティです。


 ただ、この残機表示は被弾しても減りませんorz
 
 

Class player

 public override void OnCollide(CollidableObject obj)
        {
            Engine.AddObject2D(new BreakObjectEffect(Position));
            Engine.Sound.Play(SoundDeathnd);
            Zanki--;
            if (Zanki < 0) Dispose();
        }
 


Class SceneGame

 protected override void OnUpdated()
        {
            for(int i = 0; i < player.Zanki; i++)
            {
                var pictzanki = new PictgramZanki(i);
                LayerUi.AddObject(pictzanki);
            }
            updateStage();            
        }
     
  

これで いけると思ったのですが...うーん。一度表示した★を消去するメソッドが無いからでしょうか・・・ 

前回の続きです。


無事に会話を進めることができました。

blog


Zボタンを押すと、前のセリフが消え、次のセリフが表示されます。


blog2



 ”一つ前のセリフ(インスタンス)を消去する”という予定でしたが、会話レイヤーのオブジェクト全部を消してしまったほうが簡単な記述で済みます。そのために新規で会話のみのレイヤーを追加しました。

 




  protected override void OnUpdated()
        {
            base.OnUpdated();
            if (kaiwaStage1.Count > 0)
            {
                if (Engine.Keyboard.GetKeyState(Keys.Z) == KeyState.Push)
                {
                    layerKaiwa.Clear();
                    layerKaiwa.AddObject(kaiwaStage1.Dequeue());
                }
            }

        } 

↑このページのトップヘ