Gerald
Gerald

Reputation: 597

How do I refer to a specific object?

private void addBricks(){
    for (int i = 0; i < NBRICK_ROWS; i++){
        for (int j = 0; j < NBRICKS_PER_ROW; j++){

            int y = BRICK_Y_OFFSET + (i * (BRICK_HEIGHT + BRICK_SEP));
            int x = (BRICK_X_OFFSET) + (j * (BRICK_WIDTH + BRICK_SEP));
            brick = new GRect (x, y, BRICK_WIDTH, BRICK_HEIGHT );
            add (brick);
        }
    }
}

I am trying to make a breakout game here and this is a snippet of code.

I have added a set of rectangles to my canvas. Later in my program I would like to remove some of them when the ball hits them. The problem is that I do not know how to refer to them specifically. That is to say that I do not know what parameters to input in remove() since all of them were created as brick

Thanks!

Whole program below

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 = 440;
    public static final int APPLICATION_HEIGHT = 660;

/** Dimensions of game board (usually the same) */
    private static final int WIDTH = 400;
    private static final int HEIGHT = 600;

/** 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 so that the whole set of bricks are in the centre */
    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;

/** Game speed */
    private static final int DELAY = 1;

/* Method: run() */
/** Runs the Breakout program. */
    public void run() {
        addMouseListeners();
        addWorld();
        runGame();
    }

    private void addWorld(){
        setSize (APPLICATION_WIDTH, APPLICATION_HEIGHT);
        addPlayingBox();
        addBricks();
        addPaddle();
    }

    /* lives and number of bricks will be check before game runs
     * if there are either no lives of bricks left game is over
     * ball and ball physics are only added to the screen after there is a mouse click.
     */
    private void runGame(){
        while (true){
                // add a gameover label
        waitForClick();
        addBall();
        addBallMotion();
        }
    }

    //adds the playing 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);
    } 

    /*bricks are added to the top row and left column 1st and consequently to the its right column 
     * and to the next row when a row is all filled up
     */
    private void addBricks(){
        for (int i = 0; i < NBRICK_ROWS; i++){
            for (int j = 0; j < NBRICKS_PER_ROW; j++){

                int y = BRICK_Y_OFFSET + (i * (BRICK_HEIGHT + BRICK_SEP));
                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 (WIDTH / 2 - PADDLE_WIDTH / 2, HEIGHT - PADDLE_Y_OFFSET, 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) (HEIGHT - PADDLE_Y_OFFSET));
        }
    }

    /* creates the ball 
     */
    private void addBall(){

        double ballInitXPosition = WIDTH / 2 - BALL_RADIUS;
        double ballInitYPosition = HEIGHT / 2 - BALL_RADIUS;
        ball = new GOval (ballInitXPosition, ballInitYPosition,
                            BALL_RADIUS * 2, BALL_RADIUS * 2);
        ball.setFilled(true);
        ball.setColor(Color.BLACK);
        add (ball);
    }

    /* kick start the ball motion with predetermined values
     */
    private void addBallMotion(){
    // y component of starting velocity; pixels per second
        vy = 0.3;

    /* 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
     * angle must not be 0 or 180 degrees otherwise the ball will not move anywhere else
     */
        vx = rgen.nextDouble(0.0, 0.5);
        if (rgen.nextBoolean(0.5)){
            vx = -vx;
        }
        while (true){
        ball.move(vx, vy);
        checkCollision();
        pause(DELAY);
        }
    }

    private void checkCollision(){
        checkWallCollision();
        checkBrickAndPaddleCollision();
    }

    //checks for wall collision
    private void checkWallCollision(){

        if ( (getCollidingObject() == leftBounds) || (getCollidingObject() == rightBounds )){
            vx = -vx;
        }
    //checks for floor and ceiling collision collision
        if ( (getCollidingObject() == topBounds) ){
            vy = -vy;
        }
        if ( (getCollidingObject() == bottomBounds)){
            remove (ball);
            runGame();

        }
    }

    /* check if there is any collision with brick or paddle
     */
    private void checkBrickAndPaddleCollision(){
        GObject collider = getCollidingObject();

        /* brick is removed and y direction of ball is reversed
         * bricks counter goes down by 1 and score goes up by 1 
         */
        if (collider != paddle && 
            collider != null && 
            collider != topBounds && 
            collider != rightBounds && 
            collider != bottomBounds && 
            collider != leftBounds){
            remove(collider);
            vy = -vy;
        }

        /* collide with paddle, y direction is reversed
         */
        else if (collider == paddle){
            vy = -vy;
        }
    } 

    //check for collision at the 4 sides of the ball
    //starting with the top and going clockwise
    //returns the object nearest to the screen that touches the sides of the ball
    private GObject getCollidingObject(){
        GObject ballTop = getElementAt ( (ball.getX() + BALL_RADIUS), (ball.getY() - .1) );
        GObject ballRight = getElementAt ( (ball.getX() + (BALL_RADIUS * 2) + .1), (ball.getY() + BALL_RADIUS) );
        GObject ballBottom = getElementAt ( (ball.getX() + BALL_RADIUS), ball.getY() + (BALL_RADIUS * 2) + .1);
        GObject ballLeft= getElementAt ( (ball.getX() - .1), (ball.getY() + BALL_RADIUS) );

        if (ballTop != null){
            return (ballTop);
        }
        else if (ballRight != null){
            return (ballRight);
        }
        else if (ballBottom != null){
            return (ballBottom);
        }
        else if (ballLeft != null){
            return (ballLeft);
        }
        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();

    // creates a bounding box that is the playing area
    private GLine topBounds;    
    private GLine bottomBounds;
    private GLine leftBounds;
    private GLine rightBounds;
}

Upvotes: 2

Views: 183

Answers (3)

Ross Drew
Ross Drew

Reputation: 8246

So, if you are using add() from an external library (acm.graphics), you'll need to keep your own copies of bricks that you add. Perhaps add a 2D array of boolean values or a structure like @thattolleyguy suggested to your class then a method to add them

 private void addBrick(int x, int y)
 {
   brickArray[x][y] = true; //your own copy of brick locations

   int yloc = BRICK_Y_OFFSET + (i * (BRICK_HEIGHT + BRICK_SEP));
   int xloc = (BRICK_X_OFFSET) + (j * (BRICK_WIDTH + BRICK_SEP));
   brick = new GRect (xloc, yloc, BRICK_WIDTH, BRICK_HEIGHT );
   add (brick);
 }

Then you can easily remove them from your array (set that location to false) and from your external library (or you may need a redraw) with a removeBrick method.


Also

The object reference brick is only referenced within this function so it only needs to be local

private void addBricks()
{
 GRect brick;
 ...
   add(brick);
 ...
}

Upvotes: 1

Jay
Jay

Reputation: 607

If I was you, I would store all GRects in a List<GRect>. This list should be at the center of your operations.

I suppose the drawing are triggered by repaint() method. Possibly in a sperate thread, you need to check the distance between the ball and each GRect, when you find a GRect intersected with the ball, you can pass that GRect to remove().

One simple solution is to keep an isVisible flag in each GRect and modify it in remove(). BTW, Java Objects are passed by reference, your modification will take effects.

Upvotes: 0

thattolleyguy
thattolleyguy

Reputation: 813

You'll have to maintain a separate mapping of which bricks exist. I imagine you'd need something like this to do collision detection as well. I would do something like the following.

public class Game
{
    Collection<Brick> bricks;
    Ball ball;

    public void initLocation()
    {
        for (int i = 0; i < NBRICK_ROWS; i++)
        {
            for (int j = 0; j < NBRICKS_PER_ROW; j++)
            {

                int y = BRICK_Y_OFFSET + (i * (BRICK_HEIGHT + BRICK_SEP));
                int x = (BRICK_X_OFFSET) + (j * (BRICK_WIDTH + BRICK_SEP));
                bricks.add(new Brick(x, y));
            }
        }
    }

    public void drawBricks()
    {
        for (Brick brick : bricks)
        {
            brickRect = new GRect(x, y, BRICK_WIDTH, BRICK_HEIGHT);
            add(brick);
        }
    }

}

public class Brick
{
    int x;
    int y;

    public Brick(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

public class Ball
{
    int x;
    int y;
}

This code isn't complete but should give you an idea on how to keep a reference to the brick. When you're checking for collision, you can iterate through the bricks, find any the have a collision with the ball and then call remove() on that brick.

Upvotes: 1

Related Questions