如何让用 Java 绘制的球从面板的边缘反弹?

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

我有 java 代码在扩展 JPanel class 的 class 内绘制一个红球,我有一个计时器,它由更新位置的按钮启用带有定时器 ctor 变量的球过去了。我试图得到面板的高度和绘制圆圈的 YPOSITION 的差异,如果它小于 0,弹跳球需要继续向下移动,否则它应该向上移动,我的球撞到墙上并继续击中它.帮我调试导致这种情况发生的代码。 右面板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;
    }
}

下面计时器 class 中的逻辑是我需要帮助的那个 游戏界面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();

    }
}

基本思想是,当你“放下”球时,你需要确定球应该移动的运动方向。当 timer ticks 时,它将应用该运动方向直到它要么到达底部,此时 delta 反转,要么到达顶部。

这里的重要部分是,timer 需要的所有状态都应该在 timer 启动之前确定,而不是在 timer 本身内计算,因为它需要的状态不再相关。

例如...

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();
                }
            });
        }

    }
}