我正在使用 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/