I'm trying to make a Breakout game program for my Java course that includes an array of colored blocks (Bricks). I've done this successfully, but now my instructor wants us to add different subclasses of Bricks. One of the subclasses he wants is a ColorBrick, which inherits all its behavior from the Brick superclass, except that it has an array of colors that changes every 5 ticks. The constructor takes an array of colors instead of a single color.
This is what I have for my Brick superclass:
package Breakout;
import java.awt.Color;
import java.awt.Graphics;
public class Brick {
public int x, y, i, j;
public Color c;
Brick[][] brick;
public Brick() {
}
public Brick(Color c, Brick[][] brick, int i, int j) {
this.c = c;
this.brick = brick;
this.x = i * 40;
this.y = j * 10 + 50;
this.i = i;
this.j = j;
}
public void tick() {
}
public void paint(Graphics g) {
g.setColor(c);
g.fillRect(x, y, Breakout.brickWidth, Breakout.brickHeight);
}
public void hit(Ball b) {
if (b.yThen > y + Breakout.brickHeight) {
b.yv = -b.yv;
b.yNow = 2 * (y + Breakout.brickHeight) - b.yNow;
}
if (b.yThen < y) {
b.yv = -b.yv;
b.yNow = 2 * (y) - b.yNow;
}
if (b.xThen > x + Breakout.brickWidth) {
b.xv = -b.xv;
b.xNow = 2 * (x + Breakout.brickWidth) - b.xNow;
}
if (b.xThen < x) {
b.xv = -b.xv;
b.xNow = 2 * (x) - b.xNow;
}
brick[i][j] = null;
}
}
And this is what I have so far for my colorBrick subclass:
package Breakout;
import java.awt.Color;
public class ColorBrick extends Brick {
Color colors[] = {Color.red, Color.green, Color.blue, Color.yellow};
public ColorBrick(Color[] colors, Brick[][] brick, int i, int j){
this.colors = colors;
this.brick = brick;
this.i = i;
this.j = j;
}
public void tick(){
}
}
At this point I've hit a wall and I'm not sure of what to do from here. My instructor said that the tick method needs to be empty in the superclass for some reason. If it needs to be empty then why would he have us put it there? I'm also not sure what I should put in the subclass tick method. Am I heading in the right direction with my subclass at all or is everything I did so far completely wrong? Any guidance would be very appreciated!
Here's my Main Breakout code if it's useful:
package Breakout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Breakout extends javax.swing.JFrame {
public static final int fieldHeight = 600;
public static final int fieldWidth = 400;
public int diameter = 5;
public int xNow = 200 - (diameter / 2);
public int yNow = 300 - (diameter - 2);
public int paddleWidth = 50;
public int paddleHeight = 5;
public int platform = 580;
public static int mousex;
public int mousey;
public static int brickWidth = 40;
public static int brickHeight = 10;
public Random randoms = new Random();
Brick[][] bricks = new Brick[arrayWide][arrayHigh];
public static boolean startUp;
public static int arrayWide = 10;
public static int arrayHigh = 5;
Ball ball = new Ball(200 - (diameter / 2), 20 /*300 - (diameter /2)*/, 0, 0, diameter, Color.white);
Paddle myPaddle = new Paddle(platform, paddleWidth, paddleHeight);
/**
* Creates new form Breakout
*/
public Breakout() {
initComponents();
clock.start();
}
public class MyPanel extends JPanel {
@Override
public void paint(Graphics g) {
super.paint(g);
if (startUp) {
ball.paint(g);
}
myPaddle.paint(g);
for (int i = 0; i < arrayWide; i++) {
for (int j = 0; j < arrayHigh; j++) {
if (bricks[i][j] != null) {
bricks[i][j].paint(g);
}
}
}
// Insert code to paint the scene here.
// Use methods in the Graphics class to do the painting
// Remember coordinates use (0,0) at the top left
}
}
public Timer clock = new Timer(50, new ActionListener() { // 50ms delay between ticks
public void actionPerformed(ActionEvent e) {
tick(); // Write a method named tick to advance your game
jPanel1.repaint();
}
}); // panel is the name of the JPanel that displays the game
public void launchball() {
}
public void tick() {
ball.move();
Brick brick2 = brickAt(ball);
if (brick2 != null) {
brick2.hit(ball);
}
myPaddle.move(mousex);
myPaddle.bounce(ball);
System.out.println();
}
public Brick brickAt(Ball b) {
int j = (int) (b.yNow - 50) / 10;
int i = (int) (b.xNow / 40);
if (i < arrayWide && i >= 0 && j < arrayHigh && j >= 0) {
return (bricks[i][j]);
}
return null;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jPopupMenu1 = new javax.swing.JPopupMenu();
jPanel2 = new javax.swing.JPanel();
jPanel1 = new MyPanel();
jLabel1 = new javax.swing.JLabel();
start = new javax.swing.JButton();
org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2);
jPanel2.setLayout(jPanel2Layout);
jPanel2Layout.setHorizontalGroup(
jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(0, 100, Short.MAX_VALUE)
);
jPanel2Layout.setVerticalGroup(
jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(0, 100, Short.MAX_VALUE)
);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jPanel1.setBackground(new java.awt.Color(0, 0, 0));
jPanel1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseMoved(java.awt.event.MouseEvent evt) {
mouseMove(evt);
}
});
org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(0, 400, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(0, 600, Short.MAX_VALUE)
);
jLabel1.setFont(new java.awt.Font("Hobo Std", 1, 24)); // NOI18N
jLabel1.setForeground(new java.awt.Color(153, 51, 255));
jLabel1.setText("Breakout");
start.setFont(new java.awt.Font("Hobo Std", 0, 13)); // NOI18N
start.setForeground(new java.awt.Color(255, 51, 0));
start.setText("Start");
start.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
startActionPerformed(evt);
}
});
org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.add(164, 164, 164)
.add(jLabel1))
.add(layout.createSequentialGroup()
.add(15, 15, 15)
.add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.add(layout.createSequentialGroup()
.add(175, 175, 175)
.add(start)))
.addContainerGap(17, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.add(16, 16, 16)
.add(jLabel1)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
.add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
.add(start)
.addContainerGap(10, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void mouseMove(java.awt.event.MouseEvent evt) {
mousex = evt.getX();
mousey = evt.getY();
}
private void startActionPerformed(java.awt.event.ActionEvent evt) {
startUp = true;
ball.xNow = 200 - (diameter / 2);
ball.yNow = 300 - (diameter - 2);
ball.xv = 0;
ball.yv = 8;
for (int i = 0; i < arrayWide; i++) {
for (int j = 0; j < arrayHigh; j++) {
if ((j % 2 == 0 && i % 2 == 0) || (j % 2 == 1 && i % 2 == 1)) {
bricks[i][j] = new Brick(Color.magenta, bricks, i, j);
} else {
bricks[i][j] = new Brick(Color.gray, bricks, i, j);
}
}
}
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(Breakout.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(Breakout.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(Breakout.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Breakout.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Breakout().setVisible(true);
}
});
}
Since this sounds like homework.classwork, I'm not going to go into full details.
Presumably, something (TBD) will call tick() every 5 seconds (or periodically). A normal Brick
does nothing. Your ColorBrick
should change to the next color every 5 seconds. Somehow it needs to know it's current color and change to the next one.
There needs to be an empty tick
method in Brick
so that another class only needs to deal with Bricks; the class that calls tick
doesn't need to know whether it's a Brick
or a ColorBrick
. The behavior of tick
is specified by the runtime class; this is polymorphism -- the ability of related classes to react differently to the same method call.
The subclass tick
method needs to keep track of the number of ticks that have been generated. When it needs to, it will change the Color variable c
.
One additional change I might make is in your ColorBrick
constructor: Take advantage of super
to call the superclass constructor, so as not to duplicate your code.
Additionally, declare your instance variables ( c
, x
, y
, etc.) protected
so that only the class itself and subclasses have direct access to them.
The tick method needs to exist on the superclass, because I'm guessing the intention is that for every Brick that exists, tick() will be called (probably in the main Breakout class, likely in a loop). The tick() method in the superclass specifies the "default" behaviour, which is to do nothing. For your ColorBrick class, when tick is called, the colour needs to change every five ticks, so you need to specify this special case of behaviour in the subclass (ColorBrick).
To do this, ColorBrick needs a way of keeping count of the number of times tick() has been called. Once you've added some code that can do this, you can then think about changing the colour of the ColorBrick on certain ticks: Your ColorBrick already "knows about" its current colour, as it extends from Brick, which has a Color property (c), so it's a case of changing that value on certain ticks.
I've left this deliberately vague, as I don't want to complete your assignment for you, but please feel free to ask any questions.
You need to implement your tick
method in ColorBrick
something like below:
private int i = 0;
public void tick(){
c = colors[i++ % colors.length];
}
Now, when making your graphic application you can simply use the Brick
class to create ColorBricks
as well. For example, adding multiple bricks to make a wall:
Brick[][] wall = new Brick[5][5];
Some of the Brick
in above array could be ColorBrick
. This allows to have a generic interface ie tick()
method for every Brick
object. But for ColorBrick
this method actually changes the color of Brick
where-as in other Brick
it does nothing!
You can do more stuff like, DancingBrick
that changes size after every tick
. Your graphic implementation wont be required to change drastically in order to add different kinds of Brick
as it uses the base type as Brick
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.