我编写了一个相当简单的java应用程序,它允许您拖动鼠标,并根据您拖动鼠标的长度,它会朝那个方向射出一个球,并在球移动时从墙壁上弹起。

这是一个快速截图:
替代文本 http://img222.imageshack.us/img222/3179/ballbouncemf9.png

屏幕上的每个圆圈都是一个 Ball 对象。球的运动被分解为 x 和 y 向量;

public class Ball {
    public int xPos;
    public int yPos;
    public int xVector;
    public int yVector;

    public Ball(int xPos, int yPos, int xVector, int yVector) {
        this.xPos = xPos;
        this.yPos = yPos;
        this.xVector = xVector;
        this.yVector = yVector;
    }

    public void step()
    {
        posX += xVector;
        posY += yVector;

        checkCollisions();
    }

    public void checkCollisions()
    {
        // Check if we have collided with a wall
        // If we have, take the negative of the appropriate vector
        // Depending on which wall you hit
    }

    public void draw()
    {
        // draw our circle at it's position
    }
}

这很好用。所有的球都从一面墙弹到另一面墙。

然而,我决定希望能够包含重力的影响。我知道物体以 9.8m/s 的速度向地球加速,但我不直接知道如何将其转换为代码。我意识到 yVector 会受到影响,但我对此的实验没有达到我想要的效果。

理想情况下, 我希望能够为该程序添加一些重力效果,并允许球在落到“地面”之前弹跳几次。

我怎样才能创造出这种弹力、重力效果?我必须如何操纵每一步球的速度矢量?当它撞到“地面”时必须做什么,以便我可以让它再次反弹,但比上次弹得短一些?

感谢任何帮助为我指明正确的方向。


谢谢大家的评论!它已经运行得很好了!

在我的step()中,我像人们建议的那样向我的yVector添加了一个重力常数,这是我的checkCollision():

public void checkCollision()
{
    if (posX - radius < 0)              // Left Wall?
    {
        posX = radius;              // Place ball against edge
        xVector = -(xVector * friction);
    }
    else if (posX + radius > rightBound) // Right Wall?
    {
        posX = rightBound - radius;     // Place ball against edge
        xVector = -(xVector * friction);
    }

    // Same for posY and yVector here.
}

然而,球将继续在地板上滑动/滚动。我认为这是因为我只是在每次反弹时取其矢量的百分比(90%),并且它永远不会真正为零。我是否应该添加一个检查,如果 xVector 变为某个绝对值,我应该将其更改为零?

有帮助吗?

解决方案

你有什么要做的就是不断地减去小的一定从你yVector(的东西,代表您9.8米/秒)。当球正在下降(yVector已经是负),这将使得它更快。时,它的上升(yVector为正),将慢下来。

这将不占摩擦,所以事情应该反弹几乎永远。

EDIT1: 为了说明摩擦,只要它颠倒(和你扭转标志),较低的绝对数量一点。就像如果它击中在yVector = -500,当你扭转的迹象,使这+480而不是+500。你或许应该做同样的事情,以xVector从反弹一侧到另一侧停下来。

EDIT2: 另外,如果希望反应以“空气摩擦”,由一个非常小的量的每个调整减少这两种载体。

EDIT3: 关于东西滚来滚去的底部永远 - 根据您的数字有多高,也可能是两件事情之一。无论您的数字很大,它只是似乎采取永远完成,或者你取整和您载体总是5或东西。 (90%的5为4.5,因此它可能向上舍入至5)。

我会打印出调试语句,看看矢量号码等。如果他们去的地方约5,只是呆在那里,那么您可以使用您的截断部分,以4而不是四舍五入回到5,如果它不断下降,并最终停止的功能,那么你可能需要调高摩擦系数

如果你不能找到一个简单的“四舍五入”功能,您可以使用(0.9 *矢量) - 1,从现有的方程式中减去1应该做同样的事情。

其他提示

当球都在地面上滚动时,是的,检查速度是否低于某个最小值,如果是,则将其设置为零。如果您查看这种理想化运动背后的物理原理,并与现实世界中发生的情况进行比较,您会发现单个方程不能用于解释真实球停止移动的事实。

顺便说一句,您所做的称为数值积分的欧拉方法。事情是这样的:

  • 从运动的运动学方程开始:
    x(t) = x0 + vx*t + 0.5*axt^2
    y(t) = y0 + vy
    t + 0.5*ayt^2
    vx(t) = vx0 + ax
    t
    vy(t) = vy0 + ay*t
    其中 x 和 y 是位置,vx 和 vy 是速度,ax 和 ay 是加速度,t 是时间。x0、y0、vx0 和 vy0 是初始值。这描述了在没有任何外力的情况下物体的运动。

  • 现在应用重力:
    ay = -9.8 m/s^2
    到目前为止,没有必要做任何棘手的事情。我们可以随时使用这个方程求解每个球的位置。

  • 现在添加空气摩擦力:由于它是一个球形球,我们可以假设它的摩擦系数为 c。如何模拟空气摩擦通常有两种选择。它可以与速度或速度的平方成正比。让我们使用正方形:
    斧头=-cvx^2
    ay = -c
    vy^2 - 9.8
    因为加速度现在取决于速度,而速度不是恒定的,所以我们必须积分。这很糟糕,因为没有办法手动解决这个问题。我们必须进行数值积分。

  • 我们采用离散时间步长 dt。对于欧拉方法,我们只需将上述方程中所有出现的 t 替换为 dt,并使用前一个时间步的值代替初始值 x0、y0 等。所以现在我们的方程看起来像这样(伪代码):

    // 保存之前的值
    xold=x;
    yold = y;
    vxold = vx;
    vyold = vy;

    // 更新加速度
    斧头=-cvxold^2;
    ay = -c
    维奥尔^2 - 9.8;

    // 更新速度
    vx = vxold + 斧头dt;
    vy = vyold + ay
    dt;

    // 更新位置
    x = xold + vxold*dt + 0.5*axdt^2;
    y = yold + vyold
    dt + 0.5*ay*dt^2;

这是一个近似值,因此不会完全正确,但看起来不错。问题是,对于更大的时间步长,误差会增加,因此如果我们想要准确地模拟真实球的移动方式,我们必须使用非常小的 dt 值,这会导致计算机上的准确性问题。为了解决这个问题,有更复杂的技术。但如果你只是想同时看到看起来像重力和摩擦力的行为,那么欧拉的方法就可以了。

在具有每时间片由在格兰ý向下方向加速球应用重力的影响。正如比尔ķ建议,这是因为从“yVector”做减法一样简单。当球击中底部,yVector = -yVector,所以现在它的向上移动,但仍然accelarating向下。如果你想使球最终停止跳动,你需要做的碰撞略有弹性,基本上是在y向上的方向移除一些速度,可能通过而不是“yVector = -yVector”,使其“yVector = -0.9 * yVector”。

public void step()
{
    posX += xVector;
    posY += yVector;

    yVector += g //some constant representing 9.8

    checkCollisions();
}

在checkCollisions(),则应该反转和0 1之间和乘yVector由若干时它反弹在地面上。这应该给你想要的效果

这是一个弹道运动。这样你就得到了关于x轴的线性运动和y轴的均匀加速移动。

的基本思想是,y轴将遵循方程:

y = y0 + v0 * t + (0.5)*a*t^2

或者,在C代码,例如:

float speed = 10.0f, acceleration = -9.8f, y = [whatever position];

y += speed*t + 0.5f*acceleration*t^2;

在哪里这里我用TIEM参数化。但是,你可以使用托里切利:

v = sqrt(v0^2 + 2*acceleration*(y-y0));

和,在这种模式下,你必须保持v和y的最后的值。

最后,我已经做了类似使用具有DT(时刻的差分)所述第一模型的东西固定在1/60秒(60 FPS)。

好,这两种模式给出良好的实样的结果,但SQRT(),例如,是昂贵的。

您真的想模拟一下重力那样 - 它是所有创造力作用随着时间的推移改变对象的速度。你走一步每一次,你改变你的球一点点的速度,以“拉”向它的小部件的底部。

为了应对无摩擦/弹跳球落户问题,你需要做的“地”碰撞发挥不仅仅是严格反射不同的效果 - 它应该从球中移除一些能量,使其反弹在一个较小的速度向后撞击地面会比否则后。

这是你一般要在这些类型的有弹性的可视化要做的另一件事情就是给在地侧身一些摩擦一样,所以,当它击中地面所有的时间,它最终将滚动停止。

我同意“比尔K”说,并想补充一点,如果你希望他们“摆平”,您将需要减少x和y矢量随着时间的推移(施加阻力)。这将是一次非常小的量,所以你可能需要从int更改向量浮点型,或者只有1每隔几秒钟减少他们。

您想要做的是改变xVector和yVector的数值模拟重力和摩擦力。这实在是很简单的事情。 (需要将所有的变量改为浮动。当谈到时间来绘制,刚轮的浮动。)

在您的阶跃函数,更新球的位置之后,你应该做的是这样的:

yVector *= 0.95;
xVector *= 0.95;
yVector -= 2.0;

这缩放X和Y的速度略有下降,让你的球,最终停止移动,然后施加恒定的向下的“加速”的Y值,它会积累比“放缓”更快,使钢球脱落

这是你真正想要做的近似值。你真正想要的是让代表你的球的加速度矢量。每走一步,你就那么点,与恒定重力矢量稍微改变球的加速度矢量产品。但我认为,我的更复杂的比你想要得到的,除非你正在寻找一个更真实的物理模拟。

  

当它击中必须做什么   “地面”,这样我可以允许它   再次向上反弹

如果假定一个完美的碰撞(即所有的能量都保守的)所有你必须做扭转,这取决于壁被打速度标量中的一个的标志。

例如,如果球击中的右侧或左侧壁revese在x标量分量和离开在y标量分量是相同的:

 this.xVector = -this.xVector;

如果球击中的顶部或底部壁扭转在y标量分量和离开的X标量分量是相同的:

 this.yVector = -this.yVector;
  

但略短然后以前的   时间?

在这种情况下的一些能量将在与壁碰撞丢失所以只需添加在损耗因子各壁被命中的时间采取的一些的速度的:

 double loss_factor = 0.99;
 this.xVector = -(loss_factor * this.xVector);
 this.yVector = -(loss_factor * this.yVector;
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top