Reputation: 597
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
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
Reputation: 607
If I was you, I would store all GRect
s 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
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