为什么我在使用大型 scale/speed 射弹时会出现错误,这是由于欧拉积分吗?

Why do I get inaccuracies when working with large scale/speed projectiles, is it due to Eulerian Integration?

所以我正在尝试进行物理模拟,目的是模拟导弹从很远的距离起飞,(例如,我使用了 1.6 公里)并且我在这 1.6 公里的距离上有一个防空武器;当导弹发射时,由于数学我已经计算出何时需要释放 AA 武器来击中导弹。如此酷的数学全部检查出来,我 99% 确定这在数学上应该有效;但是错误似乎出现在动画阶段,我觉得这与我处理重力的方式有关。

问题不是导弹的飞行路径遵循可爱的抛物线,而是采用由许多不同线性函数组成的路径(因此欧拉积分推测(来源:http://natureofcode.com/book/chapter-5-physics-libraries/)); and I believe the reason for this is to do with my scale. I am using a scale of 1 pixel = 1 meter. The image updates every 60 seconds, so I am saying every cycle, take the vertical velocity - (9.81 / 60) and then update the position by (Vertical velocity / 60). The problem is, it only wants to round to the nearest pixel, so in the first 2 seconds or so, it only wants to have the vertical position change at 4 pixels per cycle, and then it goes to 5, then 6... This causes the flight path (when the missile was launched at 200m/s at 50 degrees and the AA launched at 70degrees with the same speed) to look like:

如果有人知道我如何解决这个问题,将不准确的线性表示转换为一个漂亮的抛物线表示,并且仍然准确到时间,(发射后的时间约为 3 秒)。如果有人有任何建议 and/or 解决方案,或者如果您能够解释为什么会发生这种情况并且不介意花一点时间向我解释以更好地理解问题,那将不胜感激!如果您需要更多信息来帮助您帮助我,请发表评论,我将为您提供任何信息。相关代码为:

public void gravity(){
    for (int i = 0; i < rockets.size(); i++){

        if(timeToStart <= milliSecondTimer){
            rockets.get(1).fired = true;
            //Trail of other rocket
            if (milliSecondTimer > 0.1 * count){
                rockets.add(new Ball(rockets.get(1).x - 20 ,rockets.get(1).y - HEIGHT + 100,5,0,0,false));
            }

        }

        if(rockets.get(i).fired){
            rockets.get(i).vSpeed -= 9.81 / 60;
            rockets.get(i).move(0, (int) (rockets.get(i).vSpeed / 60));
            rockets.get(i).move(1, (int) (rockets.get(i).hSpeed / 60));
        } else if (timeToStart==1110){
            //function to work out the time displacment
            derr(1);
        }

        //For the trail
        if (milliSecondTimer > 0.1 * count){
            rockets.add(new Ball(rockets.get(0).x - 20 ,rockets.get(0).y - HEIGHT + 100,5,0,0,false));
            count++;
        }

    }
}   
public static void main(String[] args) throws InterruptedException{
    JFrame frame = new JFrame("App Name");
    Rockets app = new Rockets();
    frame.setSize((int)(WIDTH * SCALER),(int)(HEIGHT * SCALER));
    frame.add(app);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);
    frame.requestFocus();
    long lastLoopTime = System.nanoTime();
    int fps = 0, lastFpsTime = 0, count = 1;
    final int TARGET_FPS = 60;
    final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
    //Game Loop
    while(true){
        long now = System.nanoTime();
        long updateLength = now - lastLoopTime;
        lastLoopTime = now;
        delta = updateLength / ((double)OPTIMAL_TIME);
        lastFpsTime += updateLength;
        fps++;
        if (lastFpsTime > 100000000 * count){
           milliSecondTimer += 0.1;
           count++;
        }
        if (lastFpsTime >= 1000000000){
            System.out.println("(FPS: "+fps+")");
            lastFpsTime = 0;
            fps = 0;
            count = 1;
        }
        loopsGone++;
        app.repaint();
        Thread.sleep( (lastLoopTime-System.nanoTime() + OPTIMAL_TIME)/1000000 );
    }
}

谢谢,

山姆

也许您可以将 x 和 y 火箭坐标更改为浮点数(我假设它们现在是整数)。然后在绘图时,即添加 (int) cast 时。例如,

rockets.get(i).move(0, (int) (rockets.get(i).vSpeed / 60));

不应进行整数转换。

此外,您将要更改

(rockets.get(i).vSpeed / 60));

(rockets.get(i).vSpeed / 60.0)); 

您希望您的位置保持精度,而目前使用 int 转换时并没有做到这一点。这就是使用浮点数可以达到的效果。

规模似乎不是问题所在。如果您尝试在 10 x 10 像素的图像上绘制抛物线,这将是一个问题。

你能post你的火箭class吗?我想要 运行 这个,看起来很有趣。

感谢您接受我的回答。这是我看到的另一个问题。

为了获得更好的位置精度,您需要更频繁地更新位置函数,这意味着每次重绘时不止一次。这就是我的游戏循环的样子。

public void run() {
        long lastTime=System.nanoTime();
        final double amountOfTicks=60.0;
        double ns=1000000000/amountOfTicks;
        double delta=0; 

        int updates=0;
        int frames=0;
        long timer=System.currentTimeMillis();

        while (running) {
            long now=System.nanoTime();
            delta +=(now-lastTime) / ns;
            lastTime=now;
            if (delta>1) {      
                update();     <--- this is where your gravity() method belongs
                delta--;
                updates++;
            }
            render();     <---- this will be your repaint method
            frames++;
            if (System.currentTimeMillis()-timer>1000) {
                timer+=1000;
                currUpdates=updates;
                currFrames=frames;
                updates=0;
                frames=0;
            }
        }
    }

它的作用是每毫秒更新一次飞船位置,但仅以 60 fps 的速度呈现。