首页 > 解决方案 > 我们如何在不使用 unity 的内置物理库的情况下检查 gameObject 和 linerenderer 是否发生碰撞?

问题描述

我们有一种方法可以检测炮弹是否与线条渲染的火鸡物体发生碰撞。基本上,我们有方法在渲染的线条中获取火鸡的所有线条。然后我们检查炮弹中心到线的距离是否小于炮弹的半径。

在此处输入图像描述 这是代码:

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

    public class canonTrajectory : MonoBehaviour
    {
        GameObject[] turkeyList = new GameObject[5];
        GameObject turkeys;

        public static float rotationAngle;
        float createdTime;
        float speed = 150f;
        float gravity = -200.0f;
        public GameObject turkey;
        static int NUM_PARTICLES = 26;
        Vector3[] m_position = new Vector3[NUM_PARTICLES];
        LineRenderer lineRenderer;


        void Start()
        {
            turkeys = GameObject.Find("Turkeys");
            for (int i = 0; i<5; i++)
            {
                turkeyList[i] = turkeys.transform.GetChild(i).gameObject;
            }
        }


        // Update is called once per frame
        void FixedUpdate()
        {
            float directionx = Mathf.Cos(-rotationAngle*2.0f*Mathf.PI/360.0f);
            float directiony = Mathf.Sin(-rotationAngle * 2.0f * Mathf.PI / 360.0f);
            Debug.Log(-rotationAngle * 2.0f * Mathf.PI / 360.0f);
            float directionVectorLength = Mathf.Pow(Mathf.Pow(directionx, 2) + Mathf.Pow(directiony, 2), (0.5f));
            transform.Translate(-5 * directionx, 5 * directiony , 0.0f);

            if (transform.position.x < -300)
                Destroy(gameObject);

            if (transform.position.y < -77)
                Destroy(gameObject);
            CheckForTouchingTurkey();

        }
        public bool CheckForTouchingTurkey()
        {
            for (int i = 0; i < turkeyList.Length; i++)
            {
                Vector2 [] temporaryTurkeyLines = turkeyList[i].gameObject.GetComponent<MoveTurkey>().GetSlopeAndIntercept();
                for (int j = 0; j < temporaryTurkeyLines.Length;j++)
                {
                    float distance = Mathf.Abs(transform.position.x * temporaryTurkeyLines[i].x -transform.position.y + temporaryTurkeyLines[i].y) / Mathf.Sqrt(1 + Mathf.Pow(temporaryTurkeyLines[i].x, 2.0f));
                    Debug.Log("distance between ball and turkey is:" + distance);
                    if (distance < 2.5f)
                    {
                        turkeyList[i].gameObject.GetComponent<MoveTurkey>().UpdateMPosition(-20f);
                        Destroy(gameObject);
                    }

                }
            }
            return false;
        }
    }

土耳其运动脚本:

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

    public class MoveTurkey : MonoBehaviour
    {
        LineRenderer lineRenderer;    
        static int NUM_PARTICLES = 26;
        float fTimeStep;
        Vector3[] m_position = new Vector3[NUM_PARTICLES];
        Vector3[] m_acceleration = new Vector3[NUM_PARTICLES];
        Vector3[] m_oldPosition = new Vector3[NUM_PARTICLES];
        Vector2[] slopeAndIntercept = new Vector2[NUM_PARTICLES - 1];
        public Transform fireball;
        float gravity = -9.8f;


        // Start is called before the first frame update
        public void UpdateMPosition(float x)
        {
            for (int i = 0; i < m_position.Length; i++)
                m_position[i].x +=x;
        }

        public Vector2[] GetSlopeAndIntercept()
        {
            return slopeAndIntercept;
        }

        void Start()
        {
            fTimeStep = 0.5f;

            lineRenderer = gameObject.GetComponent<LineRenderer>();

            lineRenderer.GetPositions(m_position);

            for (int i = 0; i < m_acceleration.Length; i++)
            {
                m_acceleration[i] = new Vector3(0.0f, gravity, 0.0f);
            }
        }

        // Verlet integration step void ParticleSystem::
        void Verlet()
        {
            for (int i = 0; i < NUM_PARTICLES; i++)
            {
                m_position[i] = 2 * m_position[i] - m_oldPosition[i] + m_acceleration[i] * fTimeStep * fTimeStep;
                m_oldPosition[i] = m_position[i];
            }
        }


        public void FindLinesOfTurkey()
        {
            for (int i = 0; i < slopeAndIntercept.Length; i++)
            {
                float slope = (m_position[i + 1].y - m_position[i].y) / (m_position[i + 1].x - m_position[i].x);
                float intercept = m_position[i].y - slope * m_position[i].x;
                slopeAndIntercept[i].x = slope;
                slopeAndIntercept[i].y = intercept;
            }
        }



        // Update is called once per frame
        void Update()
        {

            //Codes for when the Turkey do the random jump
            int rn_generator = Random.Range(0, 2000);
            if (rn_generator < 5 && m_position[17].y<=-255f)
            {
                for (int i = 0; i < m_acceleration.Length; i++)
                    m_acceleration[i].y = 6.0f; //m_acceleration[i].y;
            }

            if(m_position[13].y> 90.0f && m_acceleration[13].y>0.0f)
                for (int i = 0; i < m_acceleration.Length; i++)
                    m_acceleration[i].y = -9.8f; //m_acceleration[i].y;


            //call verlet
            Verlet();
            FindLinesOfTurkey();



            //check proper orientation of the Turkey( turned left or right)
            if (m_position[4].x < m_position[13].x && m_acceleration[25].x >= 0)
            {
                Vector3 sumOfPoints = new Vector3();
                Vector3 sumOfPointsOld = new Vector3();
                int numberOfPointsAdded = 0;
                Vector3 centerOfTurkey = new Vector3();
                Vector3 centerOfTurkeyOld = new Vector3();

                for (int i = 8; i < m_position.Length; i++)
                {
                    sumOfPoints.x += m_position[i].x;
                    sumOfPointsOld.x += m_oldPosition[i].x;
                    numberOfPointsAdded++;
                }

                centerOfTurkey.x = sumOfPoints.x / numberOfPointsAdded;
                centerOfTurkeyOld.x = sumOfPointsOld.x / numberOfPointsAdded;
                for (int i = 0; i < m_position.Length; i++)
                {
                    m_position[i].x = (centerOfTurkey.x + centerOfTurkey.x - m_position[i].x);
                    m_oldPosition[i].x = (centerOfTurkeyOld.x + centerOfTurkeyOld.x - m_oldPosition[i].x);
                }
            }
            else if (m_position[4].x > m_position[13].x && m_acceleration[25].x < 0)
            {
                Vector3 sumOfPoints = new Vector3();
                Vector3 sumOfPointsOld = new Vector3();
                int numberOfPointsAdded = 0;
                Vector3 centerOfTurkey = new Vector3();
                Vector3 centerOfTurkeyOld = new Vector3();

                for (int i = 8; i < m_position.Length; i++)
                {
                    sumOfPoints.x += m_position[i].x;
                    sumOfPointsOld.x += m_oldPosition[i].x;
                    numberOfPointsAdded++;
                }
                centerOfTurkey.x = sumOfPoints.x / numberOfPointsAdded;
                centerOfTurkeyOld.x = sumOfPointsOld.x / numberOfPointsAdded;

                for (int i = 0; i < m_position.Length; i++)
                {
                    m_position[i].x = (centerOfTurkey.x + centerOfTurkey.x - m_position[i].x);
                    m_oldPosition[i].x = (centerOfTurkeyOld.x + centerOfTurkeyOld.x - m_oldPosition[i].x);
                }
            }
            else
               Debug.Log("Nothing");


            //if the turkey is on the ground , remove gravity
            if (m_position[17].y <= -255 && m_position[22].y <= -255)
            {
                float rdGenerator = Random.Range(0.0f, 1.0f);
                if (rdGenerator > 0.5f)
                {
                    for (int i = 0; i < m_acceleration.Length; i++)
                    {
                        if (m_acceleration[25].x == 0)
                            m_acceleration[i].x = 3.0f;
                        m_acceleration[i].y = 0.0f; 

                    }
                }
                else
                {
                    for (int i = 0; i < m_acceleration.Length; i++)
                    {
                        if (m_acceleration[25].x == 0)
                            m_acceleration[i].x = -3.0f;
                        m_acceleration[i].y = 0.0f; 
                    }
                }
            }

            // change direction of turkey when they hit the wall or the mountain
            if (m_position[13].x >= 280)
            {        
                for (int i = 0; i < m_acceleration.Length; i++)
                    m_acceleration[i].x = -2.0f;   
            }

            if (m_position[4].x <= -90)
            {
                for (int i = 0; i < m_acceleration.Length; i++)
                    m_acceleration[i].x = 2.0f;
            }

            //draw the turkey
            lineRenderer.SetPositions(m_position);
        }

    }

但是代码不起作用。炮弹穿过火鸡,就好像它们不在那里一样。

标签: unity3d

解决方案


您可以检查与每只火鸡中心的距离,将火鸡 + 炮弹的半径考虑在内。

Vector2 ballPos = cannonball.transform.position;
float turkeyRadius = 0.5f; // we'll assume it has a circle as a hitbox/collider
float cannonBallRadius = 0.1f; // same for the cannonball

// We want the added radius squared, because we wanna compare with sqrMagnitude later.
float minDifToCollide = Mathf.Pow(cannonBallRadius + turkeyRadius, 2);

foreach (var turkey in allTurkeys) {
    Vector2 turkeyPos = turkey.GetCenter();

    // .sqrMagnitude is more performant than .magnitude, so we use that.
    float dif = (turkeyPos - ballPos).sqrMagnitude;
    // Check for collision. 
    if (dif <= minDifToCollide) { CollideWith(turkey); }
}

您可以将这段代码添加到您的火鸡中,以便可视化它们的半径:

public float Radius;

void OnDrawGizmos() {
    Gizmos.color = Color.teal;
    Gizmos.DrawWireSphere(transform.position, Radius);
}


推荐阅读