如何让用 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();
}
});
}
}
}
我有 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();
}
});
}
}
}