抽象クラスで弾丸を統一して管理する

シンプルな構成の抽象クラスを継承して ArrayList で弾丸を統一して管理します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. プロジェクトは Array List に混在して登録する をベースに作成しています。
    説明の足らない部分は「Array List に混在して登録する」を参照して下さい。
    今回は、抽象クラスを継承して弾丸を統一して管理する方法を説明します。
    Array List には配列と違って「型の異なるデータを混在して登録出来る」ので、大抵の場合は抽象クラスを使う必要はありません。
    抽象クラスが必要になるのは、それぞれのクラスで仕様の異なるメソッドを呼び出す場合などです。
  2. 画像を描画する三種類の Object Class を使用します。
    Class ごとに弾丸の色を変えて描画する Draw() メソッドを定義しています。
  3. 各クラスの元になる Base Object Class です。
    多少なりとも解りやすいように機能を最小限に絞って定義してみました。
    abstract(抽象)で始まっているのが、抽象クラスの定義です。
    抽象クラスは他のクラスに継承されることが前提で、Base Class を直接インスタンス化することは出来ません。
    id は ArrayList に登録されたクラスを識別する領域です。
    最低限のコンストラクタと弾を移動するメソッドを定義しています。
    Drow() は abstract で定義されている実体の無いメソッドで、継承したクラスで実体を定義します。
    抽象クラスの基本的な説明は「超初心者のプログラム入門(C/C++/CLI)」を参照して下さい。
        abstract class Base
        {
            public int          id;         //クラスの識別
            public Texture2D    img;        //画像の指定
            public Vector2      pos;        //弾の座標
            public Vector2      vect;       //進行方向
    
            //コンストラクタ
            public Base(int ID, Texture2D Img, Vector2 Pos, Vector2 Vect)
            {   id = ID;
                img = Img;
                pos  = Pos;
                vect = Vect;
            }
            public abstract void  Draw(SpriteBatch spBatch);   //抽象メソッド
    
            //弾の移動
            public bool Move()
            {
                pos = pos + vect;
                if (pos.X < -8 || pos.X > 800 || pos.Y < -8 || pos.Y > 600) return true;
                return false;
            }
        }
    
  4. 抽象クラスを継承した Shot class です。
    コンストラクタでは、抽象クラスのコンストラクタを呼び出すだけです。
    C#では、継承する Class は一個しか許されず、基本クラスの Constructor を呼び出すときは、キーワード base を使います。
    abstract で定義されていた Draw() メソッドの実体を定義しなければなりません。
        class  Shot : Base
        {
            public Shot(int ID, Texture2D Img, Vector2 Pos, Vector2 Vect)
                : base(ID, Img, Pos, Vect)
            {
            }
            public override void Draw(SpriteBatch spBatch)
            {
                spBatch.Draw(img, pos, Color.Yellow);
            }
        }
    
  5. 抽象クラスを継承した Shoot class です。
    Shoot class は Shot Class と比べて描画の色が違うだけです。
        class  Shoot : Base
        {
            public Shoot(int ID, Texture2D Img, Vector2 Pos, Vector2 Vect)
                : base(ID, Img, Pos, Vect)
            {
            }
            public override void Draw(SpriteBatch spBatch)
            {
                spBatch.Draw(img, pos, Color.Aqua);
            }
        }
    
  6. 抽象クラスを継承した Fire class です。
    コンストラクタでは、抽象クラスのコンストラクタを呼び出すだけです。
    abstract で定義されていた Draw() メソッドの実体を定義しなければなりません。
    Fire class では、自機との当たり判定をするために Hit() メソッドを定義しています。
        class  Fire : Base
        {
            public Fire(int ID, Texture2D Img, Vector2 Pos, Vector2 Vect)
                : base(ID, Img, Pos, Vect)
            {
            }
            public override void Draw(SpriteBatch spBatch)
            {
                spBatch.Draw(img, pos, Color.Red);
            }
            //当たり判定
            public bool Hit(Vector2 target)
            {
                float dist;
                float wx;
                float wy;
    
                wx = pos.X - target.X;
                wy = pos.Y - target.Y;
                dist = (float)Math.Sqrt((double)(wx * wx + wy * wy));
                if (30 > dist) return true;
                return false;
            }
        }
    
  7. シューティングゲームの領域定義です。
    弾丸は統一して管理するので array が一個定義されているだけです。
    その他の領域の説明は、関連するページを参照して下さい。
            Texture2D   tama;               //弾テクスチャ
            Texture2D   ship;               //自機テクスチャ
            Shot        MyShip;             //自機の描画
            ArrayList   array;              //弾丸の ArrayList
            double      Settim;             //前回発射時刻
            Random rand = new Random();
    
  8. 乱数で弾丸を発射する fire_shoot() メソッドです。
    id = 3 で ArrayList に登録しています。
    横一列に弾丸を発射する tama_shoot() メソッドと、円状に弾丸を発射する Circle_shoot() メソッドも同じ要領です。
            public void fire_shoot()
            {
                for (int i = 0; i < 3; i++)
                {
                    pos.X = rand.Next(800);
                    pos.Y = 10;
                    vect.X = (rand.Next(100) - 50) / 10.0f;
                    vect.Y = rand.Next(100) / 10.0f + 1.5f;
                    array.Add(new Fire(3, tama, pos, vect));
                }
            }
    
  9. ウインドウを描画する Draw() メソッドです。
    ArrayList で弾丸を統一して管理しているので、非常にシンプルになっています。
    Base.Draw() では、継承したクラスで定義したそれぞれのメソッドが呼び出されます。
            protected override void Draw(GameTime gameTime)
            {
                graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
    
                // TODO: ここに描画処理を記述します。
                spriteBatch.Begin();
                //自機を描画
                MyShip.Draw(spriteBatch);
                //弾を描画
                foreach (Base BASE in array) BASE.Draw(spriteBatch);
                spriteBatch.End();
    
                base.Draw(gameTime);
            }
    
  10. Update() メソッドで、自機と弾丸の当たり判定をして下さい。
    Hit() メソッドが定義されているのは Fire Class だけです。
            protected override void Update(GameTime gameTime)
            {       :
                    :
                // 弾丸の当たり判定(id==3)
                for (int i = 0; i < array.Count; i++)
                {   if (((Base)array[i]).id==3)
                    {
                        if (((Fire)array[i]).Hit(MyShip.pos))
                            MyShip.pos.X = 0;
                    }
                }
                    :
                    :
    
  11. 三種類の弾丸が飛び交います。
    矢印キーを操作して Fire class の弾丸と自機との当たり判定を確認して下さい。

前田稔(Maeda Minoru)の超初心者のプログラム入門

超初心者のプログラム入門(XNA(C#) game program)