空气曲棍球比赛 - 如果移动太快,球员蝙蝠会经过冰球

Gra*_*eme 6 c# unity-game-engine

我目前正在Unity3d开发一款空气曲棍球比赛.我遇到的问题是,当玩家试图过快地击中冰球时,玩家最终会通过冰球,因此没有碰撞.如果玩家保持静止并且冰球击中玩家或者玩家以缓慢的速度击中冰球,则游戏将按照预期完美地运行.

玩家有一个使用胶囊对撞机进行连续碰撞检测的刚体.冰球还具有连续动态碰撞检测的刚体和带凸面的网格对撞机.

我尝试将固定时间步长设置为0.01,但没有效果.这是玩家运动的脚本:

void ObjectFollowCursor()
{
    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    Vector3 point = ray.origin + (ray.direction * distance);

    Vector3 temp = point;
    temp.y = 0.2f; // limits player on y axis

    cursorObject.position = temp;
}
Run Code Online (Sandbox Code Playgroud)

这是冰球与玩家碰撞时的代码:

// If puck hits player
if(collision.gameObject.tag == "Player")
{
    Vector3 forceVec = this.GetComponent<Rigidbody>().velocity.normalized * hitForce;
    rb.AddForce(forceVec, ForceMode.Impulse);
    Debug.Log ("Player Hit");
}
Run Code Online (Sandbox Code Playgroud)

任何帮助将非常感激.谢谢.

Jor*_*tos 5

您遇到的问题是"隧道".

发生这种情况是因为您的对象正在高速移动,并且在该特定帧中未检测到碰撞.在框架中n,球就在球棒的前面,但是当n+1计算出球时,球已经移动到球棒后面,因此完全"错过"了球.

这是一个常见的问题,但有解决方案.

我建议你学习这个脚本并尝试在你的游戏上实现.

这不是我的代码: 来源:http://wiki.unity3d.com/index.php?title = DontGoThroughThings

using UnityEngine;
using System.Collections;

public class DontGoThroughThings : MonoBehaviour
{
       // Careful when setting this to true - it might cause double
       // events to be fired - but it won't pass through the trigger
       public bool sendTriggerMessage = false;  

    public LayerMask layerMask = -1; //make sure we aren't in this layer 
    public float skinWidth = 0.1f; //probably doesn't need to be changed 

    private float minimumExtent; 
    private float partialExtent; 
    private float sqrMinimumExtent; 
    private Vector3 previousPosition; 
    private Rigidbody myRigidbody;
    private Collider myCollider;

    //initialize values 
    void Start() 
    { 
       myRigidbody = GetComponent<Rigidbody>();
       myCollider = GetComponent<Collider>();
       previousPosition = myRigidbody.position; 
       minimumExtent = Mathf.Min(Mathf.Min(myCollider.bounds.extents.x, myCollider.bounds.extents.y), myCollider.bounds.extents.z); 
       partialExtent = minimumExtent * (1.0f - skinWidth); 
       sqrMinimumExtent = minimumExtent * minimumExtent; 
    } 

    void FixedUpdate() 
    { 
       //have we moved more than our minimum extent? 
       Vector3 movementThisStep = myRigidbody.position - previousPosition; 
       float movementSqrMagnitude = movementThisStep.sqrMagnitude;

       if (movementSqrMagnitude > sqrMinimumExtent) 
        { 
          float movementMagnitude = Mathf.Sqrt(movementSqrMagnitude);
          RaycastHit hitInfo; 

          //check for obstructions we might have missed 
          if (Physics.Raycast(previousPosition, movementThisStep, out hitInfo, movementMagnitude, layerMask.value))
              {
                 if (!hitInfo.collider)
                     return;

                 if (hitInfo.collider.isTrigger) 
                     hitInfo.collider.SendMessage("OnTriggerEnter", myCollider);

                 if (!hitInfo.collider.isTrigger)
                     myRigidbody.position = hitInfo.point - (movementThisStep / movementMagnitude) * partialExtent; 

              }
       } 

       previousPosition = myRigidbody.position; 
    }
}
Run Code Online (Sandbox Code Playgroud)


31e*_*384 2

您尝试连续碰撞检测(CCD)是正确的。虽然存在一些限制(特别是在这种情况下,您想要将 CCD 与两个移动物体一起使用,而不是一个移动物体和一个静态物体),但它是为这种场景而设计的。Rigidbody 文档讨论了这些约束:

将碰撞检测模式设置为连续,以防止刚体穿过任何静态(即非刚体)网格碰撞体。将其设置为“连续动态”还可以防止刚体穿过碰撞检测模式设置为“连续”或“连续动态”的任何其他受支持的刚体。Box、Sphere 和 CapsuleColliders 支持连续碰撞检测。

综上所述,puck 和 paddle 都需要设置为 Continuous Dynamic,并且都需要是 Box-、Sphere- 或 Capsule Colliders。如果您可以使这些约束适用于您的游戏,您应该能够获得连续的碰撞检测,而无需自己编写。


关于 Unity CCD 的注释值得重复:

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

但由于您是手动指定碰撞反应,因此这可能不是问题。