我一直在做一个突破游戏,除了砖块碰撞之外,几乎所有事情都完成了。球在墙上弹跳并划桨很好,但是当涉及到砖块时,它会直接穿过它们。我很确定问题出在主类的 checkBrick() 部分,但不知道该怎么办。
主类:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.applet.*;
import java.util.Random;
import javax.swing.JOptionPane;
public class Breakout extends Applet implements Runnable {
Ball ball = new Ball();
Paddle paddle = new Paddle(135, 375);
Brick[] brick = new Brick[50];
private int bX[] = new int[50];
private int bY[] = new int[50];
private int bW[] = new int[50];
private int bH[] = new int[50];
Thread t;
Random trajectory = new Random();
boolean lose;
Image buffer = null;
// The life cycle of the Applet
// Sets up window
public void init() {
setSize(377, 500);
buffer = createImage(377, 500);
// setBackground(Color.black);
System.out.println("init()");
}
public void start() {
if (t == null) {
t = new Thread(this);
t.start();
}
System.out.println("start()");
}
public void run() {
System.out.println("run()");
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (!lose) {
ball.move();
paddle.move();
checkWall();
checkPaddle();
checkBrick();
ball.move();
repaint();
try {
Thread.sleep(30);
} catch (InterruptedException ex) {
}
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
}
JOptionPane.showMessageDialog(null, "Game Over");
System.out.println("Termintated");
System.exit(0);
}
public void stop() {
System.out.println("stop()");
}
public void destroy() {
System.out.println("destroy()");
}
public void paint(Graphics g) {
Graphics screen = null;
screen = g;
g = buffer.getGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, 377, 500);
createBricks(g);
createPaddle(g);
createBall(g);
screen.drawImage(buffer, 0, 0, this);
}
public void update(Graphics g) {
paint(g);
}
private void createBricks(Graphics g) {
int brickIndex = 0;
int brickX = 15, brickY = 160;
int brickW = 30, brickH = 10;
for (int i = 0; i <= 4; i++) {
brickX = 15;
brickY -= 20;
for (int n = 0; n < 10; n++) {
brick[brickIndex] = new Brick();
brick[brickIndex].setBounds(brickX, brickY, brickW, brickH);
bX[brickIndex] = brick[brickIndex].x();
bY[brickIndex] = brick[brickIndex].y();
bW[brickIndex] = brick[brickIndex].w();
bH[brickIndex] = brick[brickIndex].h();
brick[brickIndex].setColor(i);
brick[brickIndex].paint(g);
brickIndex++;
brickX += 35;
}
}
}
private void createPaddle(Graphics g) {
paddle.paint(g);
}
private void createBall(Graphics g) {
ball.paint(g);
}
private void checkWall() {
// If ball hits right wall it will bounce
if ((ball.getX() + ball.getR()) >= 380) {
ball.setVX(trajectory.nextInt(2) + -3);
}
// If ball hits left wall it will bounce
if ((ball.getX() - ball.getR()) < -10) {
ball.setVX(trajectory.nextInt(4) + 1);
}
// If ball hits ceiling it will bounce
if ((ball.getY() + ball.getR()) < 12)
ball.setVY(trajectory.nextInt(5) + 1);
// If ball goes through floor it will subtract a life
if ((ball.getY() + ball.getR()) > 515)
lose = true;
}
private void checkBrick() {
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
if ((ball.getX() + ball.getR()) < (tempX + tempW)
&& (ball.getX() + ball.getR()) >= tempX) {
if ((ball.getY() + ball.getR()) > (tempY + tempH)
&& (ball.getY() + ball.getR()) <= tempY) {
System.out.println("Brick " + i + " has been hit.");
}
}
}
}
private void checkPaddle() {
// Check for paddle
if ((ball.getX() + ball.getR()) < (paddle.getX() + 100)
&& (ball.getX() + ball.getR()) >= paddle.getX() + 5) {
if ((ball.getY() + ball.getR()) > (paddle.getY() - 5)
&& (ball.getY() + ball.getR()) <= (paddle.getY() + 5)) {
ball.setVX((trajectory.nextInt(7) + -2) + 1);
ball.setVY(trajectory.nextInt(1) + -3);
}
}
}
// Key Detectors
public boolean keyDown(Event e, int key) {
if (key == Event.RIGHT) {
paddle.setVX(0);
if ((paddle.getX() + 100) < 377)
paddle.setVX(10);
}
if (key == Event.LEFT) {
paddle.setVX(0);
if (paddle.getX() > 0)
paddle.setVX(-10);
}
return true;
}
// To make sure it doesn't just keep moving one way
public boolean keyUp(Event e, int key) {
paddle.setVX(0);
return true;
}
}
球类:
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
public class Ball
{
private int x, y; //Position
private int vx, vy; //Velocity
private int r; //radius
//constructor
public Ball()
{
x = 177;
y = 315;
vx = 0;
vy = 5;
r = 15;
}
public void paint(Graphics g)
{
g.setColor(Color.white);
g.fillOval(x, y, r, r);
}
//returns the x of origin
public int getX()
{
return x;
}
//returns the y of origin
public int getY()
{
return y;
}
public int getVX()
{
return vx;
}
//returns the y of origin
public int getVY()
{
return vy;
}
//returns the radius r of the ball
public int getR()
{
return r;
}
//sets the velocity of x to a different value
public void setVX(int vx)
{
this.vx = vx;
}
//sets the velocity of y to a different value
public void setVY(int vy)
{
this.vy = vy;
}
//sets the x value
public void setX(int x)
{
this.x = x;
}
//sets the y value
public void setY(int y)
{
this.y = y;
}
//starts making the ball move by changing its coords
public void move()
{
x+= vx;
y+= vy;
}
}
桨类:
import java.awt.Color;
import java.awt.Graphics;
public class Paddle {
// declares variables for x and y coordinates
int x, y;
//The velocity of to move paddle
int vx;
// constructor that takes in x and y coordinates for paddle
public Paddle(int x, int y)
{
this.x = x;
this.y = y;
}
public void paint(Graphics g)
{
// paints paddle
g.setColor(Color.WHITE);
g.fillRect(x, y, 100, 15);
g.setColor(Color.GREEN);
g.drawRect(x, y, 100, 15);
}
// gets x coordinate of paddle
public int getX() {
return x;
}
// sets x coordinate of paddle
public void setX(int x) {
this.x = x;
}
// gets y coordinate of paddle
public int getY() {
return y;
}
// sets y coordinate of paddle
public void setY(int y) {
this.y = y;
}
public void setVX(int vx)
{
this.vx = vx;
}
//Moves the paddle
public void move()
{
x+=vx;
}
}
砖类:
import java.awt.Color;
import java.awt.Graphics;
public class Brick
{
private Color color =(Color.cyan);
private int x, y, w, h;
public Brick()
{
//Garbage values that are there just for declaration
x = 0;
y = 0;
w = 10;
h = 10;
}
//Sets color for the brick
public void setColor(int paintC)
{
switch(paintC)
{
case 0:
color = (Color.magenta);
break;
case 1:
color = (Color.blue);
break;
case 2:
color = (Color.yellow);
break;
case 3:
color = (Color.orange);
break;
default:
color = (Color.red);
break;
}
}
//Sets the location then size of the brick
public void setBounds(int x, int y, int w, int h)
{
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
//returns x value
public int x()
{
return this.x;
}
//returns y value
public int y()
{
return this.y;
}
//returns width value
public int w()
{
return this.w;
}
//returns height value
public int h()
{
return this.h;
}
//Sets x for the brick
public void setX(int x)
{
this.x = x;
}
//Sets y for the brick
public void setY(int y)
{
this.y = y;
}
public void setW(int w)
{
this.w = w;
}
public void setH(int h)
{
this.h = h;
}
public void paint(Graphics g)
{
g.setColor(color);
g.fillRect(x, y, w, h);
g.setColor(Color.green);
g.drawRect(x, y, w, h);
}
}
我已经开始浏览您的代码,坦率地说,我懒得弄清楚您的逻辑,但我相信您试图推断的是砖是否"包含"球,而不是球是否与砖相交。
你不在乎有多少球或砖块相交,只要它们相交......例如。。。
private void checkBrick() {
int tx = ball.getX();
int ty = ball.getY();
int tw = ball.getR();
int th = ball.getR();
tw += tx;
th += ty;
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
int rw = tempW + tempX;
int rh = tempH + tempY;
// overflow || intersect
if ((rw < tempX || rw > tx) &&
(rh < tempY || rh > ty) &&
(tw < tx || tw > tempX) &&
(th < ty || th > tempY)) {
System.out.println("Hit");
}
}
}
现在,我从Rectangle#intersects
那里偷来
基本上,如果您使用 2D 图形 API 中的几何类,则可以将其简化为...
private void checkBrick() {
Rectangle b = new Rectangle(ball.getX(), ball.getY(), ball.getR(), ball.getR());
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
Rectangle brick = new Rectangle(tempX, tempY, tempW, tempH);
System.out.println("brick = " + brick);
if (b.intersects(brick)) {
System.out.println("Break");
}
}
}
而且,是的,我确实运行了您的代码
问题是方法checkBrick()
没有改变任何东西,它只是打印球是否与砖块发生碰撞。
您可能希望更改Ball
速度,就像您在 checkWall()
和 checkPaddle()
中所做的那样。
private void checkBrick() {
for (int i = 0; i < 50; i++) {
...
if (...) {
ball.setVX(...); // Add these lines setting the correct values
ball.setVY(...);
}
}
}
您可能还需要检查您的if-conditions
是否正确,并执行您的预期操作。
假设tempH
是正数,
((ball.getY() + ball.getR()) > (tempY + tempH)
&& (ball.getY() + ball.getR()) <= tempY)
永远不可能是真的。 >
需要<
,<=
需要>=
。
此外,如果砖块被击中,您需要采取某种行动,而不仅仅是打印出事实。 对不起,我不确定会发生什么 - 砖块会消失吗? 还是球弹跳? 还是两者兼而有之?
第二个答案(除了我认为也是一个问题的其他答案),你的逻辑是问球是否包含在砖块中,但是当你创建球时,它的半径大于砖的高度,所以即使纠正这个逻辑也不能解决问题。
你应该重构你的代码,让它像自然语言一样读出来,这将对调试有很大帮助(或者首先编写更少的错误!),即
在砖类中:
public int bottom()
{
return y;
}
public int top()
{
return y + h;
}
在球类中:
public int bottom()
{
return y - r;
}
public int top() {
return y + r;
}
然后在主类中:
private boolean withinY(brick) {
return (ball.bottom => brick.bottom() && ball.top =< brick.top());
}
然后逻辑读起来更好(伪):
foreach brick in wall {
if (ball.withinY(brick) and ball.withinX(brick))
BAM!!
}
你正在检查球是否在砖块的左侧和右侧之间,但随后检查球是否在砖块的上方和下方,因为你的大于和小于混淆了。此外,球的中心需要从其 Y 位置减去。
if ((ball.getY() + ball.getR()) **>** (tempY + tempH) &&
(ball.getY() **+** ball.getR()) **<=** tempY)
可能是
if ((ball.getY() + ball.getR()) < (tempY + tempH) &&
(ball.getY() - ball.getR()) >= tempY)
但我建议找出球的顶部是否在砖的顶部和底部之间,或者球的底部是否在砖的顶部和底部之间:
if (((ball.getY() + ball.getR()) < (tempY + tempH) && (ball.getY() - ball.getR()) >= tempY)) ||
((ball.getY() - ball.getR()) < (tempY + tempH) && (ball.getY() - ball.getR()) >= tempY))) {
CODE
}
并使用类似的逻辑在砖的左右两侧之间进行查找