【问题标题】:How to get smoother 2d projectile physics如何获得更平滑的 2d 弹丸物理
【发布时间】:2014-07-14 13:43:04
【问题描述】:

所以我想开始开发一款 2D 平台游戏,而我要到明年才能从事物理学工作,所以我在一本旧物理书中找到了方程式,我不得不帮助找到 x 和 y 位置以及他们的速度。问题是,它们似乎加速太快,因为渲染太慢了。这不是程序的错,是我的错,因为我不知道如何减慢加速速度以使其看起来更顺畅。这是我正在使用的球类的代码(我知道代码绝对是一团糟!我只是在乱七八糟地试图让方程式正确......如果我在工作,我永远不会这样写我的代码在一个严肃的项目上,所以请不要提醒我它看起来很糟糕)

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JComponent;


public class Ball extends JComponent{
    public double xpos;
     double oX;
     double oY;
     double ypos;
    double xvel;
     double yvel;
     long time;
     double oxvel;
     double oyvel;
    long angle = 45;
    long startTime = System.currentTimeMillis();

    public Ball(int p1, int p2, long t){
        xpos = p1;
        oxvel = 50;
        oX = p1;
        ypos = p2;
        time = t;
        oyvel = -50;

    }

    public void update(){
        xvel = (oxvel*Math.cos(45));
        yvel = (oyvel*Math.sin(45)) + (9.8*time);
        if(!(xpos + xvel + 10 > getWidth())&&!(xpos + xvel < 0))
            xpos +=xvel;
        if(!(ypos + yvel + 10 > getHeight())&&!(ypos + yvel <= 0))
            ypos+=yvel;
        time++;
    }

    public void paint(Graphics g){
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.RED);
        g2d.fillOval((int)xpos, (int)ypos, 15, 15);
    }
}

【问题讨论】:

  • 您的物理特性似乎与渲染速率密切相关。这很可能是你的问题。此外,为什么时间是整数(或长整数)而不是双精度数?
  • 1- 确保您在某个时候调用 repaint 以便重新绘制组件,并且 2- 使用 paintComponentpaint,因为您正在破坏绘制链,它可以导致一些奇怪和 3- 在执行任何自定义绘画之前调用 super.paintComponent

标签: java physics projectile


【解决方案1】:

您有硬编码时间,在您的更新循环中,您只需将加速度乘以预先计算的时间步长(1 个任意单位,使用秒单位会更好),您假设每次都是相同的,这总是导致跳动的动作。您应该改为将 variable 时间步传递给方法并使用它。这意味着无论渲染的速度有多快,您都会获得平滑的运动。请记住,您可能会要求 1/60 秒的帧,但您不会总是得到准确的结果。

public void update(double time){
    xvel = (oxvel*Math.cos(45));
    yvel = (oyvel*Math.sin(45)) + (9.8*time);
    if(!(xpos + xvel + 10 > getWidth())&&!(xpos + xvel < 0))
        xpos +=xvel*time;
    if(!(ypos + yvel + 10 > getHeight())&&!(ypos + yvel <= 0))
        ypos+=yvel*time;
}

在整个循环中,您将测量实际时间步长并通过它。您可以使用System.currentTimeMillis(); 进行测量

long previousStep=System.currentTimeMillis();
public void gameLoop(){
    long newStep=System.currentTimeMillis();
    double frameTime=(newStep-previousStep)/1000.0;

    ball.update(frameTime);
    previousStep= newStep;
}

time 很可能不是long,而应该是double,以整数增量实时测量很难正确。

【讨论】:

  • 在更新中,应该也是xpos += xvel*timeypos += yvel*time,这可能是模拟加速的最初问题。
【解决方案2】:

Euler 方法对于忠实的物理模拟非常不利,尤其是当您采用与两帧之间的时间一样大的时间步长时。要么每帧执行 10-20 个模拟步骤,要么使用更高阶的积分方法。

即使使用欧拉方法,您也需要在微分系统的所有部分应用时间步长。原来如此

velocity += acceleration*timestep
position += velocity*timestep

如果你打算让它成为某种辛积分器,假设加速度是由梯度力场产生的并且只取决于位置,那么交换零件,先更新位置,

position += velocity*timestep
velocity += acceleration*timestep

【讨论】:

    猜你喜欢
    • 2018-03-19
    • 2020-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-23
    相关资源
    最近更新 更多