简体   繁体   English

我的 Java 弹跳球以更大的速度弹起

[英]My Java Bouncing Ball Bounces up with a larger velocity

I'm making a simple Java program to bounce a ball up and down.我正在制作一个简单的 Java 程序来上下弹跳球。 The problem is that the ball bounces up higher than its starting point with each bounce.问题是每次弹跳时,球的弹跳位置都高于其起点。 I expect the ball to bounce back up exactly to the height that it started from.我希望球能准确地反弹回它开始的高度。

The ball physics can be found in the circle class in the doPhysics() method where I suspect the problem can be found球物理可以在 doPhysics() 方法的 circle 类中找到,我怀疑可以找到问题

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

The problem is mainly caused by using integer values for position ( x and y ).该问题主要是由使用整数值作为位置( xy )引起的。 On each iteration the values are rounded and the errors get accumulated.在每次迭代中,值都会被四舍五入并累积错误。
Solution: declare double x and double y and only use the rounded integer values for drawing.解决方案:声明double xdouble y并且只使用四舍五入的整数值进行绘制。

Above should reduce the problem, but not completely solve it.以上应该可以减少问题,但不能完全解决。 The code is doing a rough integration over time ¹ by using the velocity calculated after the time interval (see Numerical Integration ).该代码通过使用在时间间隔后计算的速度随着时间¹进行粗略积分(请参阅数值积分)。 This can be improved by doing an average of the velocities before and after it was changed.这可以通过对改变之前和之后的速度进行平均来改善。 Roughly:大致:

double preVel = yVel;
yVel += Physics.getGravity(); 
y -= (preVel + yVel)/2;

which can be simplified (pure math) to:可以简化(纯数学)为:

yVel += Physics.getGravity();
y -= yVel - Physics.getGravity()/2;

This should work fine since the acceleration is constant.这应该可以正常工作,因为加速度是恒定的。 Not the case if the acceleration is also changing.如果加速度也在变化,则情况并非如此。 And it is also susceptible to precision errors being accumulated over time.而且它也容易受到随着时间累积的精度误差的影响。


1 - see Numerical integration and Temporal discretization 1 - 见数值积分时间离散化

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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