【问题标题】:How to Draw Projectile Trajectory with Unity3d's built-in Physics Engine?Unity3d内置物理引擎如何绘制弹道轨迹?
【发布时间】:2016-06-08 13:39:20
【问题描述】:

我正在开发一款游戏,该游戏将投掷对物理力做出反应的弹丸。我在游戏中使用了内置的 Unity Physics,但我正在绘制弹丸发射之前的轨迹。为此,我使用 LineRenderer 和一个简单的物理类来计算位置:

public class SlingPhysics
{
    private Vector3 HalfGravity;
    private float ForceMultiplier;

    public void Init(Vector3 gravity, float slingForce, float mass, float drag)
    {
        HalfGravity = gravity / 2.0f;
        ForceMultiplier = slingForce / mass / (1 + drag);
    }

    public Vector3 GetPosition(Vector3 start, Vector3 direction, float timeDelta)
    {
        Vector3 pos = direction * (timeDelta * ForceMultiplier);
        pos.y += (HalfGravity.y * timeDelta * timeDelta);
        return start + pos;
    }

    /// <summary>
    /// Computes an array of Trajectory object positions by time.
    /// </summary>
    /// <returns>Number of positions filled into the buffer</returns>
    /// <param name="startPos">Starting Position</param>
    /// <param name="direction">Direction (and magnitude) vector</param>
    /// <param name="timeIncrement">Time increment of the samples</param>
    /// <param name="yFloor">Minimum height, below which is clipped</param>
    /// <param name="positions">Buffer to fill with positions</param>
    public int GetPositions(Vector3 startPos, Vector3 direction, float timeIncrement, float yFloor, Vector3[] positions)
    {
        int maxItems = positions.Length;
        int i = 0;
        for (; i < maxItems; i++)
        {
            Vector3 pos = GetPosition(startPos, direction, timeIncrement * i);
            if (pos.y < yFloor)
                break;
            positions[i] = pos;
        }
        return i;
    }
}

这很有效,并且(有点令人惊讶)与弹丸在发射时最终行进的实际轨迹完全匹配,并由 Unity 物理引擎控制。

但是现在,我们决定在刚体上引入阻力,轨迹不再完美。我可以继续尝试更改我的物理模型以匹配 Unity 正在做的事情,但这似乎是一场失败的战斗。

有没有办法使用 Unity 物理引擎预先计算和绘制轨迹?

如果没有,Unity Physics 中如何以数学方式实现拖动和角拖动?

是否有 Unity (5.3.4) 物理实现的文档来源?

【问题讨论】:

  • 我搜索了同样的东西,但找不到任何官方文档。但是,自己测试它是相当容易的。我不记得我的头顶了,但是我使用了一个有阻力值的刚体,一个没有阻力值的刚体,只写了一个简单的脚本来模拟阻力,并尝试了几个典型的公式,结果证明是其中一个简单的。然后您仍然需要手动计算所有内容以匹配 Unity 的实现,因为它们没有提供任何您想要的 API。
  • Xarbrough,谢谢。尽管程序员的明智建议是避免追逐 Unity 的愚蠢,但我将追踪阻力公式并尝试一下。我的代码真的很简单,所以再复杂一点也不会害死我;希望到此为止。当下一个伟大的物理引擎问世时,我会跨过那座桥。

标签: c# unity3d


【解决方案1】:

我可以继续尝试更改我的物理模型以匹配 Unity 正在做

不,不要这样做。每当 Unity 更新时,像这样的物理东西就会中断。例如,Unity 4 和 Unity 5 的物理特性并不相同。不得不大量修改我的 Unity 4 物理代码以使其正常工作。

解决问题的最简单方法是计算任何东西。我这样做的方法是创建 两个 射弹。 Projectile1 是可以看到和射击的主要射弹。 Projectile2 是一个隐藏的弹丸,玩家看不到

在拖动模式下,拍摄Projectile2(隐藏),然后将其经过的路径或位置(Vector3)存储在List 中。使用该存储路径来绘制您的Projectile Trajectory

您只需要射击Projectile2(隐藏)一次并存储路径。如果在拖动模式下,手指、鼠标或拖动移动到另一个位置,那么您必须清除List,重新拍摄Projectile2(隐藏)一次,将位置存储到List,然后再次更新您的Projectile Trajectory

松开手指后,您现在可以射击玩家可见的Projectile1(主射弹)。

如果您使用lineRenderer,则SetVertexCount 的号码与您的List.Count 的号码相同。通过循环 List 中的位置可以轻松绘制线条。

无论 Unity 更新多少次,结果总是相同的。

【讨论】:

  • 我同意,尝试模仿 Unity Physics 是个坏主意,我只是没有更好的。我认为这是在正确的轨道上,但弹丸需要一些时间才能到达它的目标(这是一个弹弓游戏),所以如果我采用这种方法,轨迹会随着玩家的目标而严重滞后。有没有什么方法可以让我射出隐藏的弹丸并为它加快时间,这样它就不会滞后?
  • @ThisGuy 这是 2D 还是 3D 游戏?这取决于拍摄对象的速度和相机的视野,对此有解决方案。
  • 这是一款 3D 增强现实游戏。相机连接到弹弓补丁。随着设备移动,相机移动,因此轨迹移动。由于我们稍微降低了重力,弹丸的飞行速度相对较慢。
【解决方案2】:

计算阻力以匹配 Unity 引擎的方法是在 FixedUpdate 中计算并跟踪速度,然后更新阻力的速度。

此处提供了拖动的 Unity 公式: http://forum.unity3d.com/threads/drag-factor-what-is-it.85504/

确实很简单;关键部分是这样的:

velocity *= Mathf.Clamp01(1f - Drag * Time.fixedDeltaTime);

必须重新设计自定义物理类以要求时间增量为 Unity 的 Time.fixedDeltaTime(FixedUpdate 调用之间的时间)

public class SlingPhysics
{
    private Vector3 Gravity;
    private float Force, Mass, Drag;

    public void Init(Vector3 gravity, float force, float mass, float drag)
    {
        Gravity = gravity;
        Force = force;
        Mass = mass;
        Drag = drag;
    }

    /// <summary>
    /// Computes an array of Trajectory object positions by time.
    /// </summary>
    /// <returns>Number of positions filled into the buffer</returns>
    /// <param name="startPos">Starting Position</param>
    /// <param name="direction">Direction (and magnitude) vector</param>
    /// <param name="yFloor">Minimum height, below which is clipped</param>
    /// <param name="positions">Buffer to fill with positions</param>
    public int GetPositions(Vector3 startPos, Vector3 direction, float yFloor, Vector3[] positions)
    {
        float timeIncrement = Time.fixedDeltaTime;

        int maxItems = positions.Length;
        int i = 0;
        Vector3 velocity = direction * Force / Mass;
        Vector3 pos = startPos;
        for (; i < maxItems; i++)
        {
            velocity += Gravity * timeIncrement;
            velocity *= Mathf.Clamp01(1f - Drag * timeIncrement);
            pos += velocity * timeIncrement;
            if (pos.y < yFloor)
                break;
            positions[i] = pos;
        }
        return i;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-25
    • 2011-03-02
    • 2014-09-12
    • 2017-01-18
    相关资源
    最近更新 更多