データベースとは?|初心者でもわかるプログラミング学習入門
GEEK JOB編集部
前章までで、自機と弾を作りました。
次に、シューティングゲームに必要な敵を作っていきたいと思います。
完成イメージは以下の通り。
自機や弾と違い、シューティングでは敵は普通複数体出てきます。
複数の要素の管理、と聞いて初心者が初めに思いつくのは配列でしょう。
実際、配列を使えば複数の敵を管理することは可能です(面倒ですが)。
JavaやC#のような言語には、このような複数要素の管理を容易にするデータ構造があらかじめ用意されています。
そのうちの一つが、Listというデータ構造です。
Listは、整数値のインデックスに任意のクラスを格納できる点で配列に似ていますが、配列と違ってはじめに要素数を宣言しなくても、いつでも好きなタイミングで要素を追加できます。
また、要素をListで管理することにより、for文のような繰り返しをしたいときに、一般にforeachと呼ばれる文法を使用することができ、コードがいくらか読みやすくなります。
Listの宣言方法と初期化、および要素の追加は以下の通りです。
1 2 |
List<クラス名> list = new Arraylist<>(); list.add(クラスのインスタンス); |
要素の追加については、他にも初期化のときにコンストラクタ内で一緒に追加するやり方や、既存のリストに格納されているインスタンスを同時に追加する方法があります。
今回は、このリストを使って、Enemyクラスを作ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
Field.java public class Field extends JPanel implements KeyListener, ActionListener { private Player player; private Bullet bullet; private List enemies; public Field() { setSize(600, 400); setBackground(Color.white); setFocusable(true); addKeyListener(this); Timer timer = new Timer(20, this); timer.start(); player = new Player(); bullet = new Bullet(300, 300); enemies = new ArrayList<>(); for(int i=0; i<20; i++) { enemies.add(new Enemy(i*30, 20)); } } @Override public void paintComponent(Graphics g) { g.clearRect(0, 0, getWidth(), getHeight()); g.setColor(Color.red); player.draw(g); bullet.draw(g); for(Enemy enemy: enemies) { enemy.draw(g); } } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { player.move(e.getKeyCode()); if(e.getKeyChar() == 'z') { bullet = player.shoot(); } } @Override public void keyReleased(KeyEvent e) { } @Override public void actionPerformed(ActionEvent e) { bullet.update(); for(Enemy enemy: enemies) { enemy.update(); } repaint(); } } Enemy.java public class Enemy { private int x; private int y; public Enemy(int x, int y) { this.x = x; this.y = y; } public void update() { this.y += 1; } public void draw(Graphics g) { g.drawRect(x, y, 20, 20); } } |
Fieldクラスの冒頭でListのenemiesを宣言して、コンストラクタの中でenemiesにEnemyクラスのインスタンスを格納しています。
ここで注意していただきたいのが、以下の一文です。
1 |
enemies = new ArrayList<>(); |
Javaでは、Listで宣言したクラスに対して、ArrayListのインスタンスを代入するのが普通です。
Listは抽象クラスで、インスタンスを作れないので、new List<>();とするとコンパイルエラーになります。
次に注目してほしいのが、以下の一文です。
1 |
for(Enemy enemy: enemies) { enemy.draw(g); } |
いわゆるforeach文です。
カッコの中に書かれたListの各要素(each)に対して、同一の処理をすることからforeach文と呼ばれています。
今回は、enemiesというListに入っている、各enemy要素に対して、draw()メソッドを呼び出しています。
このように、Listに格納されている要素の中で、特に呼び出す順序にこだわらない場合には、foreach文が威力を発揮します。
もしforeach文を使わなければ、このループは以下のように書き直す必要があります。
1 |
for(int i=0; i<enemies.size(); i++) { enemies.get(i).draw(g); } |
先ほどより、コードが冗長になっているのが分かります。
一応この書き方にも、enemiesの中に格納された順序に応じた処理を追加できるという利点はありますが、そもそもそのような処理はソースコードの可読性を下げ、あまり好ましくないので、なるべく避けましょう。
以上で、自機、弾、敵を出し、シューティングに必要な役者は揃いました。
ここで、それぞれのクラスのコードを読み比べてみてください。
xやyといった同じ名前の変数や、draw()やupdate()のような共通するメソッドが多いことに気が付いたでしょうか。
このような場合、クラスの継承を用いることで、よりコードを簡略に記述することが可能になります。
というわけで、次の章ではクラスの継承と、オブジェクト指向の華ともいえる多態性(ポリモーフィズム)について学んでいきましょう。