【问题标题】:How to get Direction after cueBall collide with any ball in unity3d? Like in 8 ball poolcueBall与unity3d中的任何球碰撞后如何获得方向?就像在 8 球池中一样
【发布时间】:2021-09-12 22:54:18
【问题描述】:

嗨! 我正在使用统一 3d C# 制作类似 8 球池的 3d 球池。 A 是 que 球,我知道 Dir1。我想计算 Dir2。我正在使用 Raycast 以获得联系点。

【问题讨论】:

  • 会用 B 位置减去 C 位置来得到方向 Vector 并使用 AddForce(Vector3 force, ForceMode.Force) 方法施加力;工作吗?
  • @Armin no ... OP 希望在实际物理发生之前预览行;)

标签: c# unity3d prediction direction


【解决方案1】:

如果你真的想手动

您宁愿使用Physics.SphereCast(根据您的球形状)而不是Raycast,或者您也可以使用Rigidbody.SweepTest 来获取如果您反对的命中信息移动。

两者都为您提供信息

  • 是否被击中(例如,通过标签检查首先击中的是墙还是另一个球)

  • 两者都给你一个RaycastHit,其中包含详细信息,例如

    • point具体联系方式
    • distance 球在击中某物之前行进了多远(例如,用于计算已经应用的阻尼/台面摩擦)
    • normal 您击球的表面,因此您可以从中计算出两个球的新方向
    • 当然最重要的是哪个物体被击中,因此您也可以开始对该球进行新的计算

其余的是The Math and Physics of BillardPhysics of Billard 等,你会发现完整的答案对于这个页面来说是复杂的;)

在手动计算物理时,有很多事情需要考虑,首先你需要确定你想要的实际程度。有旋转、摩擦、跳跃,你知道在现实世界中根本不存在任何完全弹性的碰撞......所以男孩,如果你要手动预先计算所有这些,你也可以自己写物理引擎;)


使用现有的物理,完全不用自己计算

现在作为所有这些的完全替代方法,它根本不需要您计算任何东西

您可以模拟整个物理学!

你可以

  • 存储所有球的当前位置(以便以后恢复)
  • 在循环中使用Physics.Simulate,作为条件检查两个调用之间是否有任何球体移动 -> 如果没有(或在某个预览时间之后)则中断。
  • 每一步都会跟踪所有球的位置
  • 循环中断后重置所有位置和速度

=> 你已经获得了 LineRenderer 每个球的所有跟踪点;)

您甚至可以使用位置来爱自己的球,而不是再次使用物理来显示实际的运动;)

对于大型系统,这当然会导致巨大的延迟(也取决于您的目标预览时间范围)。但我会说,对于有限数量的球来说,这应该没问题。

这是我在几分钟内拼凑起来的一小段代码(当然不完美)

public class Example : MonoBehaviour
{
    public Ball[] balls;

    public Ball whiteBall;

    public Vector3 direction;
    public float force;

    private class TransformData
    {
        public Vector3 Position;
        public Quaternion Rotation;

        private readonly Transform _transform;

        public TransformData(Transform transform)
        {
            _transform = transform;
            Update();
        }

        public void Update()
        {
            Position = _transform.position;
            Rotation = _transform.rotation;
        }
    }

    public float maxPreviewTime = 10;

    public bool continousUpdates;
    
    private const float physicsSteps = 0.02f;

    private readonly Dictionary<Ball, TransformData> initialPositions = new Dictionary<Ball, TransformData>();
    private readonly Dictionary<Ball, List<Vector3>> simulatedPositions = new Dictionary<Ball, List<Vector3>>();

    private void Awake()
    {
        foreach (var ball in balls)
        {
            initialPositions.Add(ball, new TransformData(ball.transform));
            simulatedPositions.Add(ball, new List<Vector3>());
        }
    }

    private void Update()
    {
        if (continousUpdates)
        {
            UpdateLines();
        }

        if (Input.GetKeyDown(KeyCode.Space))
        {
            whiteBall.Rigidbody.AddForce(direction.normalized * force, ForceMode.Impulse);
        }
    }

    [ContextMenu("Update Preview Lines")]
    public void UpdateLines()
    {
        foreach (var transformData in initialPositions.Values)
        {
            transformData.Update();
        }

        foreach (var list in this.simulatedPositions.Values)
        {
            list.Clear();
        }

        Physics.autoSimulation = false;

        var somethingChanged = true;
        var simulatedTime = 0f;

        whiteBall.Rigidbody.AddForce(direction.normalized * force, ForceMode.Impulse);

        while (somethingChanged && simulatedTime < maxPreviewTime)
        {
            somethingChanged = false;

            Physics.Simulate(physicsSteps);

            foreach (var kvp in simulatedPositions)
            {
                var ball = kvp.Key;
                var positions = kvp.Value;
                var currentPosition = ball.transform.position;

                var hasChanged = positions.Count == 0 || (positions.Count > 0 && currentPosition != positions[positions.Count - 1]);

                if (hasChanged)
                {
                    positions.Add(currentPosition);
                }

                somethingChanged = somethingChanged || hasChanged;
            }

            simulatedTime += physicsSteps;
        }

        foreach (var kvp in initialPositions)
        {
            kvp.Key.Rigidbody.velocity = Vector3.zero;
            kvp.Key.Rigidbody.angularVelocity = Vector3.zero;
            kvp.Key.Rigidbody.position = kvp.Value.Position;
            kvp.Key.Rigidbody.rotation = kvp.Value.Rotation;
        }

        foreach (var kvp in simulatedPositions)
        {
            var ball = kvp.Key;
            var positions = kvp.Value;

            ball.Line.positionCount = positions.Count;
            ball.Line.SetPositions(positions.ToArray());
        }

        Physics.autoSimulation = true;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多