我的 Java 弹跳球以更快的速度弹起
My Java Bouncing Ball Bounces up with a larger velocity
我正在制作一个简单的 Java 程序来上下弹跳球。问题是每次弹跳时,球弹起的高度都高于它的起点。我希望球能准确地反弹到它开始时的高度。
在doPhysics()方法中的圆class中可以找到球物理,我怀疑可以找到问题所在
import java.awt.*;
import java.util.*;
public class Main{
public static Frame frame = new Frame();
public static Physics physics = new Physics();
public static ArrayList<Circle> circles = new ArrayList<Circle>(); //array for the points
public static void main(String args[]) {
Circle circle = new Circle(100, 300, 50, Color.BLACK);
circles.add(circle);
run();
}
public static void run() {
physics.timer.start();
}
}
import java.awt.*;
public class Circle {
private int x;
private int y;
private double xAccel= 0;
private double yAccel = 0;
private double xVel= 0;
private double yVel = 0;
private Color colour;
private int radius;
public Circle(int x, int y, int radius, Color colour) {
setX(x);
setY(y);
setRadius(radius);
setColour(colour);
}
public void draw(Graphics2D g2d) {
g2d.setColor(colour);
g2d.fillOval(x, y, radius*2, radius*2);
}
public void doPhysics() {
hitGround();
System.out.println(yVel);
yVel += Physics.getGravity();
y -= yVel;
}
public void hitGround() {
if(y + radius*2 > Frame.panel.h ) {
yVel = -yVel;
}
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setColour(Color colour) {
this.colour = colour;
}
public void setRadius(int radius) {
this.radius = radius;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColour() {
return colour;
}
public int getRadius() {
return radius;
}
}
import java.awt.*;
import javax.swing.*;
class Frame extends JFrame {
public static Panel panel;
public Frame() {
panel = new Panel();
this.setTitle("Fun");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(panel);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
class Panel extends JPanel {
public int w = 500;
public int h = 500;
public Panel() {
this.setPreferredSize(new Dimension(w, h));
this.setBackground(Color.red);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
for(Circle circle : Main.circles) {
circle.draw(g2d);
}
}
}
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Physics implements ActionListener {
private static double gravity = -.1;
public Timer timer;
public Physics() {
timer = new Timer(1, this);
}
public static double getGravity() {
return gravity;
}
@Override
public void actionPerformed(ActionEvent e) {
for(Circle circle : Main.circles) {
circle.doPhysics();
}
Main.frame.repaint();
}
}
问题主要是由于位置(x
和y
)使用整数值引起的。在每次迭代中,值都会四舍五入并且误差会累积。
解决方案:声明double x
和double y
并且只使用四舍五入的整数值来绘制。
以上应该可以减少问题,但不能完全解决。该代码通过使用在时间间隔后计算的速度(参见 Numerical Integration)随时间 ¹ 进行粗略积分。这可以通过计算更改前后的平均速度来改善。大致:
double preVel = yVel;
yVel += Physics.getGravity();
y -= (preVel + yVel)/2;
可以简化(纯数学)为:
yVel += Physics.getGravity();
y -= yVel - Physics.getGravity()/2;
这应该可以正常工作,因为加速度是恒定的。如果加速度也在变化,则情况并非如此。而且它也容易受到随着时间累积的精度误差的影响。
1 - 参见 Numerical integration and Temporal discretization
我正在制作一个简单的 Java 程序来上下弹跳球。问题是每次弹跳时,球弹起的高度都高于它的起点。我希望球能准确地反弹到它开始时的高度。
在doPhysics()方法中的圆class中可以找到球物理,我怀疑可以找到问题所在
import java.awt.*;
import java.util.*;
public class Main{
public static Frame frame = new Frame();
public static Physics physics = new Physics();
public static ArrayList<Circle> circles = new ArrayList<Circle>(); //array for the points
public static void main(String args[]) {
Circle circle = new Circle(100, 300, 50, Color.BLACK);
circles.add(circle);
run();
}
public static void run() {
physics.timer.start();
}
}
import java.awt.*;
public class Circle {
private int x;
private int y;
private double xAccel= 0;
private double yAccel = 0;
private double xVel= 0;
private double yVel = 0;
private Color colour;
private int radius;
public Circle(int x, int y, int radius, Color colour) {
setX(x);
setY(y);
setRadius(radius);
setColour(colour);
}
public void draw(Graphics2D g2d) {
g2d.setColor(colour);
g2d.fillOval(x, y, radius*2, radius*2);
}
public void doPhysics() {
hitGround();
System.out.println(yVel);
yVel += Physics.getGravity();
y -= yVel;
}
public void hitGround() {
if(y + radius*2 > Frame.panel.h ) {
yVel = -yVel;
}
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setColour(Color colour) {
this.colour = colour;
}
public void setRadius(int radius) {
this.radius = radius;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColour() {
return colour;
}
public int getRadius() {
return radius;
}
}
import java.awt.*;
import javax.swing.*;
class Frame extends JFrame {
public static Panel panel;
public Frame() {
panel = new Panel();
this.setTitle("Fun");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(panel);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
class Panel extends JPanel {
public int w = 500;
public int h = 500;
public Panel() {
this.setPreferredSize(new Dimension(w, h));
this.setBackground(Color.red);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
for(Circle circle : Main.circles) {
circle.draw(g2d);
}
}
}
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Physics implements ActionListener {
private static double gravity = -.1;
public Timer timer;
public Physics() {
timer = new Timer(1, this);
}
public static double getGravity() {
return gravity;
}
@Override
public void actionPerformed(ActionEvent e) {
for(Circle circle : Main.circles) {
circle.doPhysics();
}
Main.frame.repaint();
}
}
问题主要是由于位置(x
和y
)使用整数值引起的。在每次迭代中,值都会四舍五入并且误差会累积。
解决方案:声明double x
和double y
并且只使用四舍五入的整数值来绘制。
以上应该可以减少问题,但不能完全解决。该代码通过使用在时间间隔后计算的速度(参见 Numerical Integration)随时间 ¹ 进行粗略积分。这可以通过计算更改前后的平均速度来改善。大致:
double preVel = yVel;
yVel += Physics.getGravity();
y -= (preVel + yVel)/2;
可以简化(纯数学)为:
yVel += Physics.getGravity();
y -= yVel - Physics.getGravity()/2;
这应该可以正常工作,因为加速度是恒定的。如果加速度也在变化,则情况并非如此。而且它也容易受到随着时间累积的精度误差的影响。
1 - 参见 Numerical integration and Temporal discretization