我是Java的新手,正在从YouTube的斯坦福讲座中学习。
所以我正在尝试他们的任务来制作一个突破游戏,到目前为止还不错。我有我所有的砖块,球和球拍,包括游戏的机制,但是当我运行游戏时,只有一块砖块在被球击中时可以移除。看到这里。那块砖恰好是添加到画布上的最后一块砖。
球只是飞过所有其他砖块,没有任何效果。相关代码如下。
我是否缺乏一些关于getElementat的重要知识?我有一种感觉,getCollidingObject没有分配给碰撞体,这使得碰撞检测出错。我希望有人能启发我!
private void addBallMotion(){
// y component of starting velocity; pixels per second
vy = 3.0;
/* x component of starting velocity; pixels per second
* which ranges according to the random generator
* can be negative or positive, ball can go left or right with equal chances
*/
vx = rgen.nextDouble(1.0, 3.0);
if (rgen.nextBoolean(0.5)){
vx = -vx;
}
while (true){
ball.move(vx, vy);
checkCollision();
pause(FPS);
}
}
private void checkCollision(){
checkWallCollision();
checkBrickAndPaddleCollision();
}
private void checkWallCollision(){
//checks for left or right collision
if ( (ball.getX() < leftBounds.getX() ) || (ball.getX() + BALL_RADIUS * 2 > rightBounds.getX()) ){
vx = -vx;
}
//checks for top or bottom collision
if ( (ball.getY() < topBounds.getY() ) || (ball.getY() + BALL_RADIUS * 2 > bottomBounds.getY()) ){
vy = -vy;
}
}
private void checkBrickAndPaddleCollision(){
GObject collider = getCollidingObject();
if (collider == brick){
remove(collider);
vy = -vy;
}
if (collider == paddle){
vy = -vy;
}
}
//check for collision at the 4 edges of the ball
//starting with the left and going clockwise
private GObject getCollidingObject(){
GObject ballLeft= getElementAt (ball.getX() - 1, ball.getY() + BALL_RADIUS);
GObject ballRight= getElementAt (ball.getX() + BALL_RADIUS * 2 + 1, ball.getY() + BALL_RADIUS);
GObject ballTop = getElementAt (ball.getX() + BALL_RADIUS * 2, ball.getY() - 1);
GObject ballBottom= getElementAt (ball.getX() + BALL_RADIUS, ball.getY() + BALL_RADIUS * 2 + 1);
if (ballLeft != null){
return (ballLeft);
}
else if (ballTop != null){
return (ballTop);
}
else if (ballRight != null){
return (ballRight);
}
else if (ballBottom != null){
return (ballBottom);
}
return (null);
}
private GRect paddle; // creates a paddle that only moves linearly according to mouses' x coordinate
private GRect brick;
private GOval ball;
private double vx, vy; // x and y components of the ball's velocity
//private GObject collider;
这是整个程序:
import acm.graphics.*;
import acm.program.*;
import acm.util.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class Breakout extends GraphicsProgram {
/** Width and height of application window in pixels */
public static final int APPLICATION_WIDTH = 400;
public static final int APPLICATION_HEIGHT = 600;
/** Dimensions of game board (usually the same) */
private static final int WIDTH = APPLICATION_WIDTH;
private static final int HEIGHT = APPLICATION_HEIGHT;
/** Dimensions of the paddle */
private static final int PADDLE_WIDTH = 60;
private static final int PADDLE_HEIGHT = 10;
/** Offset of the paddle up from the bottom */
private static final int PADDLE_Y_OFFSET = 30;
/** Number of bricks per row */
private static final int NBRICKS_PER_ROW = 10;
/** Number of rows of bricks */
private static final int NBRICK_ROWS = 10;
/** Separation between bricks */
private static final int BRICK_SEP = 4;
/** Width of a brick */
private static final int BRICK_WIDTH =
(WIDTH - (NBRICKS_PER_ROW - 1) * BRICK_SEP) / NBRICKS_PER_ROW;
/** Height of a brick */
private static final int BRICK_HEIGHT = 8;
/** Radius of the ball in pixels */
private static final int BALL_RADIUS = 10;
/** Offset of the top brick row from the top */
private static final int BRICK_Y_OFFSET = 70;
/** Offset of the side bricks from the sides of game window */
private static final int BRICK_X_OFFSET = ((WIDTH - NBRICKS_PER_ROW * (BRICK_WIDTH + BRICK_SEP) + BRICK_SEP) / 2);
/** Number of turns */
private static final int NTURNS = 3;
/** Number of frames per second */
private static final int FPS = 1;
/* Method: run() */
/** Runs the Breakout program. */
public void run() {
addMouseListeners();
addWorld();
// runGame();
}
private void addWorld(){
setSize (APPLICATION_WIDTH, APPLICATION_HEIGHT);
addPlayingBox();
addBricks();
addPaddle();
addBall();
// addCounter();
}
//adds the bound area onto screen
private void addPlayingBox(){
topBounds = new GLine (0, 0, WIDTH, 0);
bottomBounds = new GLine (0, HEIGHT, WIDTH, HEIGHT);
leftBounds = new GLine (0, 0, 0, HEIGHT);
rightBounds = new GLine (WIDTH, 0, WIDTH, HEIGHT);
add (topBounds);
add (bottomBounds);
add (leftBounds);
add (rightBounds);
}
private void addBricks(){
for (int i = 0; i < NBRICK_ROWS; i++){
int y = BRICK_Y_OFFSET + (i * (BRICK_HEIGHT + BRICK_SEP));
for (int j = 0; j < NBRICKS_PER_ROW; j++){
int x = (BRICK_X_OFFSET) + (j * (BRICK_WIDTH + BRICK_SEP));
brick = new GRect (x, y, BRICK_WIDTH, BRICK_HEIGHT );
colorBrick(brick, i);
add (brick);
}
}
}
// every consecutive 2 rows are colored the same
private void colorBrick(GRect brick, int rowNumber){
brick.setFilled (true);
switch (rowNumber + 1) {
case 1: case 2: brick.setColor(Color.red);
break;
case 3: case 4: brick.setColor(Color.orange);
break;
case 5: case 6: brick.setColor(Color.yellow);
break;
case 7: case 8: brick.setColor(Color.green);
break;
case 9: case 10:brick.setColor(Color.cyan);
break;
}
}
//adds paddle to screen
private void addPaddle(){
paddle = new GRect (PADDLE_WIDTH, PADDLE_HEIGHT);
paddle.setFilled(true);
paddle.setColor (Color.BLACK);
add (paddle);
}
//creates motion for the paddle according to mouse movement
public void mouseMoved(MouseEvent e){
paddle.setLocation ((e.getX() - PADDLE_WIDTH / 2), (double) (HEIGHT - PADDLE_Y_OFFSET));
/* checks if the paddle within the playing area
* if not the paddles will stay at the extremities*/
if ( paddle.getX() > (WIDTH - PADDLE_WIDTH)){
paddle.setLocation((double) (WIDTH - PADDLE_WIDTH), (double) (HEIGHT - PADDLE_Y_OFFSET));
}
if ( paddle.getX() < 0){
paddle.setLocation((double) 0, (double) (APPLICATION_HEIGHT - PADDLE_Y_OFFSET));
}
}
private void addBall(){
ball = new GOval (((WIDTH - BALL_RADIUS * 2) / 2), ((HEIGHT - BALL_RADIUS * 2) / 2),
BALL_RADIUS * 2, BALL_RADIUS * 2);
ball.setFilled(true);
ball.setColor(Color.BLACK);
add (ball);
addBallMotion();
}
private void addBallMotion(){
// y component of starting velocity; pixels per second
vy = 3.0;
/* x component of starting velocity; pixels per second
* which ranges according to the random generator
* can be negative or positive, ball can go left or right with equal chances
*/
vx = rgen.nextDouble(1.0, 3.0);
if (rgen.nextBoolean(0.5)){
vx = -vx;
}
while (true){
ball.move(vx, vy);
checkCollision();
pause(FPS);
}
}
private void checkCollision(){
checkWallCollision();
checkBrickAndPaddleCollision();
}
private void checkWallCollision(){
//checks for left or right collision
if ( (ball.getX() < leftBounds.getX() ) || (ball.getX() + BALL_RADIUS * 2 > rightBounds.getX()) ){
vx = -vx;
}
//checks for top or bottom collision
if ( (ball.getY() < topBounds.getY() ) || (ball.getY() + BALL_RADIUS * 2 > bottomBounds.getY()) ){
vy = -vy;
}
}
private void checkBrickAndPaddleCollision(){
GObject collider = getCollidingObject();
if (collider == brick){
remove(collider);
vy = -vy;
}
if (collider == paddle){
vy = -vy;
}
}
//check for collision at the 4 edges of the ball
//starting with the left and going clockwise
private GObject getCollidingObject(){
GObject ballLeft= getElementAt (ball.getX() - 1, ball.getY() + BALL_RADIUS);
GObject ballRight= getElementAt (ball.getX() + BALL_RADIUS * 2 + 1, ball.getY() + BALL_RADIUS);
GObject ballTop = getElementAt (ball.getX() + BALL_RADIUS * 2, ball.getY() - 1);
GObject ballBottom= getElementAt (ball.getX() + BALL_RADIUS, ball.getY() + BALL_RADIUS * 2 + 1);
if (ballLeft != null){
return (ballLeft);
}
else if (ballTop != null){
return (ballTop);
}
else if (ballRight != null){
return (ballRight);
}
else if (ballBottom != null){
return (ballBottom);
}
return (null);
}
private GRect paddle; // creates a paddle that only moves linearly according to mouses' x coordinate
private GRect brick;
private GOval ball;
private double vx, vy; // x and y components of the ball's velocity
private RandomGenerator rgen = RandomGenerator.getInstance();
//private GObject collider;
private GLine topBounds; // creates a bounding box that is the playing area
private GLine bottomBounds;
private GLine leftBounds;
private GLine rightBounds;
}
完全符合我的想法。看 - 您的类中有一个名为 brick
的字段。它是GRect
类型。一开始你调用addWorld()
方法,该方法调用addBricks()
。现在检查你写了什么:
private void addBricks(){
for (int i = 0; i < NBRICK_ROWS; i++){
int y = BRICK_Y_OFFSET + (i * (BRICK_HEIGHT + BRICK_SEP));
for (int j = 0; j < NBRICKS_PER_ROW; j++){
int x = (BRICK_X_OFFSET) + (j * (BRICK_WIDTH + BRICK_SEP));
brick = new GRect (x, y, BRICK_WIDTH, BRICK_HEIGHT );
colorBrick(brick, i);
add (brick);
}
}
}
里面发生了什么?您有一个循环,其中brick
被覆盖NBRICK_ROWS * NBRICKS_PER_ROW 次,这会导致brick
字段成为屏幕上最后创建的砖块。
基本上,您正在执行类似此操作的操作:
int x;
x = 5;
x = 6;
x = 8;
// x is 8 now
在checkBrickAndPaddleCollision()
中,您只检查对撞机是否brick
。换句话说,这意味着,你正在检查它是否是最后一块砖 - 如果是,那么你把它移除。
首先,您应该创建一个砖块数组,而不仅仅是一个字段。
ArrayList<GRect> bricks;
而不是:
GRect brick;
然后在addBricks()
方法中,您应该具有:
bricks.add(new GRect (x, y, BRICK_WIDTH, BRICK_HEIGHT));
而不是:
brick = new GRect (x, y, BRICK_WIDTH, BRICK_HEIGHT );
在此之后,在 checkBrickAndPaddleCollision()
中,您不应检查:
if (collider == brick) {
remove(collider);
vy = -vy;
}
而是所有的砖块:
for(GRect brick : bricks) {
if (collider.equals(brick)) { // Note that you should rather use .equals, instead of == as Aurand stated in his comment
remove(collider);
vy = -vy;
}
}