按下其他键时,键未注册

时间:2015-05-19 17:30:25

标签: java swing keylistener

我正在重建小行星,宇宙飞船可以向前和向后移动并改变它的旋转。例如,当我向前移动时,速度会持续增加,直到我释放前进键。但是当我按下旋转左键时,它也会停止增加速度。我不明白为什么会这样做,我希望能够在增加或减少我的速度的同时增加旋转度(即按下向上或向下箭头)。当我拍摄时它也会停止向前移动或旋转(即空格键)。

另外,我的代码是否可读且是否适合OO?

小行星:

import javax.swing.*;

public class Asteroids {

    public static void createAndShowGui() {
        GamePanel gamePanel = new GamePanel();
        JFrame frame = new JFrame("Asteroids");
        frame.getContentPane().add(gamePanel);
        frame.pack();
        frame.setVisible(true);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocation(2000, 50);
        gamePanel.requestFocusInWindow();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }

}

GamePanel.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

public class GamePanel extends JPanel implements ActionListener {

    private final int WIDTH = 1600;
    private final int HEIGHT = 900;

    private ArrayList<Rock> rocks;
    private ArrayList<Bullet> bullets;
    private SpaceShip spaceShip;
    private boolean keyHeld;
    private int keyCode;

    public GamePanel() {
        setPreferredSize(new Dimension(WIDTH, HEIGHT));

        setUp();
    }

    public void setUp() {
        Timer animationTimer = new Timer(15, this);

        spaceShip = new SpaceShip(WIDTH, HEIGHT);
        bullets = new ArrayList<>();
        rocks = new ArrayList<>();

        addKeyListener(new KeyListener());

        for (int i = 0; i < 12; i++) {
            rocks.add(new Rock(WIDTH, HEIGHT));
        }

        animationTimer.start();
    }

    class KeyListener extends KeyAdapter {
        @Override
        public void keyPressed(KeyEvent e) {
            keyCode = e.getKeyCode();
            keyHeld = true;
        }

        @Override
        public void keyReleased(KeyEvent e) {
            keyHeld = false;
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        checkRockCollisions();

        for (int i = 0; i < bullets.size(); i++)
            checkBulletOffScreen(bullets.get(i));

        spaceShip.checkForCollisionWithFrame(WIDTH, HEIGHT);

        moveObjects();

        checkForPressedKeys();

        repaint();
    }

    public void moveObjects() {
        for (Rock rock : rocks)
            rock.moveForward();

        for (Bullet bullet : bullets)
            bullet.moveForward();

        spaceShip.moveSpaceShip();
    }

    public void checkRockCollisions() {
        for (int i = 0; i < rocks.size(); i++) {
            Rock rock = rocks.get(i);

            rocks.stream().filter(rockToCheck -> !rock.equals(rockToCheck)).forEach(rock::checkRockCollision);

            for (int j = 0; j < bullets.size(); j++) {
                Bullet bullet = bullets.get(j);
                if (rock.checkBulletCollision(bullet)) {
                    rocks.remove(rock);
                    bullets.remove(bullet);
                }
            }

            if (rock.checkSpaceShipCollision(spaceShip))
                resetSpaceShip();

            rock.checkFrameCollision(WIDTH, HEIGHT);
        }
    }

    public void checkBulletOffScreen(Bullet bullet) {
        if (bullet.getxPos() + bullet.getBulletWidth() < 0 || bullet.getxPos() > WIDTH || bullet.getyPos() + bullet.getBulletHeight() < 0 || bullet.getyPos() > HEIGHT)
            bullets.remove(bullet);
    }

    public void resetSpaceShip() {
        spaceShip = new SpaceShip(WIDTH, HEIGHT);
    }

    public void checkForPressedKeys() {
        if (keyHeld) {
            switch (keyCode) {
                case KeyEvent.VK_RIGHT:
                    spaceShip.increaseRotationDegree();
                    break;
                case KeyEvent.VK_LEFT:
                    spaceShip.decreaseRotationDegree();
                    break;
                case KeyEvent.VK_UP:
                    spaceShip.increaseForwardVelocity();
                    break;
                case KeyEvent.VK_DOWN:
                    spaceShip.decreaseForwardVelocity();
                    break;
                case KeyEvent.VK_SPACE:
                    bullets.add(new Bullet(spaceShip.getxPos() + spaceShip.getSpaceShipRadius(), spaceShip.getyPos() + spaceShip.getSpaceShipRadius(), spaceShip.getRotationDegree()));
                    keyHeld = false;
                    break;
            }
        }
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        RenderingHints mainRenderingHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHints(mainRenderingHints);

        for (Rock rock : rocks)
            rock.display(g2d);
        for (Bullet bullet : bullets)
            bullet.display(g2d);
        spaceShip.display(g2d);

        g2d.dispose();
    }
}

SpaceShip.java

import java.awt.*;

public class SpaceShip {

    private double xPos;
    private double yPos;
    private double xVelocity;
    private double yVelocity;
    private int spaceShipDiameter;
    private int rotationDegree;
    private int spaceShipRadius;

    public SpaceShip(final int WIDTH, final int HEIGHT) {
        spaceShipDiameter = 30;
        spaceShipRadius = spaceShipDiameter / 2;
        xPos = WIDTH / 2 - spaceShipRadius;
        yPos = HEIGHT / 2 - spaceShipRadius;
        rotationDegree = 0;
    }

    public int getSpaceShipRadius() {
        return spaceShipRadius;
    }
    public double getxPos() {
        return xPos;
    }
    public double getyPos() {
        return yPos;
    }
    public int getRotationDegree() {
        return rotationDegree;
    }

    public void increaseForwardVelocity() {
        xVelocity += 0.04 * Math.sin(Math.toRadians(this.rotationDegree));
        yVelocity += 0.04 * -Math.cos(Math.toRadians(this.rotationDegree));
    }

    public void decreaseForwardVelocity() {
        xVelocity -= 0.04 * Math.sin(Math.toRadians(this.rotationDegree));
        yVelocity -= 0.04 * -Math.cos(Math.toRadians(this.rotationDegree));
    }

    public void moveSpaceShip() {
        this.xPos += xVelocity;
        this.yPos += yVelocity;
    }

    public void increaseRotationDegree() {
        if (rotationDegree >= 350)
            rotationDegree = 0;
        else
            rotationDegree+=10;
    }

    public void decreaseRotationDegree() {
        if (rotationDegree <= 0)
            rotationDegree = 350;
        else
            rotationDegree-=10;
    }

    public void checkForCollisionWithFrame(final int WIDTH, final int HEIGHT) {
        if (xPos + spaceShipDiameter < 0)
            xPos = WIDTH;
        else if (xPos > WIDTH)
            xPos = 0 - spaceShipDiameter;
        else if (yPos + spaceShipDiameter < 0)
            yPos = HEIGHT;
        else if (yPos > HEIGHT)
            yPos = 0 - spaceShipDiameter;
    }

    public void display(Graphics2D g2d) {
        g2d.setColor(Color.BLACK);
        g2d.rotate(Math.toRadians(rotationDegree), xPos + spaceShipRadius, yPos + spaceShipRadius);
        g2d.fillOval((int) xPos, (int) yPos, spaceShipDiameter, spaceShipDiameter);

        g2d.setColor(Color.YELLOW);
        g2d.drawLine((int) xPos + spaceShipRadius, (int) yPos , (int) xPos + spaceShipRadius, (int) yPos + spaceShipRadius);
    }
}

Rock.java

import java.awt.*;
import java.util.Random;

public class Rock {

    private int xPos;
    private int yPos;
    private int rockDiameter;
    private int xVelocity;
    private int yVelocity;
    private int rockRadius;
    private Color rockColor;

    public Rock(int WIDTH, int HEIGHT) {
        Random r = new Random();
        rockDiameter = r.nextInt(40) + 30;
        rockRadius = rockDiameter / 2;
        xPos = r.nextInt(WIDTH - rockDiameter);
        yPos = r.nextInt(HEIGHT - rockDiameter);
        xVelocity = r.nextInt(6) - 3;
        yVelocity = r.nextInt(6) - 3;
        rockColor = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
    }

    public void moveForward() {
        xPos += xVelocity;
        yPos += yVelocity;
    }

    public void checkRockCollision(Rock rock) {
        if (calculateDistances(rock.xPos, rock.yPos, rock.rockRadius))
            switchVelocities(rock);
    }

    public void switchVelocities(Rock rock) {
        int tempXVelocity = this.xVelocity;
        int tempYVelocity = this.yVelocity;

        this.xVelocity = rock.xVelocity;
        this.yVelocity = rock.yVelocity;

        rock.xVelocity = tempXVelocity;
        rock.yVelocity = tempYVelocity;
        moveForward();
        rock.moveForward();
    }

    public boolean checkBulletCollision(Bullet bullet) {
        return calculateDistances(bullet.getxPos(), bullet.getyPos(), bullet.getBulletRadius());
    }

    public boolean checkSpaceShipCollision(SpaceShip spaceShip) {
        return calculateDistances(spaceShip.getxPos(), spaceShip.getyPos(), spaceShip.getSpaceShipRadius());
    }

    public boolean calculateDistances(double objectxPos, double objectyPos, int objectRadius) {
        int radiusOfBoth = objectRadius + rockRadius;
        double horDistance = Math.abs((objectxPos + objectRadius) - (xPos + rockRadius));
        double verDistance = Math.abs((objectyPos + objectRadius) - (yPos + rockRadius));
        double diagDistance = Math.sqrt(Math.pow(horDistance, 2) + Math.pow(verDistance, 2));

        return diagDistance <= radiusOfBoth;
    }

    public void checkFrameCollision(final int WIDTH, final int HEIGHT) {
        if (xPos < 0) {
            xVelocity *= -1;
            xPos = 0;
        } else if (xPos + rockDiameter > WIDTH) {
            xVelocity *= -1;
            xPos = WIDTH - rockDiameter;
        } else if (yPos < 0) {
            yVelocity *= -1;
            yPos = 0;
        } else if (yPos + rockDiameter > HEIGHT) {
            yVelocity *= -1;
            yPos = HEIGHT - rockDiameter;
        }
    }

    public void display(Graphics2D g2d) {
        g2d.setColor(rockColor);
        g2d.fillOval(xPos, yPos, rockDiameter, rockDiameter);
    }
}

Bullet.java

import java.awt.*;

public class Bullet {

    private double xPos;
    private double yPos;
    private int bulletWidth;
    private int bulletHeight;
    private double xVelocity;
    private double yVelocity;
    private int bulletRadius;

    public Bullet(double startingXPos, double startingYPos, int rotationDegree) {
        bulletHeight = 10;
        bulletWidth = 10;
        bulletRadius = bulletWidth / 2;
        xPos = startingXPos - bulletRadius;
        yPos = startingYPos - bulletRadius;
        xVelocity = 5 * Math.sin(Math.toRadians(rotationDegree));
        yVelocity = 5 * -Math.cos(Math.toRadians(rotationDegree));
    }

    public void moveForward() {
        this.xPos += xVelocity;
        this.yPos += yVelocity;
    }

    public double getxPos() {
        return xPos;
    }
    public double getyPos() {
        return yPos;
    }
    public int getBulletWidth() {
        return bulletWidth;
    }
    public int getBulletHeight() {
        return bulletHeight;
    }
    public int getBulletRadius() {
        return bulletRadius;
    }

    public void display(Graphics2D g2d) {
        g2d.setColor(Color.GREEN);
        g2d.fillOval((int) xPos, (int) yPos, bulletWidth, bulletHeight);
    }
}

1 个答案:

答案 0 :(得分:1)

您只跟踪最近按下的键。相反,您需要跟踪被按下的每个键。一种方法是通过为每个键使用布尔变量。在keyPressed()函数中,将相应的布尔值设置为true,并在keyReleased()函数中将其设置为false。然后在你的游戏循环中,只需检查哪些布尔值是真的并采取适当的行动。