Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Unity3D设置速度不会在OnCollisionCenter中立即生效_C#_Unity3d_Rigid Bodies - Fatal编程技术网

C# Unity3D设置速度不会在OnCollisionCenter中立即生效

C# Unity3D设置速度不会在OnCollisionCenter中立即生效,c#,unity3d,rigid-bodies,C#,Unity3d,Rigid Bodies,我有一个简单的脚本,可以在与某物发生碰撞时将速度设置为零,但似乎无法立即工作: using System.Collections; using System.Collections.Generic; using UnityEngine; public class MoveController : MonoBehaviour { [SerializeField] private float shootVelocity=30f; void Start () {

我有一个简单的脚本,可以在与某物发生碰撞时将速度设置为零,但似乎无法立即工作:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoveController : MonoBehaviour {

    [SerializeField]
    private float shootVelocity=30f;

    void Start () {

    }

    private void OnGUI()
    {
        if(GUI.Button(new Rect(0,0,100,100), "shoot"))
        {
            GetComponent<Rigidbody>().velocity = shootVelocity * Vector3.forward;
        }
    }

    private void OnCollisionEnter(Collision collision)
    {
        GetComponent<Rigidbody>().velocity = Vector3.zero;
        GetComponent<Rigidbody>().isKinematic = true;
    }

}
我还做了一个例子来说明这个问题

碰撞发生后,让球立即停下来是非常重要的


如何做到这一点?

物理学就是这样工作的

如果运动物体的速度更高,它的动量也会更大,因此需要更多的时间才能停止

您可以尝试像这样更新代码以提高效率

public class MoveController : MonoBehaviour 
{

    [SerializeField]
    private float shootVelocity=30f;

    Rigidbody rb;
    void Start () 
    {
        rb = GetComponent<Rigidbody>();
    }

    private void OnGUI()
    {
        if(GUI.Button(new Rect(0,0,100,100), "shoot"))
        {
            rb.velocity = shootVelocity * Vector3.forward;
        }
    }

    private void OnCollisionEnter(Collision collision)
    {
        rb.isKinematic = true;  
        rb.velocity = Vector3.zero;
        rb.angularVelocity = Vector3.zero;
    }
}

希望这对你有所帮助:

你会遇到这个问题,因为物理计算是在特定的时间步之后进行的,你可以在这里阅读更多关于它的内容

想象一下这种情况,对象没有碰撞这一帧,下一帧第一个对象移动了一段距离,现在它正在与第二个对象碰撞,但它已经在该对象内部的某个位置,因为它移动得非常快,然后检测到碰撞,但已经太晚了。有时,如果对象非常小和/或移动速度非常快,则不会检测到碰撞,因为当它第一次检查对象1时在对象2之前,当它第二次检查对象1时已通过对象2,因此未检测到碰撞

一种方法是将这个时间步长变小,这样Unity会更频繁地检查碰撞,但这会增加开销,特别是如果你有大量的物理计算,并且球体停止时的位置永远不会是完美的。我建议你用这个来写你自己的计算,和Unity的模拟一起工作

我将给你们一个例子,如何计算完美的停止位置,当两个物体在一个点上刚刚接触时,如果物体通过另一个物体时总是朝着相同的方向移动,并且你们正在使用两个球体碰撞器,你们知道它们的半径在世界范围内。让我们将它们命名为radius1和radius2,参数t表示对象需要向前/向后移动多少才能获得完美的碰撞位置

当检测到冲突时,您可以执行以下计算

Vector3 firstVector=transform.position-CollidateObject.transform.position; 矢量3第二矢量=方向; 浮动r=半径1+半径2

第一个向量-第二个向量*t.sqrMagnitude=r^2

展开你的方程式

或者在文本模式下=\sqrt{2x_2^2t^2+z_2^2t^2-2x_1x_2t-2z_1x_2t-2z_1z_2t+x_1^2+2z_1^2}

现在求解t,你会得到两个值,因为给定方向有两个完美的碰撞位置,一个在第二个对象之前,一个在第二个对象之后

你可以得到这个等式

它可能看起来很复杂,但你可以看到,t的这两个解只有一个区别,负号和它的其余部分是一样的,你可以把它分成3个变量,使它看起来很简单,这只是集中在一个方程中,所以看起来很多

假设现在你们有t1和t2,方程的值,你们现在可以这样做

float finalT = Mathf.Abs(t1) < Mathf.Abs(t2) ? t1 : t2;
transform.position += dir*t;
因此,如果Unity engine已经很好地定位了对象,则忽略计算。让我知道进展如何,希望这有帮助


注意:即使对象没有恒定的方向,您也可以采用最后知道的方向来近似它,并且为了计算的目的,使其在该值上保持恒定。你不会得到几乎没有差别的结果,它极大地解决了计算问题。

谢谢你的回答,但似乎添加了rb.angularVelocity=Vect3.zero没有多大帮助:-这并不是我所改变的全部,预取刚体参考将在微观层面加快速度。您还可以尝试不同的刚体碰撞模式离散/连续、增加/减少质量、使用位置约束。在刚体检查器中查找所有这些选项嗯,你的意思是将刚体作为保留引用吗?只要用你的代码替换我的代码,看起来都一样。总是将组件引用存储在变量中。GetComponent调用需要一些处理。当它发生碰撞时,首先要做的事情是设置为运动学Hanks,Neven,我会尝试理解这一点,并尝试让你们知道这可能需要一些时间。我已经尝试过的一件事是确保固定时间戳变小,以获得更精确的位置
if((transform.position-collidedObject.transform.position).sqrMagnitude > (radius1+radius2 + someThresholdValue)^2)