简体   繁体   中英

Having trouble making my first subclass in Java

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM