Home > Blockchain >  How to make ball drawn with Java bounce off the edges of the panel?
How to make ball drawn with Java bounce off the edges of the panel?

Time:05-22

I have java code that draws a red ball inside a class that extends the JPanel class, I have a timer that is enabled by a button that updates the position of the ball with timer ctor variable elapse. I am trying to get the difference of the height of the panel and the YPOSITION where the circle is drawn if its less than 0 the the bounce ball needs to keep moving down else it should move up, my ball hits the wall and keeps hitting it. Help me debug the code that is causing that to happen. RightPanel class

import javax.swing.*;
import java.awt.*;

public class RightPanel extends JPanel {
    //define the position where the circle will be drawn
    private int positionX=150;
    private int positionY=150;
    private int radius=100;//as the shape is a circle
    //override the paint method to draw the bounce ball on the second panel


    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d= (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setColor(Color.RED);
        g2d.fillOval(positionX,positionY,radius,radius);
    }
     //let's us update the position of the ball from another class
    public int getPositionY(){
    public void setPositionX(int positionX) {
        this.positionX = positionX;
    }
    public void setPositionY(int positionY){
        this.positionY=positionY;
    }
    
    public int getPositionX(){
        return this.positionX;
    }
   
        return this.positionY;
    }
}

The logic in the timer class below is the one I need help with GameInterface class

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;

public class GameInterface extends JFrame {
    //declare a Timer object to start the movement
    Graphics ctx;
    RightPanel rightpanel;
    private int height;
    //declare a timer to start moving the ball
    Timer mytimer= new Timer(50, new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            //check this and keep moving the ball down
            if(rightpanel.getPositionY()- rightpanel.getHeight()<0){

                rightpanel.setPositionY(rightpanel.getPositionY() 5);
                rightpanel.paint(rightpanel.getGraphics());
            }else{

            //move the ball up
                rightpanel.setPositionY(rightpanel.getPositionY()-5);
                rightpanel.paint(rightpanel.getGraphics());
            }


        }
    });
    public GameInterface(){
        setSize(new Dimension(800, 600));
        height=this.getHeight();
        setResizable(false);
        setTitle("Bounce Game");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBackground(Color.black);
        //define a new JSplitPane and use it to add two JPanels
        JPanel leftpanel= new JPanel();
        //add buttons to the left panel programatically
        JButton up= new JButton("Move up");
        //set the event listeners for the buttons
        up.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //start he timer
                mytimer.start();


            }
        });
        JButton down = new JButton("Move down");
        down.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //move my ball down
                rightpanel.setPositionX(rightpanel.getPositionX());
                rightpanel.setPositionY(rightpanel.getPositionY() 5);
                rightpanel.paint(rightpanel.getGraphics());

            }
        });
        leftpanel.add(up);
        leftpanel.add(down);
        rightpanel= new RightPanel();
        JSplitPane splitpane= new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,leftpanel,rightpanel);
        this.add(splitpane);
        setVisible(true);
        ctx=this.getGraphics();

    }
}

CodePudding user response:

The basic idea is, when you "drop" the ball, you need to determine the direction of movement that the ball should move in. When the timer ticks, it will apply that direction of movement until it either reaches the bottom, at which time the delta is reversed, or it reaches the top.

The important part here is, all the state the timer needs should be determined before the timer is started and not calculated within the timer itself, as the state it needs is no longer relevant.

For example...

enter image description here

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                Ball ball = new Ball(20);
                JFrame frame = new JFrame();
                frame.add(new MainPane(ball));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class Ball {
        private Point location;
        private Dimension size;
        private Shape shape;

        public Ball(int radius) {
            location = new Point(0, 0);
            size = new Dimension(radius * 2, radius * 2);
            shape = new Ellipse2D.Double(0, 0, radius * 2, radius * 2);
        }

        public Rectangle getBounds() {
            return new Rectangle(location, size);
        }

        public void setLocation(Point p) {
            location = new Point(p);
        }

        public void paint(Graphics2D g2d) {
            g2d = (Graphics2D) g2d.create();
            g2d.setColor(Color.RED);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.translate(location.x, location.y);
            g2d.fill(shape);
            g2d.dispose();
        }
    }

    public class SurfacePane extends JPanel {

        private Ball ball;
        private Timer timer;
        private int yDelta;

        public SurfacePane(Ball ball) {
            this.ball = ball;
            this.ball.setLocation(new Point(200 - (ball.getBounds().width / 2), 0));
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            ball.paint(g2d);
            g2d.dispose();
        }

        public void moveBallDown() {
            Rectangle bounds = ball.getBounds();
            Dimension size = ball.size;
            Point location = bounds.getLocation();
            location.y  = size.height;
            if (location.y   size.height > getHeight()) {
                location.y = getHeight() - size.height;
            }
            ball.setLocation(location);
            repaint();
        }

        public void dropBall() {
            if (timer != null) {
                return;
            }
            Rectangle bounds = ball.getBounds();
            Dimension size = ball.size;
            Point location = bounds.getLocation();
            if (location.y   size.height > getHeight()) {
                yDelta = -1;
            } else {
                yDelta = 1;
            }

            timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Rectangle bounds = ball.getBounds();
                    Dimension size = ball.size;
                    Point location = bounds.getLocation();
                    location.y  = yDelta;
                    if (location.y < 0) {
                        location.y = 0;
                        yDelta = 0;
                        timer.stop();
                        timer = null;
                    } else if (location.y   size.height > getHeight()) {
                        location.y = getHeight() - size.height;
                        yDelta *= -1;
                    }
                    ball.setLocation(location);
                    repaint();
                }
            });
            timer.start();
        }
    }

    public class MainPane extends JPanel {

        private Ball ball;
        private SurfacePane surfacePane;

        public MainPane(Ball ball) {
            setLayout(new BorderLayout());
            this.ball = ball;
            surfacePane = new SurfacePane(ball);
            add(surfacePane);

            JPanel actionPane = new JPanel(new GridBagLayout());
            JButton up = new JButton("Up");
            JButton down = new JButton("Down");

            actionPane.add(up);
            actionPane.add(down);

            add(actionPane, BorderLayout.SOUTH);

            up.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    surfacePane.dropBall();
                }
            });
            down.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    surfacePane.moveBallDown();
                }
            });
        }

    }
}
  • Related