【问题标题】:Unity player collision with horizontal small collidersUnity 玩家与水平小碰撞器的碰撞
【发布时间】:2019-01-25 01:46:10
【问题描述】:

我知道标题不是很清楚,但这是我的问题:

我有一个玩家(只是一个带有刚体、碰撞器和运动脚本的立方体),我有一个由 1 x 1 x 1 的小立方体(带有盒子碰撞器的立方体)组成的地板。

出于某种我不知道的原因,当我的玩家立方体掉落并试图与地板水平碰撞时,他只是逐步通过......但是希望他像垂直一样被立方体阻挡。任何帮助将不胜感激;)

这是场景的样子

这是一个立方体对象

这里是播放器对象

这是玩家穿过地板的 gif 图像

这是我的 c# 玩家移动脚本(我知道它很糟糕,但我更愿意把它放在这里以防它与我的问题有关):

void ApplyMovement()
{        

 transform.position += new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));

}

如果您需要更多信息来帮助我,请告诉我,我会尽快提供。

【问题讨论】:

  • 你是否为你的立方体和播放器附加了刚体组件?
  • 不,我只是在播放器中添加了一个 ribidbody。我已经尝试向立方体添加刚体,但无济于事。
  • 让我们看看你的PlayerMovement 脚本的其余部分。直接操纵transform.position 会导致这样的问题(您应该改为施加力或操纵Rigidbody 的速度,以便物理引擎可以做它的事情)。 FWIW,您不需要在地板上使用Rigidbody 组件。这是为了让物理引擎能够操纵GameObject运动,而它们已经拥有的BoxColllider 足以让它们充当静态“地板”。

标签: c# unity3d collision mesh-collider


【解决方案1】:
  1. 价值

    new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"))
    

    取决于帧率。这意味着帧速率越快,对象移动的速度就越快。这通常不是你想要的。而是使用Time.deltaTime

    // Adjust the speed in the inspector
    public float speedMultiplicator = 1;
    
    //...
    
    new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * speedMultiplicator * Time.deltaTime
    

    获得与帧速率无关的运动。另请参阅Input.GetAxis 中的示例。

  2. 在处理RigidBody 时,切勿直接更改transform.position(和rotation)!

    如果您想要RigidBody 跳转到某个位置而不是使用

    rigidBody.position = transform.position + ...;
    

    但是,您想要的是平稳的运动,以保持碰撞检测的完整性。所以你应该改用RigidBody.MovePosition

    rigidBody.MovePosition(transform.position + ...);
    

    您不必处理武力等。

  3. 还将RigidBody 组件添加到地板对象。即使物体没有移动,这也会提高碰撞检测(当然以物理引擎的性能为代价)。而且由于对象不应该移动设置

    • isKinematic -> 是的
    • 使用重力 -> 错误

    你也可以设置freeze positionfreeze rotation

  4. 在地板和玩家对象上设置Collision Detection -> Continous Dynamic
    这改进了碰撞检测并在帧之间寻找碰撞。
    但是请注意,动态检测非常昂贵,因此只有在对象过快仍然存在问题时才使用它。

  5. 在播放器上,您可能还想使用interpolate

  6. 终于

    请注意,连续碰撞检测旨在作为一个安全网,以在物体相互穿过的情况下捕捉碰撞,但不会提供物理上准确的碰撞结果,因此您仍可以考虑减小时间管理器检查器 如果您遇到快速移动物体的问题,可以使模拟更加精确。

有关详细信息,请参阅RigidBody manualColliders manual

【讨论】:

    【解决方案2】:

    我重新创建了您最后描述的场景。我将您的“ApplyMovement”代码放在“更新”中。我基本上能够重现你的结果。

    在我看来,问题可能是在播放器上冻结位置 X/Z。我认为既然你这样做了,你就是在告诉刚体组件,作为碰撞分辨率和物理模拟的一部分,不允许修改对象的 X/Z 位置。当我关闭这两个时,我得到的结果(我认为)更接近你正在寻找的结果。

    请注意:您的“ApplyMovement”代码是帧锁定的,这意味着您的播放器将以不同的速度和不同的帧速率移动。要解决此问题,您需要将 Input.GetAxis 值乘以 Time.deltaTime。

    另外,如果你的玩家移动得太快,它仍然能够通过碰撞并导致奇怪的行为,所以一定要将玩家的最大移动速率限制在某个合理的值。

    【讨论】:

      【解决方案3】:

      您应该对角色的Rigidbody 施加一个力,而不是直接操纵transform.position(这会阻止物理引擎解决碰撞)。您还冻结了Rigidbody 上的 X 和 Z 位置;您不希望这样,因为它完全阻止了 Rigidbody 操纵这些值。

      首先在脚本中的某处获取对Rigidbody 的引用,而不是transform.postion += ...(最好在Awake() 方法中完成):

      private Rigidbody _body;
      private void Awake() {
          _body = GetComponent<Rigidbody>();
      }
      

      然后确保根据您的输入构建的向量被应用于对象的“运动”,而不是其位置:

      Vector3 inputVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
      // You can multiply this vector by a float to adjust "speed"
      
      _body.ApplyForce(inputVector, ForceMode.VelocityChange);
      

      最后,您应该阅读不同的 ForceMode 选项并决定哪一个适合您的偏好:https://docs.unity3d.com/ScriptReference/ForceMode.html

      别忘了这应该发生在FixedUpdate(),而不是Update()(所有物理操作都应该在FixedUpdate() 中完成)


      附带说明,您的刚体仍有可能向上移动过快并相互穿过。即使您使用力和速度,这也是可能的,因此如果您遇到这种情况,请调查Collision Detection Modes。 TLDR;它们是性能与准确性权衡的设置。

      【讨论】:

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