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

时间:2015-11-20 15:26:17

标签: c# unity3d

我目前正在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;
}

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

// 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");
}

非常感谢任何帮助。谢谢。

2 个答案:

答案 0 :(得分: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; 
    }
}

答案 1 :(得分:2)

你尝试连续碰撞检测(CCD)是对的。存在一些约束(特别是在这种情况下,您希望使用具有两个移动对象的CCD而不是一个移动对象和一个静态对象),但它是针对这种情况设计的。 The Rigidbody documentation进入了这些限制:

  

将碰撞检测模式设置为连续以防止   刚体穿过任何静态(即非刚体)   MeshColliders。将其设置为连续动态以防止   刚体穿过任何其他支撑的刚体   碰撞检测模式设置为连续或连续动态。   Box-,Sphere-和。支持连续碰撞检测   CapsuleColliders。

总而言之,冰球和球拍都需要设置为连续动态,并且都需要是Box,Sphere或Capsule Colliders。如果您可以使这些约束适用于您的游戏,您应该能够在不自己编写的情况下获得连续的碰撞检测。

有关Unity的CCD的重复说明:

  

请注意,连续碰撞检测旨在作为安全网   在物体否则会通过的情况下捕捉碰撞   通过彼此,但不会提供物理上准确的碰撞   结果,因此您可能仍会考虑减少固定的时间步长   TimeManager检查器中的值,以使模拟更多   如果遇到快速移动物体的问题,请准确无误。

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