Raycast2D 仅命中 Collider 的一侧

Raycast2D hits only one side of Collider

我想确保高速移动的各种物体不能穿过墙壁或其他物体。我的想法是通过 Raycast 检查两个运动时刻之间是否发生了碰撞。

因此脚本应该记住之前的位置并通过 Raycast 检查之前和当前位置之间的碰撞。

如果发生碰撞,物体应定位在交汇点,并向先前位置的方向稍微移动。

我的问题是在地图外不在地图内。如果我从里到外,我可以穿墙。从外到内不是。

显然我误解了一些关于光线投射的应用程序。

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

public class ObsticalControll : MonoBehaviour
{

    private Vector3 positionBefore;
    public LayerMask collisionLayer = 9;
    private Vector3 lastHit = new Vector3(0, 0, -20);
    // Start is called before the first frame update
    void Start()
    {
        positionBefore = transform.position;


    }

    private void OnDrawGizmos()
    {
        Gizmos.DrawCube(lastHit, new Vector3(.2f,.2f,.2f));
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 curruentMovement = transform.position;
        Vector2 dVector = (Vector2)transform.position - (Vector2)positionBefore;
        float distance = Vector2.Distance((Vector2)positionBefore, (Vector2)curruentMovement);
        RaycastHit2D[] hits = Physics2D.RaycastAll((Vector2)positionBefore, dVector, distance, collisionLayer);

        if(hits.Length > 0)
        {
            Debug.Log(hits.Length);
            for (int i = hits.Length -1 ; i >= 0 ; i--)
            {
                RaycastHit2D hit = hits[i];
                if (hit.collider != null)
                {
                    Debug.Log("hit");
                    lastHit.x = hit.point.x;
                    lastHit.y = hit.point.y;      
                    Vector3 resetPos = new Vector3(hit.point.x, hit.point.y, transform.position.z) + positionBefore.normalized * 0.1f;
                    transform.position = new Vector3(resetPos.x, resetPos.y, transform.position.z);
                }
            }
                
           
        }



        positionBefore = transform.position;
    }
}

Unity 内置了一种更好的方法来解决这个问题。 假设高速移动的物体有一个 RigidBody(在你的例子中是 2d),你可以将它的 Collision Detection 设置为 Continuous 而不是 Discrete。

假设它高速移动而墙壁不动,这将有助于高速碰撞。

如果由于某种原因您无法将此应用到您的场景中,我会尝试帮助解决光线投射问题。

However, I am still wondering about the collision behavior of my raycast script. That would be surely interesting, if you want to calculate shots or similar via raycast

好的,所以您最初的想法是通过检查其当前位置和之前的位置来检查是否发生了碰撞。并检查它们之间是否有任何东西,这意味着发生了碰撞。然后你会把它传送回它应该击中的地方。

一个更好的方法是检查 GameObject 在下一帧中的位置,通过在它前面进行光线投射,根据它将移动的距离。如果它确实撞到了某物,这意味着在下一帧内,它就会与之发生碰撞。所以你可以在碰撞碰撞点停止它,并得到它碰撞的东西。 (这意味着你不必将它传送回去,所以不会有它经过然后返回的帧)

几乎相同的想法,但稍微不那么复杂。

问题在于,如果在下一帧中另一个对象也出现在它们之间,则无法解释这一点。这就是 rigidbody.movePosition 的亮点,使用 OnCollisionEnter 您可以检测到它何时以及与什么正确碰撞。以及无需将其传送回去