2017-01-21 6 views
-1

私は、インベーダーを1つだけ使用してスペースインベーダーゲームを作成しています。画像は吃音で、時間の10%しか視認できません。私のコードで何が間違っていますか?グラフィックス・スタッター・イン・ジャワ(スペースインベーダー)

package spaceinvader; 

import javax.swing.*; 
import java.awt.event.*; 

import java.awt.*; 

public class spaceInvaders extends JApplet implements KeyListener, ActionListener 
{ 
//Declare components and variables 

JPanel mainPanel = new JPanel(); 
ImageIcon carImage = new ImageIcon("ship.png"); 
ImageIcon invaderImage = new ImageIcon("invader.png"); 

int intPosX = 240; 
int intPosY = 330; 
int intXAmount = 15; 
boolean shipMoveLeft = false; 
boolean shipMoveRight = false; 
Timer shipTimer = new Timer(100,this); 

int intBulletX = -50; 
int intBulletY = -50; 
boolean bulletMove = false; 
boolean bulletActive = false; 
Timer bulletTimer = new Timer(50,this); 

int intInvaderX = 0; 
int intInvaderY = 0; 
int invaderXAmount = 10; 
boolean invaderMove = true; 
Timer invaderTimer= new Timer(1000,this); 

public void init() 
{ 
    addKeyListener(this); 
    setFocusable(true); 

    resize(600,400); 
    setContentPane(mainPanel); 

    shipTimer.start(); 
    bulletTimer.start(); 
    invaderTimer.start(); 
} 

public void actionPerformed(ActionEvent e) 
{ 
    requestFocus(); 
    if(shipMoveLeft) 
     intPosX += intXAmount; 
    else if(shipMoveRight) 
     intPosX -= intXAmount; 
    if(bulletMove && bulletActive){ 
     intBulletY -= 15; 
     if(intBulletY <= -50){ 
      bulletMove = false; 
      bulletActive = false; 
     } 
    } 
    if(invaderMove){ 
     intInvaderX += invaderXAmount; 
     if(intInvaderX > getWidth() - 60 || intInvaderX < 0){ 
      intInvaderY += 40; 
      invaderXAmount *= -1; 
     } 
    } 
    repaint(); 
} 

public void keyPressed(KeyEvent e) 
{ 
    int key = e.getKeyCode(); 
    if (key == 37){ 
     shipMoveRight = true; 
    } 
    else if (key == 39){ 
     shipMoveLeft = true; 
    } 
    else if (key == 32){ 
     if(bulletActive == false){ 
      intBulletX = intPosX; 
      intBulletY = intPosY; 
     } 
     bulletMove = true; 
     bulletActive = true; 
    } 
} 

public void keyReleased(KeyEvent e) 
{ 
    shipMoveLeft = false; 
    shipMoveRight = false; 
} 

public void keyTyped(KeyEvent e) 
{ 

} 

public void paint(Graphics gr) 
{ 
    super.paint(gr); 

    gr.setColor(Color.red); 
    gr.fillOval(intBulletX, intBulletY, 10, 25); 

    carImage.paintIcon(this,gr, intPosX, intPosY); //Draw image in new spot 

    invaderImage.paintIcon(this,gr, intInvaderX, intInvaderY); 
} 
} 
+0

に役立ちます願っていますが、いずれかを使用、すべて同じのActionListenerにリンクされている3つのタイマーを必要としませんモデルが各tiの何をするのかを決定できるようにするck。エンティティのデルタを変更して速度を変更します。ペイントの代わりにpaintComponentをオーバーライドすることをお勧めします。 – MadProgrammer

+1

ペイントをカスタムコンポーネントに移動すると、mainPanelとオーバーライドされたペイントメソッドが互いに干渉する可能性があります。 – MadProgrammer

+0

BufferedImageがよりよくなる可能性があります。ImageIcon – MadProgrammer

答えて

3

だからすぐに飛び出し、多くの問題...

  • アプレットは行き止まりですありますが、ほとんどのブラウザは、積極的にそれらをブロックしますおよび/またはプラグインのサポートを落としている
  • アプレットにJPanelを追加していますが、アプレットのpaintメソッドをオーバーライドすると、ペイントが機能するため、パネルはアプレットとは独立してペイントされ、ペイントされたものをペイントできます。
  • 複数のタイマーは必要ありません。より良いデルタ値を持っているだけです(より速く小さくなりました)
  • KeyListenerは、キーボード入力を検出するにはあまり適していませんが、かなり低いレベルであり、キーバインディングAPI

私はより多くの詳細については、Performing Custom PaintingPainting in AWT and SwingHow to Use Key Bindingsを見て持つことから始めたいです。

どのように修正しますか?最初にJPanelを基本コンテナとして使用し、それをオーバーライドしてpaintComponentとし、すべてのペイントロジックをここに配置します。

使用単一Timerアップデート

を管理するための

あり、あなたが取ることができるのアプローチの任意の数がありますが、私はゲームに行くことができるかを定義いくつかの契約を定義して起動したい

public interface GameSpace extends ImageObserver { 
    public Dimension getGameSpace(); 
    public boolean hasInput(Input input); 
} 

public interface Entity { 
    public void paint(GameSpace gameSpace, Graphics2D g2d); 
    public boolean update(GameSpace gameSpace); 

    public Rectangle getBounds(); 
} 

public abstract class AbstractEntity implements Entity { 

    private int x; 
    private int y; 

    public int getX() { 
     return x; 
    } 

    public int getY() { 
     return y; 
    } 

    public void setX(int x) { 
     this.x = x; 
    } 

    public void setY(int y) { 
     this.y = y; 
    } 

    protected abstract int getWidth(); 
    protected abstract int getHeight(); 

    public Rectangle getBounds() { 
     return new Rectangle(getX(), getY(), getWidth(), getHeight()); 
    } 

} 

public abstract class AbstractImageEntity extends AbstractEntity { 

    protected abstract BufferedImage getImage(); 

    @Override 
    protected int getWidth() { 
     return getImage().getWidth(); 
    } 

    @Override 
    protected int getHeight() { 
     return getImage().getHeight(); 
    } 

} 

これにより、キー要素の管理の一部が分離され、より柔軟な設計が可能になります。移動できるもの、できなかったもの、塗装されたもの、そうでないもの、コアエンジンをサポートするものがあります。あなたは、いくつかのコアエンティティの定義を開始できることをしたら

あなたは

public class ShipEntity extends AbstractImageEntity { 

    private BufferedImage ship; 

    public ShipEntity(GameSpace gameSpace) throws IOException { 
     ship = ImageIO.read(getClass().getResource("/resources/ship.png")); 
     setY(gameSpace.getGameSpace().height - getBounds().height); 
     setX((gameSpace.getGameSpace().width - getBounds().width)/2); 
    } 

    @Override 
    public BufferedImage getImage() { 
     return ship; 
    } 

    @Override 
    public void paint(GameSpace gameSpace, Graphics2D g2d) { 
     g2d.drawImage(ship, getX(), getY(), gameSpace); 
    } 

    @Override 
    public boolean update(GameSpace gameSpace) { 
     int x = getX(); 
     if (gameSpace.hasInput(Input.LEFT)) { 
      x -= 2; 
     }  
     if (gameSpace.hasInput(Input.RIGHT)) { 
      x += 2; 
     }  

     if (x < 0) { 
      x = 0; 
     } else if (x + getWidth() > gameSpace.getGameSpace().width) { 
      x = gameSpace.getGameSpace().width - getWidth(); 
     } 

     setX(x); 

     return true; 
    } 

} 

public class InvaderEntity extends AbstractImageEntity { 
    private BufferedImage invader; 

    public InvaderEntity() throws IOException { 
     invader = ImageIO.read(getClass().getResource("/resources/Invader.png")); 
    } 

    @Override 
    protected BufferedImage getImage() { 
     return invader; 
    } 

    @Override 
    public void paint(GameSpace gameSpace, Graphics2D g2d) { 
     g2d.drawImage(invader, getX(), getY(), gameSpace); 
    } 

    @Override 
    public boolean update(GameSpace gameSpace) { 
     return true;    
    } 

} 

public class ProjectileEntity extends AbstractEntity { 

    private int delta; 

    public ProjectileEntity(int delta) { 
     this.delta = delta; 
    } 

    @Override 
    protected int getWidth() { 
     return 10; 
    } 

    @Override 
    protected int getHeight() { 
     return 10; 
    } 

    @Override 
    public void paint(GameSpace gameSpace, Graphics2D g2d) { 
     g2d.setColor(Color.RED); 
     int width = getWidth(); 
     int height = getHeight(); 
     g2d.fillOval(getX() - width/2, getY() - height/2, width, height); 
    } 

    @Override 
    public boolean update(GameSpace gameSpace) { 
     int y = getY() + delta; 
     setY(getY() + delta); 
     return y + getHeight() >= 0 && y + getHeight() <= gameSpace.getGameSpace().height; 
    } 

} 

は基本的に、彼らは彼らの仕事を行って取得するために必要なロジックが含まれている必要があります。

最後に、あなたは今、あなたはさらに少し行くとエンティティを制御し、必要なすべての更新を行い、「エンジン」クラスを生成しますが、私は可能性が

public class GamePane extends JPanel implements GameSpace { 

    private Set<Input> inputs; 

    private Entity playerEntity; 
    private List<Entity> projectileEntities; 
    private List<Entity> invaderEntities; 

    private long timeOfLastProjectile = -1; 

    public GamePane() throws IOException { 
     setBackground(Color.BLACK); 

     inputs = new HashSet<>(2); 

     playerEntity = new ShipEntity(this); 

     projectileEntities = new ArrayList<>(25); 
     invaderEntities = new ArrayList<>(25); 

     InvaderEntity invader = new InvaderEntity(); 
     invader.setX((getGameSpace().width - invader.getBounds().width)/2); 
     invader.setY((getGameSpace().height - invader.getBounds().height)/2); 

     invaderEntities.add(invader); 

     addKeyBinding(Input.LEFT, "left", KeyEvent.VK_LEFT); 
     addKeyBinding(Input.RIGHT, "right", KeyEvent.VK_RIGHT); 
     addKeyBinding(Input.SPACE, "space", KeyEvent.VK_SPACE); 

     Timer timer = new Timer(15, new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       updateState(); 
       processCollisions(); 
       repaint(); 
      } 
     }); 
     timer.start(); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(800, 800); 
    } 

    protected void updateState() { 
     playerEntity.update(this); 
     if (hasInput(Input.SPACE)) { 
      long time = System.currentTimeMillis() - timeOfLastProjectile; 
      if (time < 0 || time > 1000) { 
       timeOfLastProjectile = System.currentTimeMillis(); 
       Rectangle bounds = playerEntity.getBounds(); 
       ProjectileEntity projectile = new ProjectileEntity(-1); 
       int x = bounds.x + ((bounds.width - projectile.getWidth())/2); 
       int y = bounds.y - projectile.getHeight(); 

       projectile.setX(x); 
       projectile.setY(y); 
       projectileEntities.add(projectile); 
      } 
     } 

     for (Entity entity : invaderEntities) { 
      entity.update(this); 
     } 

     List<Entity> outOfBounds = new ArrayList<>(25); 
     for (Entity entity : projectileEntities) { 
      if (!entity.update(this)) { 
       outOfBounds.add(entity); 
      } 
     } 
     projectileEntities.removeAll(outOfBounds); 
    } 

    protected void processCollisions() { 
     Set<Entity> hitInvaders = new HashSet<>(25); 
     Set<Entity> hitProjectiles = new HashSet<>(25); 
     for (Entity invader : invaderEntities) { 
      for (Entity projectile : projectileEntities) { 
       if (projectile.getBounds().intersects(invader.getBounds())) { 
        // Maybe lots of cool explosiions 
        hitInvaders.add(invader); 
        hitProjectiles.add(projectile); 
       } 
      } 
     } 

     invaderEntities.removeAll(hitInvaders); 
     projectileEntities.removeAll(hitProjectiles); 
    } 

    protected void addKeyBinding(Input input, String name, int virtualKey) { 
     ActionMap am = getActionMap(); 
     InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW); 

     im.put(KeyStroke.getKeyStroke(virtualKey, 0, false), name + ".pressed"); 
     im.put(KeyStroke.getKeyStroke(virtualKey, 0, true), name + ".released"); 

     am.put(name + ".pressed", new KeyAction(inputs, input, true)); 
     am.put(name + ".released", new KeyAction(inputs, input, false)); 
    } 

    @Override 
    public Dimension getGameSpace() { 
     return getPreferredSize(); 
    } 

    @Override 
    public boolean hasInput(Input input) { 
     return inputs.contains(input); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 

     Graphics2D g2d = (Graphics2D) g.create(); 
     playerEntity.paint(this, g2d); 
     g2d.dispose(); 

     for (Entity entity : invaderEntities) { 
      g2d = (Graphics2D) g.create(); 
      entity.paint(this, g2d); 
      g2d.dispose(); 
     } 
     for (Entity entity : projectileEntities) { 
      g2d = (Graphics2D) g.create(); 
      entity.paint(this, g2d); 
      g2d.dispose(); 
     } 
    } 

} 

public class KeyAction extends AbstractAction { 

    private Input input; 
    private Set<Input> inputs; 
    private boolean pressed; 

    public KeyAction(Set<Input> inputs, Input input, boolean pressed) { 
     this.input = input; 
     this.inputs = inputs; 
     this.pressed = pressed; 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     if (pressed) { 
      inputs.add(input); 
     } else { 
      inputs.remove(input); 
     } 
    } 

} 

セットアップに実際のゲームのUIを必要とします怠惰な、あなたが前進することができるように開発する必要があるいくつかの基本的な概念の本当にラフなアイデアです)

、それは

+0

ダウンボートの理由を説明できるのは1つだけですか?質問に新しい下降票や近い票が追加されていないので、新しい質問は追加されていないので、質問に問題はないと仮定することができます。自分で問題を解決する方法がわからないと仮定することができます。個人的に私の答えを取っている – MadProgrammer

+0

いいえ、考えていません。私への確かな答えのようです。それに応じて投票した。 –