简体   繁体   English

CircleCast经过对撞机

[英]CircleCast goes through a collider

I'm working on a custom physics behaviour and use CircleCast to determine whether there is ground/wall or not. 我正在研究自定义物理行为,并使用CircleCast来确定是否有地面/墙壁。 But in some cases CircleCast goes through a collider without hitting it. 但是在某些情况下,CircleCast会通过撞机而不会撞上撞机。 It seems that the issue appears when start circle a little bit overlaps a collider. 似乎当起始圆圈稍微与对撞机重叠时出现此问题。

How do I fix it, or what do I do wrong? 我该如何解决,或者我做错了什么?

using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public Rigidbody2D ball;
    public CircleCollider2D circleCollider;
    public float speed;
    public LayerMask layerMask;
    public bool grounded;
    public Transform graphics;
    public Transform startCast, endCast;
    public GameObject tempBall;

    private int maxPathSize = 5;
    private Queue<GameObject> path;
    private float realRadius;
    private Vector2 roughDirection;
    private float rayLength;
    private Vector2 realDirection;
    private Vector2 gravity;
    private Vector2 preferedDirectionOfMove;

    // Use this for initialization
    void Start()
    {
        path = new Queue<GameObject>();
        realRadius = circleCollider.radius * ball.transform.localScale.x;
        rayLength = realRadius + (realRadius / 10);
        gravity = new Vector2(0, -9.81f);
    }

    // Update is called once per frame
    void Update()
    {
        // if (Time.frameCount % 10 == 0)
        {
            preferedDirectionOfMove = gravity;
            if (Input.GetKey(KeyCode.RightArrow) && grounded)
            {
                preferedDirectionOfMove = ball.transform.right;
            }
            if (Input.GetKey(KeyCode.LeftArrow) && grounded)
            {
                preferedDirectionOfMove = -ball.transform.right;
            }

            Move();

        }
    }

    void Move()
    {
        if (grounded && preferedDirectionOfMove == gravity)
            return;
        Debug.Log("***********");
        AddToPath(ball.position);
        realDirection = (preferedDirectionOfMove * speed * Time.deltaTime);
        Color color = Color.black;
        Vector2 oldPos = ball.position;
        Color colorX = RandomColor();
        DrawX(ball.position, colorX, 0.2f, 1, 0.5f);
        RaycastHit2D hit = Physics2D.CircleCast(ball.position, realRadius, realDirection.normalized, realDirection.magnitude, layerMask);
        if (hit)
        {
            DrawX(hit.point, colorX, 0.2f, 0.5f, 1.5f);
            SetAngle(hit);
            ball.position = GetNewPosition(hit);
            grounded = true;
            Debug.Log("grounded: " + true);
        }
        else
        {
            ball.position += realDirection;
            DrawX(ball.position, colorX, 0.2f, 0.5f, 1.5f);
            Debug.Log("grounded: " + false);
            color = Color.red;
            grounded = false;
        }
        Debug.DrawLine(oldPos, ball.position, color, 1);
    }

    void AddToPath(Vector2 position)
    {
        GameObject go = Instantiate(tempBall, position, Quaternion.identity) as GameObject;
        if (path.Count >= 5)
        {
            Destroy(path.Dequeue());
        }
        path.Enqueue(go);
    }

    void DrawX(Vector2 position, Color color, float size, float duration, float shape)
    {
        Debug.DrawLine(position - Vector2.one * (size / 2f), position + Vector2.one * (size / 2f), color, duration);
        Debug.DrawLine(position + new Vector2(-1 * shape, 1) * (size / 2f), position + new Vector2(1, -1 * shape) * (size / 2f), color, duration);
    }

    Color RandomColor()
    {
        return new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f), 1);
    }

    Vector2 GetNewPosition(RaycastHit2D hit)
    {
        return hit.point + ((Vector2)hit.normal * realRadius);
    }

    void SetAngle(RaycastHit2D hit)
    {
        float angle2 = AngleAtan2(hit.normal, Vector2.right);
        ball.MoveRotation(angle2);
    }

    float AngleAtan2(Vector2 from, Vector2 to)
    {
        return Mathf.Rad2Deg * (Mathf.Atan2(to.y, to.x) - Mathf.Atan2(from.x, from.y));
    }

    void OnCollisionEnter2D(Collision2D collision)
    {
        Debug.Log("collision enter");
    }
}

Not registering hits when the casted object overlaps a collider at the start position is the default behavior. 默认的行为是,当投射对象在起始位置与碰撞器重叠时不记录命中。 To fix this, check the Queries Start In Colliders box in the Physics 2D Manager in Project Settings . 要解决此问题,请在“ 项目设置”中的Physics 2D Manager中选中“ 在碰撞器查询开始”框。

If you don't want this behavior for all queries, you may want to look at ray casting instead since raycasts have a much lower chance of starting in a collider. 如果您不希望所有查询都具有这种行为,则可能需要查看光线投射,因为光线投射在对撞机中启动的机会要低得多。 If you do decide to go with a ray cast, untick the above box and start the ray cast inside your player/ball's collider itself. 如果确实决定使用射线投射,请取消选中上面的框,然后在玩家/球的对撞机本身内部开始射线投射。 That way you can be sure that you'll never miss any hits because of the ray starting inside the offending collider. 这样一来,您就可以确定不会因碰撞的对撞机内部发出的光线而错过任何命中事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM