Javaゲームプログラミング

シューティングゲームを作ってみようの連載6回目です。自機移動時の不具合を解消します。



弾の発射 その2

このページには、以下のサンプルを掲載しています。 下の項目をクリックをすると各サンプルにジャンプします。 ※2週間以内の新着記事はNewアイコン、更新記事はUpアイコンが表示されます。

やっと弾が発射出来るようになりました。。。が、実は、アプレットを実行してみるといくつか不具合があります。
目だったところで下のような不具合があります。
1.自機を移動しながら(「←」または「→」キーを押しながら)弾を発射すると自機の動きが、止まってしまう。
2.画面がちらついてしまう。
3.弾が画面のはしに行く前に消えているように見える。
それでは、ひとつひとつ対処方法を考えて見ましょう。
このサンプルでは、自機を移動するのにKeyListnerをインプリメントしてkeyPressedメソッドにキー入力が行われた時の 処理を記述しています。ちょっとその部分だけ抜き出してみます(下記参照)
■弾クラス (Bullet.java)
   ...  
    8.  public class ShootGame extends JApplet implements KeyListener {
   ...  
   ...  
   ...  
   65.    public void keyPressed(KeyEvent e) {
   66.      if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
   67.        gun.moveRightGun();
   68.      } else if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
   69.        gun.moveLeftGun();
   70.      } else if (e.getKeyCode() == KeyEvent.VK_SPACE ) {
   71.        bullet = bullet == null ? new Bullet(gun.getGun().x, gun.getGun().y) : bullet;
   72.      }
   73.      repaint();
   74.    }
   ...  
   ...  
   ...  
キーが押された場合keyPressedメソッドが呼び出されメソッド内でどのキーが押されたか判定しています。 どのキーが押されたかというのは、keyPressedの引数であるKeyEventオブジェクトが保持しているキーコード から取得します。66、68、70行目のe.getKeyCode()と記述されている部分が押されているキーコードを取得している部分になります。 自機を移動しているときは、「←」または、「→」キーが押されていてe.getKeyCodeの値は、「←」または、「→」のキーコードとなります。 しかし、弾の発射でスペースキーを押すとe.getKeyCodeの値は、スペースキーのキーコードになり67または69行目の自機移動処理は、実行されなくなります。
。。とまぁこんな原因で止まってしまうのではないかと思います。
では、どうやって解決するか。。。
解決策は、考えればそれこそ無数にあると思うのですが、ここでは、下のように対処したいと思います。
・自機クラスに移動方向に関する変数と変数設定用メソッドを持たせる。
・自機クラスに移動メソッドを持たせる。移動メソッドでは、移動方向変数によって処理を振り分けるようにする。
・アプレットクラスで「←」または、「→」キーが押された場合、自機オブジェクトの移動方向変数をそれぞれの方向を表す状態に設定する。
・アプレットクラスで「←」または、「→」キーが離された場合、自機オブジェクトの移動方向変数を停止状態に設定する。
では、改造!!!※赤字の部分が前回からの追加・変更点になります。
■自機クラス(Gun.java)
  1. import java.awt.Color;
  2. import java.awt.Graphics2D;
  3. import java.awt.Point;
  4. import java.awt.Polygon;
  5. public class Gun {
  6.   private Polygon p;
  7.   private int direction;
  8.   public static int STAY_HERE = 0;
  9.   public static int RIGHT_MOVE = 1;
  10.   public static int LEFT_MOVE = 2;
  11.   public Gun() {
  12.     int[] xlist = {  0,  0,  8, 13, 18, 26, 26,  0 };
  13.     int[] ylist = { 15,  5,  5,  0,  5,  5, 15, 15 };
  14.     p = new Polygon(xlist, ylist, xlist.length);
  15.     direction = STAY_HERE;
  16.   }
  17.   public Gun(int x, int y ) {
  18.     this();
  19.     for (int i=0; i < p.xpoints.length; i++ ) {
  20.       p.xpoints[i] += x;
  21.       p.ypoints[i] += y;
  22.     }
  23.   }
  24.   public void draw(Graphics2D g2) {
  25.     g2.setColor(Color.YELLOW);
  26.     g2.fill(p);
  27.     g2.setColor(Color.BLACK);
  28.     g2.draw(p);
  29.   }
  30.   private void moveLeftGun() {
  31.     for (int i=0; i < p.xpoints.length; i++ ) {
  32.       p.xpoints[i] -= 5;
  33.     }
  34.   }
  35.   private void moveRightGun() {
  36.     for (int i=0; i < p.xpoints.length; i++ ) {
  37.       p.xpoints[i] += 5;
  38.     }
  39.   }
  40.   public void move() {
  41.     if (direction == RIGHT_MOVE ) {
  42.       moveRightGun();
  43.     } else if ( direction == LEFT_MOVE ) {
  44.       moveLeftGun();
  45.     }
  46.   }
  47.   public void setGun(){
  48.   }
  49.   public Point getGun(){
  50.     return new Point(p.xpoints[0],p.ypoints[0]);  
  51.   }
  52.   public void setDirection(int direction) {
  53.     this.direction = direction;
  54.   }
  55. }
9行目は、移動方向を保持する変数を定義しています。
10行目〜12行目は、移動方向を表す定数の定義になります。
順に停止状態、右移動状態、左移動状態を表しています。
18行目、ゲーム開始時は、停止状態で初期化しています。
36行目、42行目、右移動メソッドおよび左移動メソッドは、他のクラスから 呼び出さなくなったためメソッドのアクセス範囲を自クラスのみ(private)に変更しました。
48行目〜54行目、移動方向を保持する変数により右移動メソッドまたは、左移動メソッドを呼び出し自機の表示位置を変化させます。
64行目〜66行目、移動方向を設定します。KeyListnerをインプリメントしたクラス(ShootGame.java)より呼び出されキー入力状態により設定されます。

■アプレットクラス(ShootGame.java)
  1. import java.awt.Graphics;
  2. import java.awt.Graphics2D;
  3. import java.awt.event.KeyEvent;
  4. import java.awt.event.KeyListener;
  5. import javax.swing.JApplet;
  6. public class ShootGame extends JApplet implements KeyListener {
  7.   private static final long serialVersionUID = 1L;
  8.   public Gun gun = new Gun(87, 180);
  9.   public Bullet bullet;
  10.   public static Thread t;
  11.   public void init() {
  12.     addKeyListener(this);
  13.   }
  14.   public void start(){
  15.     t = new Thread(){
  16.       public void run(){
  17.         Thread ct = Thread.currentThread();
  18.         while( t == ct ){
  19.           try {
  20.             Thread.sleep(10);
  21.             repaint();
  22.           } catch(Exception e) {
  23.             e.printStackTrace();  
  24.           }
  25.         }
  26.       }
  27.     };
  28.     t.start();
  29.   }
  30.   public void paint(Graphics g) {
  31.     Graphics2D g2 = (Graphics2D)g;
  32.     g2.clearRect(0,0,getWidth(), getHeight());
  33.     gun.move();
  34.     gun.draw(g2);
  35.     if ( bullet != null ) {
  36.       if ( bullet.getBulletY() > 0 ) {
  37.         bullet.draw(g2);
  38.         bullet.setBulletY(bullet.getBulletY() - 5 );
  39.       } else {
  40.         bullet = null;
  41.       }
  42.     }
  43.   }
  44.   public void update(Graphics g){
  45.     paint(g);
  46.   }
  47.   public void destroy() {
  48.     t = null;
  49.   }
  50.   public void keyPressed(KeyEvent e) {
  51.     if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
  52.       gun.setDirection(Gun.RIGHT_MOVE);
  53.     } else if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
  54.       gun.setDirection(Gun.LEFT_MOVE);
  55.     } else if (e.getKeyCode() == KeyEvent.VK_SPACE ) {
  56.       bullet = bullet == null ? new Bullet(gun.getGun().x, gun.getGun().y) : bullet;
  57.     }
  58.     //repaint();←この行は、削除
  59.   }
  60.   public void keyReleased(KeyEvent e) {
  61.     if ( e.getKeyCode() == KeyEvent.VK_RIGHT || 
  62.         e.getKeyCode() == KeyEvent.VK_LEFT ) {
  63.       gun.setDirection(Gun.STAY_HERE);
  64.     }
  65.   }
  66.   public void keyTyped(KeyEvent e) {
  67.   }
  68. }
46行目、自機を移動します。右または、左への移動が設定されていれば自機がそれぞれの方向へ移動することになります。
68、70行目、「←」または、「→」キーに応じて自機オブジェクトに移動方向の設定を行います。
78〜81行目、keyReleasedメソッドは、キーが離された時に呼び出されます。このメソッド内で離されたキーの判定を行い、「←」キーまたは、「→」キー だった場合、自機オブジェクトを停止状態に設定します。

■弾クラス(Bullet.java)
弾クラスは、前回と同じです。変更はありません。
 →前回分を見たい方はここをクリック

下記のボタンを押すと今回のプログラムを実行してみることが出来ます。
※実行は、別ウィンドウで開きます。実行には時間がかかることがありますのでご注意ください。




最終更新日:2019/02/13

2015-03-01からの訪問者数
  403 人