【问题标题】:Ball Mechanics - Is this the best approach?Ball Mechanics - 这是最好的方法吗?
【发布时间】:2019-09-28 11:14:04
【问题描述】:

早安,

我想编写一个不断移动的球 (object3) 在两个静止物体 (object1, object2) 之间传递,并能够动态设置传球轨迹的最大高度 Y .

您认为为这个概念编写球物理的最佳方法是什么?

我研究过在带有刚体的默认球体上使用addForce。似乎应该有一个方程来表达object3object1 的x 到object2 的x 的轨迹...在已知的,给定的speed,已知的,设置@ 987654332@,以及已知的重力环境。

但是,目前我有一个 Vector3.Lerp 在每个 FixedUpdate() 上的两个对象之间插入球,t 表示为:

`(Mathf.Sin(speed * Time.time) + 1.0f) / 2.0f;`

一切正常,但是使用这种方法,似乎没有明确的方法可以将height 添加到球路径的轨迹中。我考虑将height 添加到object2 中的Y 值,直到球到达一半,然后将其设置回原来的Y 位置……但感觉不对!想法?

谢谢!

【问题讨论】:

  • 您能否为您想要实现的目标添加一个视觉效果.. 确定是我,但目前我无法想象您的目标到底是什么。据我了解,您希望球在两个给定对象之间来回移动..但是height 在哪里以及如何发挥作用?
  • @derHugo 感谢您的写作。刚刚添加了一张图片。

标签: unity3d game-physics


【解决方案1】:

好吧,如果我理解正确,你目前正在做的事情

privte void FixedUpdate()
{
    var factor = (Mathf.Sin(speed * Time.time) + 1.0f) / 2.0f;
    object1.MovePosition(Vector3.Lerp(object2.position, object3.position, factor));
}

object1object2 位置之间移动乒乓球,但仅限平面。

现在假设对象只会在 XZ 平面内移动,并且永远不会有不同的 Y 位置,以便获得一个高度曲线,您可以单独处理: - 像以前一样在两个位置之间插值 - 用 sinus 或任何其他数学曲线函数单独计算 Y 位置 - 对于现实的物理可能实际上是抛物线

看起来有点像

public class Example : MonoBehaviour
{
    public Rigidbody object1;
    public Transform object2;
    public Transform object3;

    // adjust in the Inspector
    public float speed = 1;
    public float Amplitude = 0;

    // Just for debug
    [Range(0, 1)] [SerializeField] private float linearFactor;
    [SerializeField] private float yPosition;

    private void FixedUpdate()
    {
        // This always returns a value between 0 and 1 
        // and linearly pingpongs forth and back
        linearFactor = Mathf.PingPong(Time.time * speed, 1);
        // * Mathf.PI => gives now a value 0 - PI
        // so sinus returns correctly 0 - 1 (no need for +1 and /2 anymore)
        // then simply multiply by the desired amplitude
        var sinus = Mathf.Sin(linearFactor * Mathf.PI);
        yPosition = sinus * Amplitude;

        // As before interpolate between the positions
        // later we will ignore/replace the Y component
        var position = Vector3.Lerp(object2.position, object3.position, linearFactor);

        object1.MovePosition(new Vector3(position.x, yPosition, position.z));
    }
}


您还可以选择尝试在 Y 方向添加一些倾倒,以使垂直运动更加逼真(达到峰值时减速)。我尝试使用倒置的SmoothStep

// just for debug
[Range(0, 1)] [SerializeField] private float dampedSinusFactor;
[Range(0, 1)] [SerializeField] private float linearFactor;
[SerializeField] private float yPosition;

private void FixedUpdate()
{
    // Use two different factros:
    // - a linear one for movement in XZ
    // - a smoothed one for movement in Y (in order to slow down when reaching the peak ;) )
    linearFactor = Mathf.PingPong(Time.time * speed, 1);
    dampedSinusFactor = InvertSmoothStep(linearFactor);

    // * Mathf.PI => gives now a value 0 - PI
    // so sinus returns correctly 0 - 1 ()
    // then simply multiply by the desired amplitude
    var sinus = Mathf.Sin(dampedSinusFactor * Mathf.PI);
    yPosition = sinus * Amplitude;

    // later we will ignore/replace the Y component
    var position = Vector3.Lerp(object2.position, object3.position, linearFactor);

    object1.position = new Vector3(position.x, yPosition, position.z);
}

// source: https://stackoverflow.com/a/34576808/7111561
private float InvertSmoothStep(float x)
{
    return x + (x - (x * x * (3.0f - 2.0f * x)));
}

但是对于缓慢的动作,这看起来有点奇怪。但是您可以提出任何其他数学曲线,从而导致x=[0,1] 的预期行为;)

【讨论】:

  • 非常感谢!我现在将尝试实现这一点。
  • 很高兴为您提供帮助 :) 顺便说一句,如果您希望这更像物理学,您可能会使用抛物线而不是窦;)
  • 好的,那我先试试!是的,我绝对希望它代表一个在物理世界中两个物体之间移动的球。
猜你喜欢
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 2011-05-30
  • 2015-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多