java - 如何更改使用 Java 制作的打砖 block 游戏中球的 vector ?

标签 java angle breakout

我正在使用 Java 制作一款闯关游戏。独立的部件正在发挥作用:桨、球、砖 block 。

但是,球撞到墙壁后,球不会改变其 vector ,而是在 JFrame 窗口边缘沿着 x 轴沿直线向上移动,直到撞到窗口顶部并向下弹回从这个角落。

然后,球会卡在从左上角开始的无限来回线上,直到它接触到桨(来回),并且永远不会打破任何其他砖 block 。

如何更改代码来解决此问题?

    import java.awt.Graphics;

    public class Ball extends Sprite {

    private int xVelocity = 1, yVelocity = -1;

    // Constructor
    public Ball() {
        setWidth(Settings.BALL_WIDTH);
        setHeight(Settings.BALL_HEIGHT);
        resetPosition();

    public void resetPosition() {
        setX(Settings.INITIAL_BALL_X);
        setY(Settings.INITIAL_BALL_Y);
    }

    public void update() {
        x += yVelocity;
        y += yVelocity;

        // Bounce off left side of screen
        if(x <= 0) {
            x = 0;
            setXVelocity(-1);

        }

        // Bounce off right side of screen
        if(x >= Settings.WINDOW_WIDTH - Settings.BALL_WIDTH) {
            x =Settings.WINDOW_WIDTH;
            setXVelocity(-1);
        }

        // Bounce off top of screen
        if(y <= 0) {
            y = 0;
            setYVelocity(1);
        }

    }

    public void setXVelocity(int x) {
        xVelocity = x;
    }
    public void setYVelocity(int y) {
        yVelocity = y;
    }

    public int getXVelocity() {
        return xVelocity;   
    }
    public int getYVelocity() {
        return yVelocity;   
    }

    public void paint(Graphics g) {
        g.fillOval(x, y, Settings.BALL_WIDTH, Settings.BALL_HEIGHT);
    }
}



import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Paint;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JPanel;
import javax.swing.Timer;

public class BreakoutPanel extends JPanel implements ActionListener, KeyListener {

    static final long serialVersionUID = 2L;

    private boolean gameRunning = true;
    private int livesLeft = 3;
    private String screenMessage = "";
    private Ball ball;
    private Paddle paddle;
    private Brick bricks[];

    public BreakoutPanel(Breakout game) {

        addKeyListener(this);
        setFocusable(true);

        Timer timer = new Timer(5, this);
        timer.start();

        ball = new Ball();
        paddle = new Paddle();
        bricks = new Brick[Settings.TOTAL_BRICKS];
        createBricks();

    }

    private void createBricks() {
        int counter = 0;
        int x_space = 0;
        int y_space = 0;
        for(int x = 0; x < 4; x++) {
            for(int y = 0; y < 5; y++) {
                bricks[counter] = new Brick((x * Settings.BRICK_WIDTH) + Settings.BRICK_HORI_PADDING + x_space, (y * Settings.BRICK_HEIGHT) + Settings.BRICK_VERT_PADDING + y_space);
                counter++;
                y_space++;
            }
            x_space++;
            y_space = 0;
        }
    }

    private void paintBricks(Graphics g) {
        for(int x = 0; x < Settings.TOTAL_BRICKS; x++) {
            for(int y = 0; y < Settings.TOTAL_BRICKS; y++) {
                bricks[y].paint(g);
            }
        }
    }

    private void update() {
        if(gameRunning) {
            // TODO: Update the ball and paddle
            ball.update();
            paddle.update();
            collisions();
            repaint();
        }
    }

    private void gameOver() {
        stopGame();
        screenMessage = "Game Over!";
    }

    private void gameWon() {
        stopGame();
        screenMessage = "Congratulations! You have won!";
    }

    private void stopGame() {
        gameRunning = false;
    }

    private void collisions() {
        // Check for loss
        if(ball.y > 450) {
            // Game over
            livesLeft--;
            if(livesLeft <= 0) {
                gameOver();
                return;
            } else {
                ball.resetPosition();
                ball.setYVelocity(-1);
            }
        }

        // Check for win
        boolean bricksLeft = false;
        for(int i = 0; i < bricks.length; i++) {
            // Check if there are any bricks left
            if(!bricks[i].isBroken()) {
                // Brick was found, close loop
                bricksLeft = true;
                break;
            }
        }
        if(!bricksLeft) {
            gameWon();
            return;
        }

        // Check collisions
        if(ball.getRectangle().intersects(paddle.getRectangle())) {
            // Simplified touching of paddle
            ball.setYVelocity(-1);

        }

        for(int i = 0; i < bricks.length; i++) {
            if (ball.getRectangle().intersects(bricks[i].getRectangle())) {
                int ballLeft = (int) ball.getRectangle().getMinX();
                int ballHeight = (int) ball.getRectangle().getHeight();
                int ballWidth = (int) ball.getRectangle().getWidth();
                int ballTop = (int) ball.getRectangle().getMinY();

                Point pointRight = new Point(ballLeft + ballWidth + 1, ballTop);
                Point pointLeft = new Point(ballLeft - 1, ballTop);
                Point pointTop = new Point(ballLeft, ballTop - 1);
                Point pointBottom = new Point(ballLeft, ballTop + ballHeight + 1);

                if (!bricks[i].isBroken()) {
                    if (bricks[i].getRectangle().contains(pointRight)) {
                        ball.setXVelocity(-1);
                    } else if (bricks[i].getRectangle().contains(pointLeft)) {
                        ball.setXVelocity(1);
                    }

                    if (bricks[i].getRectangle().contains(pointTop)) {
                        ball.setYVelocity(1);
                    } else if (bricks[i].getRectangle().contains(pointBottom)) {
                        ball.setYVelocity(-1);
                    }
                    bricks[i].setBroken(true);
                }
            }
        }
    }

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

        ball.paint(g);
        paddle.paint(g);
        paintBricks(g);

        // Draw lives left
        // TODO: Draw lives left in the top left hand corner**
        if(livesLeft != 0) {
            String displayLives = Integer.toString(livesLeft);
            g.setFont(new Font("Arial", Font.BOLD, 18));
            g.drawString(displayLives, Settings.LIVES_POSITION_X, Settings.LIVES_POSITION_Y);
        }

        // Draw screen message*
        if(screenMessage != null) {
            g.setFont(new Font("Arial", Font.BOLD, 18));
            int messageWidth = g.getFontMetrics().stringWidth(screenMessage);
            g.drawString(screenMessage, (Settings.WINDOW_WIDTH / 2) - (messageWidth / 2), 
     Settings.MESSAGE_POSITION);
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT) {
            paddle.setXVelocity(-1);
        }
        if (key == KeyEvent.VK_RIGHT) {
        paddle.setXVelocity(1);
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_RIGHT) {
            paddle.setXVelocity(0);
        }
    }

    @Override
    public void keyTyped(KeyEvent arg0) {

    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        update();
    }

}

最佳答案

几年前我用 python 制作了一个类似的游戏。我为解决这个问题所做的就是让玩家通过用 Racket 的不同部分击球来控制球的方向。

如果玩家用 Racket 的绝对中心击球,那么我只会反转 vector ,就好像它击中了墙壁一样。但是,如果 Racket 的绝对边缘击中球,那么我会在其击中边缘的同一方向上增加 x 速度。您可以使效果连续,因此如果球击中边缘和中心之间的 Racket ,它会增加 x 速度,其速度将是击中绝对边缘时的一半。

这样, vector 将不断变化,球将以更有趣的方式从物体上弹开,并为玩家提供更多控制权,这样他们就不必等到球最终击中每 block 砖 block 。预定义模式。

如果您不希望球撞击 Racket 的位置以线性方式影响 x 速度,则可以使用系数或更复杂的函数。

您可以使用类似的策略来处理与砖 block 的碰撞。例如,如果球击中了砖 block 的一角,您可能不希望它像击中底部或侧面那样使用react,而是做出介于两者之间的 react 。

关于java - 如何更改使用 Java 制作的打砖 block 游戏中球的 vector ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60236842/

相关文章:

java - spring boot Autowiring 和在 Autowiring 类上使用 new 关键字的区别?

java - java中将文本转换为二进制

java - 坚持一些角度算术

java - 突破游戏(当我出局时,我希望球再次击中剩余的砖 block )

java - 按日期对图表中的 X 轴进行排序 - JavaFX

java - 已用、已提交和最大堆内存的差异

ios - 我想在 iOS 中按角度旋转图像

c++ - 俯仰偏航,角度独立

java - Java 使用 .intersection 进行矩形和圆形碰撞

java - 测试颜色是否相等