0

I am creating a brick breaker game for school using ArrayLists, abstraction, and polymorphism. I have created an abstract class DrawableBrick that includes a draw method. I have already successfully created the other subclasses that fill my ArrayList and the game works beautifully, but I need to create a new subclass called ShavedBrick that is a polygon that can be easily added to my ArrayList.

I am a little stuck as to how to create the parameterized constructor for this class and to set the class data to the arguments passed in by the user. Here is what I have so far. It needs to be an octagon.

import java.awt.*;
import java.util.*;

public class ShavedBrick extends DrawableBrick {


    //data
    private int [] xArray = new int [8];
    private int [] yArray = new int [8];
    private int numberOfSides;
    //private Color color;

    //constructor
        public ShavedBrick(int[] x {}, int [] y {}, int numberOfPoints)
        {
            Random ranGen = new Random();
            xArray[0] = x;
            yArray[0] = y;
            this.numberOfSides = numberOfPoints; 
            //this.width = width;
            //this.height = height;
            this.color = new Color(0,(ranGen.nextInt(156)+100),0);

        }


    //draw - tells the ShavedBrick to draw itself, using the Graphics object received
        public void draw(Graphics g)
        {
            Color prevColor = g.getColor(); //save previous color associated with g
            g.setColor(this.color);
            g.fillPolygon(xArray, yArray, numberOfSides);
            g.setColor(prevColor);                  //restore previous color
         }

Here is an example of creating the object in the ArrayList

//some constants created in the main data
private final int WALLWIDTH = 5;    //Walls' width
private final int BRICKSTARTX = WALLWIDTH;
private final int BRICKSTARTY = 100 + WALLWIDTH;
private final int BRICKWIDTH = 150;
private final int BRICKHEIGHT = 75;

//Fill the ArrayList with random DrawableBricks


    for (int i = 0; i<10; i++){
        Random random = new Random();
        int randomBrick = random.nextInt(3);
        if (randomBrick == 0){
            myBricks.add(i, new RedBrick((BRICKSTARTX + i*BRICKWIDTH),(BRICKSTARTY + BRICKHEIGHT),BRICKWIDTH,BRICKHEIGHT));
            myBricks.add(i, new RedBrick((BRICKSTARTX + i*BRICKWIDTH),((BRICKSTARTY+75) + BRICKHEIGHT),BRICKWIDTH,BRICKHEIGHT));
        }
        else if (randomBrick == 1) {
            myBricks.add(i, new BlueBrick((BRICKSTARTX + i*BRICKWIDTH),(BRICKSTARTY + BRICKHEIGHT),BRICKWIDTH, BRICKHEIGHT));
            myBricks.add(i, new BlueBrick((BRICKSTARTX + i*BRICKWIDTH),((BRICKSTARTY+75) + BRICKHEIGHT),BRICKWIDTH,BRICKHEIGHT));
        }
        //else if (randomBrick == 3){
            //myBricks.add(new ShavedBrick(0,0,2,6));
        //}
        else if (randomBrick == 2){
            for (int i = 0; i<8; i++){
                xValues[] array = new xArray[8];
                myBricks.add(new ShavedBrick(int [i] x {BRICKSTARTX,});
            }

        }
    }
  • Is `ShavedBrick` always an octagon? Or arbitrary poligon? – default locale Mar 04 '13 at 04:21
  • It is going to always be an octagon. We create the object in the main applet program. – OaklandFanatic Mar 04 '13 at 04:23
  • what is `numberOfSides`? – vijay Mar 04 '13 at 04:23
  • This code doesn't compile. You're also not setting the x and y arrays correctly. Is the constructor supposed to take in an x and y coordinate rather than the arrays of points? That would make a lot more sense. If that's the case, then you would just fill in the x and y coordinates based on this central point and go from there. You'll need to know the size of the octagon and then just loop through calculating each point of the polygon. – I82Much Mar 04 '13 at 04:23
  • Sorry, ya it doesn't compile because I got stuck on the constructor part. Where am I not setting the arrays correctly? As a parameter or in the class data. The constructor is supposed to take in an array of x coordinates and an array of y coordinates and then draw the 8 sided polygon. – OaklandFanatic Mar 04 '13 at 04:24
  • Here is a code example of another subclass and how it is created in the main game program. – OaklandFanatic Mar 04 '13 at 04:27
  • for (int i = 0; i<10; i++){ Random random = new Random(); int randomBrick = random.nextInt(3); if (randomBrick == 0){ myBricks.add(i, new RedBrick((BRICKSTARTX + i*BRICKWIDTH),(BRICKSTARTY + BRICKHEIGHT),BRICKWIDTH,BRICKHEIGHT)); myBricks.add(i, new RedBrick((BRICKSTARTX + i*BRICKWIDTH),((BRICKSTARTY+75) + BRICKHEIGHT),BRICKWIDTH,BRICKHEIGHT)); } – OaklandFanatic Mar 04 '13 at 04:28
  • what are `xArray` and `xValues`? – vijay Mar 04 '13 at 04:54

3 Answers3

0

i would suggest something like this...

public ShavedBrick(int[] x, int[] y, int numberOfPoints)
        {
            Random ranGen = new Random();
            for(int i = 0; i < 8; i ++) {
                 xArray[i] = x[i];
                 yArray[i] = y[i];
            }
            this.numberOfSides = numberOfPoints;
            this.color = new Color(0,(ranGen.nextInt(156)+100),0);

        }

Basically, remove the braces ({ }) from the constructor signature. And add each of the 8 elements in the input arrays to the private arrays of the class using a for loop. You could point the private arrays of the class directly to the input arrays, but i would personally avoid that and simply copy the values to a newly created pair of arrays.

You could also use the Array.copyOf(int[], int) http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html#copyOf(int[], int) as well.

In your client code just run a loop to compute your co-ordinates and then pass those co-ordinates along to the constructor like this ...

int[] xArray = new int[8];
int[] yArray = new int[8];
for (int i = 0; i < 8; i ++) {
   xArray[i] = //some value for the x co-ordinate of the ith point
   yArray[i] = //some value for the y co-ordinate of the ith point
}
ShavedBrick b = new ShavedBrick(xArray, yArray, 8);
myBricks.add(b); //finally add the new shaved brick
vijay
  • 2,646
  • 2
  • 23
  • 37
  • Awesome. This seems to make sense. The only thing I am worried about is how this will fit into my ArrayList. Basically, this ShavedBrick is randomly created in the main program and added to the ArrayList based on the location of the brick next to it. – OaklandFanatic Mar 04 '13 at 04:34
  • what is the type of the ArrayList? i am assuming that the arraylist consists of `DrawableBrick`s ? So just say `ArrayList list = new ArrayList(); list.add(new ShavedBrick(x,y,n));` – vijay Mar 04 '13 at 04:44
  • This is basically what I am doing but it is a little more complicated. I just added more code to my original question that will probably provide more clarification. – OaklandFanatic Mar 04 '13 at 04:52
  • compute the coordinates of your octagon before passing them on to the constructor. and then add the newly created object to the list. – vijay Mar 04 '13 at 05:01
0

You can directly assign the argument arrays as follows:

public ShavedBrick(int[] xArray, int[] yArray, int numberOfPoints)
    this.xArray = xArray;
    this.yArray = yArray;
    //...

int[] x {} actually creates a new empty array which of course is not a valid parameter declaration. Parameter declaration should look as int[] xArray.

Bhesh Gurung
  • 50,430
  • 22
  • 93
  • 142
  • This gives me a syntax error of Type mismatch: cannot convert from int to int[] – OaklandFanatic Mar 04 '13 at 04:30
  • It shouldn't. What are you doing? – Bhesh Gurung Mar 04 '13 at 04:33
  • `ShavedBrick sb = new ShavedBrick(x,y,8); x[3] = -1;//happy debugging` – default locale Mar 04 '13 at 04:35
  • Woops. Found my mistake. I think this way will be easiest for creating the ShavedBrick in my main program. Thanks a lot – OaklandFanatic Mar 04 '13 at 04:38
  • Assigning the array references directly might lead to bugs later on. Especially when the array references being passed as parameters are changed from the site of constructor invocation. it will be difficult to detect how changes in the arrays at the invocation site relate to the changes in the arrays of the object. I recommend the use of `Array.copyOf` or a simple loop construct to copy the elements one at a time. – vijay Mar 04 '13 at 04:40
  • That's a good idea. But, IMHO, defensive copy should be made by the class for its own need (which generally would be to make it immutable which requires a lot more than just that) and not to avoid mistakes in the client code. The client code should be clever enough to not make mistakes like that specially when it's the one to pass the reference to the constructor. – Bhesh Gurung Mar 04 '13 at 04:47
  • relying on the client code to not make mistakes is IMHO not the best way to construct your classes. The class itself should be resilient as far as possible. – vijay Mar 04 '13 at 04:56
  • That implies that every class should clone all the objects it receives to be resilient. Generally, I think it's the approach for immutability not resiliency. – Bhesh Gurung Mar 04 '13 at 05:01
  • well, i was referring to the class being resilient in general. Making it immutable is one way. I agree that there are other things one might do. but given the information and context of this question, immutability is the only thing i can think of to make life simpler when it comes to debugging. – vijay Mar 04 '13 at 05:04
0

I'm not sure what your problem is, but if you have an octagon then you don't need a numberOfPoints argument:

public ShavedBrick(int[] x, int [] y)
    {
        Random ranGen = new Random();
        this.numberOfSides = 8; //it's always 8
        xArray = Arrays.copyOf(x,numberOfSides); //note, this method will pad array with zeros if x.length is less than 8
        yArray = Arrays.copyOf(y,numberOfSides);
        this.color = new Color(0,(ranGen.nextInt(156)+100),0);
    }
default locale
  • 13,035
  • 13
  • 56
  • 62