如何防止碰撞发生?

时间:2021-05-28 00:03:14

I am having trouble keeping game objects inside of a contained space. When they reach the edge, there is some momentary push back but then they will go right through the wall.

我在把游戏对象放在一个封闭的空间里有困难。当它们到达边缘时,会有短暂的向后推,然后它们会穿过墙壁。

I am using a Box Collider on the player, and a Mesh Collider for the level's wall. I am having issues with both a Player Character (a space ship) that the movement is controlled by the player. And with projectiles, which are fire and forget moving at a constant speed.

我在玩家身上使用了一个盒子对撞机,在关卡的墙壁上使用了一个网格对撞机。我对玩家角色(太空飞船)都有问题,这个动作是由玩家控制的。还有弹丸,它们是火,忘记了匀速运动。

This is my movement code for my player. It is being run in the FixedUpdate() function.

这是我球员的移动代码。它正在FixedUpdate()函数中运行。

//Movement
    haxis = Input.GetAxis("Horizontal") * speed;
    vaxis = Input.GetAxis("Vertical") * speed;

    moveVector.x = haxis;
    moveVector.z = vaxis;

    if(moveVector.magnitude > 1)
    {
        moveVector.Normalize();
    }

    rigidbody.MovePosition(transform.position + moveVector * speed);

With the bullets, they are given a velocity and the engine calculates their moviements. They are using Box Collider and it is set as a Trigger so they don't have physics. But I use OnTriggerEnter to destroy them.

对于子弹,给他们一个速度,引擎计算他们的移动速度。他们正在使用盒子对撞机,它被设置为一个触发器,所以他们没有物理。但是我用OnTriggerEnter去摧毁它们的。

//Projectiles without physics collisiions
function OnTriggerEnter (other : Collider) {
    Destroy(gameObject);
}

Some, but not all of the bullets will be destroyed when hitting the mesh collider wall. The player will sometimes hit it and stop, but can usually push through it. How can I make the collisions with the mesh collider work every time?

有些子弹,但不是所有的子弹都将被摧毁,当撞到网格碰撞墙。玩家有时会撞到它并停下来,但通常可以推过它。我怎么能每次都和网格对撞机对撞?

7 个解决方案

#1


9  

Collision with fast-moving objects is always a problem. A good way to ensure that you detect all collision is to use Raycasting instead of relying on the physics simulation. This works well for bullets or small objects, but will not produce good results for large objects. http://unity3d.com/support/documentation/ScriptReference/Physics.Raycast.html

与快速移动的物体碰撞总是一个问题。确保检测所有冲突的一个好方法是使用Raycasting,而不是依赖物理模拟。这适用于子弹或小物体,但不会对大物体产生好的结果。http://unity3d.com/support/documentation/ScriptReference/Physics.Raycast.html

Pseudo-codeish (I don't have code-completion here and a poor memory):

伪码(我这里没有代码补全,内存不足):

void FixedUpdate()
{
    Vector3 direction = new Vector3(transform.position - lastPosition);
    Ray ray = new Ray(lastPosition, direction);
    RaycastHit hit;
    if (Physics.Raycast(ray, hit, direction.magnitude))
    {
        // Do something if hit
    }

    this.lastPosition = transform.position;
}

#2


12  

I have a pinball prototype that also gave me much trouble in the same areas. These are all the steps I've taken to almost (but not yet entirely) solve these problems:

我有一个弹球的原型,在同样的领域给我带来了很多麻烦。这些都是我为解决这些问题所采取的步骤(但还没有完全解决):

For fast moving objects:

快速移动的物件除外:

  • Set the rigidbody's Interpolate to 'Interpolate' (this does not affect the actual physics simulation, but updates the rendering of the object properly - use this only on important objects from a rendering point of view, like the player, or a pinball, but not for projectiles)

    将刚体的内插设置为“内插”(这并不影响实际的物理模拟,而是适当地更新对象的呈现——只在从渲染的角度(如球员或弹珠)对重要的对象使用这个内插,而不用于投射)

  • Set Collision Detection to Continuous Dynamic

    将碰撞检测设置为连续动态。

  • Attach the script DontGoThroughThings (https://www.auto.tuwien.ac.at/wordpress/?p=260) to your object. This script cleverly uses the Raycasting solution I posted in my other answer to pull back offending objects to before the collision points.

    在你的对象上附加一个脚本,DontGoThroughThings (https://www.auto.tuwien.ac.at/wordpress/?p=260)。这个脚本巧妙地使用了我在另一个答案中发布的Raycasting解决方案,以便在冲突点之前将问题对象拉回。

In Edit -> Project Settings -> Physics:

在编辑->项目设置->物理学:

  • Set Min Penetration for Penalty to a very low value. I've set mine to 0.001

    将最小穿透值设置为非常低的值。我的是0。001

  • Set Solver Iteration Count to a higher value. I've set mine to 50, but you can probably do ok with much less.

    将求解器迭代计数设置为更高的值。我已经把我的数字设为50,但是你可以少做一些。

All that is going to have a penalty in performace, but that's unavoidable. The defaults values are soft on performance but are not really intented for proper simulation of small and fast-moving objects.

所有这一切都将在表现上受到惩罚,但这是不可避免的。默认值在性能上不太理想,但并不是为了适当地模拟快速移动的小对象。

#3


6  

How about set the Collision Detection of rigidbody to Continuous or Continuous Dynamic?

将刚体碰撞检测设为连续动态还是连续动态?

http://unity3d.com/support/documentation/Components/class-Rigidbody.html

http://unity3d.com/support/documentation/Components/class-Rigidbody.html

#4


1  

So I haven't been able to get the Mesh Colliders to work. I created a composite collider using simple box colliders and it worked exactly as expected.

所以我没能让网格对撞机工作。我使用简单的盒子对撞机创建了一个复合对撞机,它的工作完全符合预期。

Other tests with simple Mesh Colliders have come out the same.

使用简单的网格对撞机的其他测试结果也一样。

It looks like the best answer is to build a composite collider out of simple box/sphere colliders.

看起来最好的解决办法是用简单的盒/球对撞机建立一个复合对撞机。

For my specific case I wrote a Wizard that creates a Pipe shaped compound collider.

在我的具体案例中,我编写了一个创建管状复合对撞机的向导。

@script AddComponentMenu("Colliders/Pipe Collider");
class WizardCreatePipeCollider extends ScriptableWizard
{
    public var outterRadius : float = 200;
    public var innerRadius : float = 190;
    public var sections : int = 12;
    public var height : float = 20;

    @MenuItem("GameObject/Colliders/Create Pipe Collider")
    static function CreateWizard()
    {
        ScriptableWizard.DisplayWizard.<WizardCreatePipeCollider>("Create Pipe Collider");
    }

    public function OnWizardUpdate() {
        helpString = "Creates a Pipe Collider";
    }

    public function OnWizardCreate() {
        var theta : float = 360f / sections;
        var width : float = outterRadius - innerRadius;

        var sectionLength : float = 2 * outterRadius * Mathf.Sin((theta / 2) * Mathf.Deg2Rad);

        var container : GameObject = new GameObject("Pipe Collider");
        var section : GameObject;
        var sectionCollider : GameObject;
        var boxCollider : BoxCollider;

        for(var i = 0; i < sections; i++)
        {
            section = new GameObject("Section " + (i + 1));

            sectionCollider = new GameObject("SectionCollider " + (i + 1));
            section.transform.parent = container.transform;
            sectionCollider.transform.parent = section.transform;

            section.transform.localPosition = Vector3.zero;
            section.transform.localRotation.eulerAngles.y = i * theta;

            boxCollider = sectionCollider.AddComponent.<BoxCollider>();
            boxCollider.center = Vector3.zero;
            boxCollider.size = new Vector3(width, height, sectionLength);

            sectionCollider.transform.localPosition = new Vector3(innerRadius + (width / 2), 0, 0);
        }
    }
}

#5


1  

  • Edit ---> Project Settings ---> Time ... decrease "Fixed Timestep" value .. This will solve the problem but it can affect performance negatively.

    编辑--->项目设置-->时间…减少“固定时间步”值。这将解决问题,但会对性能产生负面影响。

  • Another solution is could be calculate the coordinates (for example, you have a ball and wall. Ball will hit to wall. So calculate coordinates of wall and set hitting process according these cordinates )

    另一个解决方案是计算坐标(例如,你有一个球和墙)。球会撞到墙上。所以计算墙的坐标并根据这些坐标来设置击球过程)

#6


0  

1.) Never use MESH COLLIDER. Use combination of box and capsule collider.

1)。从不使用网对撞机。使用盒和胶囊对撞机。

2.) Check constraints in RigidBody. If you tick Freeze Position X than it will pass through the object on the X axis. (Same for y axis).

2)。在RigidBody检查约束。如果你在冻结位置X,它会穿过X轴上的物体。y轴(相同)。

#7


0  

Old Question but maybe it helps someone.

这是个老问题,但可能对某些人有帮助。

Go to Project settings > Time and Try dividing the fixed timestep and maximum allowed timestep by two or by four.

转到项目设置>时间,尝试将固定时间步和最大允许时间步分割为2或4。

I had the problem that my player was able to squeeze through openings smaller than the players collider and that solved it. It also helps with stopping fast moving objects.

我有一个问题,我的球员能够挤过比球员对撞机还小的开口,这就解决了问题。它还有助于阻止快速移动的物体。

#1


9  

Collision with fast-moving objects is always a problem. A good way to ensure that you detect all collision is to use Raycasting instead of relying on the physics simulation. This works well for bullets or small objects, but will not produce good results for large objects. http://unity3d.com/support/documentation/ScriptReference/Physics.Raycast.html

与快速移动的物体碰撞总是一个问题。确保检测所有冲突的一个好方法是使用Raycasting,而不是依赖物理模拟。这适用于子弹或小物体,但不会对大物体产生好的结果。http://unity3d.com/support/documentation/ScriptReference/Physics.Raycast.html

Pseudo-codeish (I don't have code-completion here and a poor memory):

伪码(我这里没有代码补全,内存不足):

void FixedUpdate()
{
    Vector3 direction = new Vector3(transform.position - lastPosition);
    Ray ray = new Ray(lastPosition, direction);
    RaycastHit hit;
    if (Physics.Raycast(ray, hit, direction.magnitude))
    {
        // Do something if hit
    }

    this.lastPosition = transform.position;
}

#2


12  

I have a pinball prototype that also gave me much trouble in the same areas. These are all the steps I've taken to almost (but not yet entirely) solve these problems:

我有一个弹球的原型,在同样的领域给我带来了很多麻烦。这些都是我为解决这些问题所采取的步骤(但还没有完全解决):

For fast moving objects:

快速移动的物件除外:

  • Set the rigidbody's Interpolate to 'Interpolate' (this does not affect the actual physics simulation, but updates the rendering of the object properly - use this only on important objects from a rendering point of view, like the player, or a pinball, but not for projectiles)

    将刚体的内插设置为“内插”(这并不影响实际的物理模拟,而是适当地更新对象的呈现——只在从渲染的角度(如球员或弹珠)对重要的对象使用这个内插,而不用于投射)

  • Set Collision Detection to Continuous Dynamic

    将碰撞检测设置为连续动态。

  • Attach the script DontGoThroughThings (https://www.auto.tuwien.ac.at/wordpress/?p=260) to your object. This script cleverly uses the Raycasting solution I posted in my other answer to pull back offending objects to before the collision points.

    在你的对象上附加一个脚本,DontGoThroughThings (https://www.auto.tuwien.ac.at/wordpress/?p=260)。这个脚本巧妙地使用了我在另一个答案中发布的Raycasting解决方案,以便在冲突点之前将问题对象拉回。

In Edit -> Project Settings -> Physics:

在编辑->项目设置->物理学:

  • Set Min Penetration for Penalty to a very low value. I've set mine to 0.001

    将最小穿透值设置为非常低的值。我的是0。001

  • Set Solver Iteration Count to a higher value. I've set mine to 50, but you can probably do ok with much less.

    将求解器迭代计数设置为更高的值。我已经把我的数字设为50,但是你可以少做一些。

All that is going to have a penalty in performace, but that's unavoidable. The defaults values are soft on performance but are not really intented for proper simulation of small and fast-moving objects.

所有这一切都将在表现上受到惩罚,但这是不可避免的。默认值在性能上不太理想,但并不是为了适当地模拟快速移动的小对象。

#3


6  

How about set the Collision Detection of rigidbody to Continuous or Continuous Dynamic?

将刚体碰撞检测设为连续动态还是连续动态?

http://unity3d.com/support/documentation/Components/class-Rigidbody.html

http://unity3d.com/support/documentation/Components/class-Rigidbody.html

#4


1  

So I haven't been able to get the Mesh Colliders to work. I created a composite collider using simple box colliders and it worked exactly as expected.

所以我没能让网格对撞机工作。我使用简单的盒子对撞机创建了一个复合对撞机,它的工作完全符合预期。

Other tests with simple Mesh Colliders have come out the same.

使用简单的网格对撞机的其他测试结果也一样。

It looks like the best answer is to build a composite collider out of simple box/sphere colliders.

看起来最好的解决办法是用简单的盒/球对撞机建立一个复合对撞机。

For my specific case I wrote a Wizard that creates a Pipe shaped compound collider.

在我的具体案例中,我编写了一个创建管状复合对撞机的向导。

@script AddComponentMenu("Colliders/Pipe Collider");
class WizardCreatePipeCollider extends ScriptableWizard
{
    public var outterRadius : float = 200;
    public var innerRadius : float = 190;
    public var sections : int = 12;
    public var height : float = 20;

    @MenuItem("GameObject/Colliders/Create Pipe Collider")
    static function CreateWizard()
    {
        ScriptableWizard.DisplayWizard.<WizardCreatePipeCollider>("Create Pipe Collider");
    }

    public function OnWizardUpdate() {
        helpString = "Creates a Pipe Collider";
    }

    public function OnWizardCreate() {
        var theta : float = 360f / sections;
        var width : float = outterRadius - innerRadius;

        var sectionLength : float = 2 * outterRadius * Mathf.Sin((theta / 2) * Mathf.Deg2Rad);

        var container : GameObject = new GameObject("Pipe Collider");
        var section : GameObject;
        var sectionCollider : GameObject;
        var boxCollider : BoxCollider;

        for(var i = 0; i < sections; i++)
        {
            section = new GameObject("Section " + (i + 1));

            sectionCollider = new GameObject("SectionCollider " + (i + 1));
            section.transform.parent = container.transform;
            sectionCollider.transform.parent = section.transform;

            section.transform.localPosition = Vector3.zero;
            section.transform.localRotation.eulerAngles.y = i * theta;

            boxCollider = sectionCollider.AddComponent.<BoxCollider>();
            boxCollider.center = Vector3.zero;
            boxCollider.size = new Vector3(width, height, sectionLength);

            sectionCollider.transform.localPosition = new Vector3(innerRadius + (width / 2), 0, 0);
        }
    }
}

#5


1  

  • Edit ---> Project Settings ---> Time ... decrease "Fixed Timestep" value .. This will solve the problem but it can affect performance negatively.

    编辑--->项目设置-->时间…减少“固定时间步”值。这将解决问题,但会对性能产生负面影响。

  • Another solution is could be calculate the coordinates (for example, you have a ball and wall. Ball will hit to wall. So calculate coordinates of wall and set hitting process according these cordinates )

    另一个解决方案是计算坐标(例如,你有一个球和墙)。球会撞到墙上。所以计算墙的坐标并根据这些坐标来设置击球过程)

#6


0  

1.) Never use MESH COLLIDER. Use combination of box and capsule collider.

1)。从不使用网对撞机。使用盒和胶囊对撞机。

2.) Check constraints in RigidBody. If you tick Freeze Position X than it will pass through the object on the X axis. (Same for y axis).

2)。在RigidBody检查约束。如果你在冻结位置X,它会穿过X轴上的物体。y轴(相同)。

#7


0  

Old Question but maybe it helps someone.

这是个老问题,但可能对某些人有帮助。

Go to Project settings > Time and Try dividing the fixed timestep and maximum allowed timestep by two or by four.

转到项目设置>时间,尝试将固定时间步和最大允许时间步分割为2或4。

I had the problem that my player was able to squeeze through openings smaller than the players collider and that solved it. It also helps with stopping fast moving objects.

我有一个问题,我的球员能够挤过比球员对撞机还小的开口,这就解决了问题。它还有助于阻止快速移动的物体。