• 碰撞检测(上篇)


    游戏中的每个3D对象在世界坐标系里都有坐标。
    技能的作用范围可能是圆形,矩形,扇形,三角形等。
    那可不可以直接拿 “点”直接与这些形状进行碰撞检测呢!
    如果你要的效果不是那么精确,可以允许一点点瑕疵,那么是可行的。
    那么这个瑕疵是什么呢?
    因为3D物体都有体积,当你肉眼都能看到你的3D模型已经在范围里面,但是为什么技能作用不到它呢?
    因为实际取的是3D物体的中心点。当这个中心点真正进入技能范围内,技能才真正作用到他。
    如图:中心点还在范围外

    如果你不能允许,那这种方式就不适合了。我会在下篇整理更精确的方式。
    这里有本书:Real-Time Collision Dectection 中文版
    我上传到网盘了:
    链接:http://pan.baidu.com/s/1o63VtqE 密码:d5vt
    如果你能允许,那么请往下看。
    1.点在三角形内

    using UnityEngine;
    using System.Collections;
     
    /// <summary>
    /// 点在三角形里面
    /// </summary>
    public class PointInTriangle : MonoBehaviour
    {
        public Transform PointTrans;
        public float distance = 5f;
        public float angle = 30f;
     
        void Update()
        {
            Quaternion r = this.transform.rotation;
            Vector3 f0 = transform.position + (r * Vector3.forward) * distance;
            //Debug.DrawLine(transform.position, f0, Color.red);//正前方
     
            Quaternion r0 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y - angle, transform.rotation.eulerAngles.z);
            Vector3 f1 = transform.position + (r0 * Vector3.forward) * distance;
            Debug.DrawLine(transform.position, f1, Color.red);//左30度方向
     
            Quaternion r1 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y + angle, transform.rotation.eulerAngles.z);
            Vector3 f2 = transform.position + (r1 * Vector3.forward) * distance;//右30度方向
            Debug.DrawLine(transform.position, f2, Color.red);
     
            Debug.DrawLine(f1, f2, Color.red);//连接成一个三角形
     
            Vector3 point = PointTrans.position;
     
            //点是否在一个三角形内
            if (MyTool.isINTriangle(point, transform.position, f1, f2))
            {
                Debug.Log("in");
            }
            else
            {
                Debug.Log("not in");
            }
        }
    }

    2.点在扇形内

    using UnityEngine;
    using System.Collections;
     
    /// <summary>
    /// 点在扇形里面
    /// </summary>
    public class PointInSector : MonoBehaviour
    {
        public Transform pointTransform;
        public float distance = 5f;
        public float angle = 30f;
        void Update()
        {
            Quaternion r = this.transform.rotation;
            Vector3 f0 = transform.position + (r * Vector3.forward) * distance;
            Debug.DrawLine(transform.position, f0, Color.red);//正前方
     
            Quaternion r0 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y - angle, transform.rotation.eulerAngles.z);
            Vector3 f1 = transform.position + (r0 * Vector3.forward) * distance;
            Debug.DrawLine(transform.position, f1, Color.red);//左30度方向
     
            Quaternion r1 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y + angle, transform.rotation.eulerAngles.z);
            Vector3 f2 = transform.position + (r1 * Vector3.forward) * distance;//右30度方向
            Debug.DrawLine(transform.position, f2, Color.red);
     
            Debug.DrawLine(f1, f2, Color.red);//连接成一个三角形
     
            Vector3 point = pointTransform.position;
     
            Vector3 selfVec = (f0 - this.transform.position).normalized;
            Vector3 targetVec = (pointTransform.position - this.transform.position).normalized;
            Debug.DrawLine(pointTransform.position, this.transform.position, Color.yellow);
     
            //在左右30度以内
            if (Vector3.Dot(selfVec, targetVec) > Mathf.Cos(Mathf.PI / 6.0f))
            {
                //且在周围distance范围以内,等价于在这个扇形区域!
                if ((pointTransform.position - this.transform.position).sqrMagnitude < distance * distance)
                {
                    Debug.Log("in");
                }
                else
                {
                    Debug.Log("not in");
                }
            }
            else
            {
                Debug.Log("out of angle");
            }
        }
    }

    3.点在矩形内

    using UnityEngine;
    using System.Collections;
     
    /// <summary>
    /// 点在矩形里面
    /// </summary>
    public class PointInRectangle : MonoBehaviour
    {
        public Transform pointTransform;
        public float length = 5f;
        public float width = 5f;
     
        private float half_length;
        private float half_width;
     
        void Start()
        {
            this.half_length = this.length / 2.0f;
            this.half_width = this.width / 2.0f;
        }
     
        void Update()
        {
            Quaternion r = transform.rotation;
            Vector3 left = (transform.position + (r * Vector3.left) * this.half_length);
            Debug.DrawLine(transform.position, left, Color.red);
     
            Vector3 right = (transform.position + (r * Vector3.right) * this.half_length);
            Debug.DrawLine(transform.position, right, Color.red);
     
            Vector3 leftEnd = (left + (r * Vector3.forward) * this.width);
            Debug.DrawLine(left, leftEnd, Color.red);
     
            Vector3 rightEnd = (right + (r * Vector3.forward) * this.width);
            Debug.DrawLine(right, rightEnd, Color.red);
     
            Debug.DrawLine(leftEnd, rightEnd, Color.red);
     
            Vector3 point = pointTransform.position;
     
            //是否在矩形内
            if (MyTool.isINRect(point, leftEnd, rightEnd, right, left))
            {
                Debug.Log("in");
            }
            else
            {
                Debug.Log("not in");
            }
        }
    }

    工具类:

    using UnityEngine;
     
    public class MyTool
    {
        private static float triangleArea(float v0x, float v0y, float v1x, float v1y, float v2x, float v2y)
        {
            return Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
                - v1x * v0y - v2x * v1y - v0x * v2y) / 2f);
        }
        public static bool isINTriangle(Vector3 point, Vector3 v0, Vector3 v1, Vector3 v2)
        {
            float x = point.x;
            float y = point.z;
     
            float v0x = v0.x;
            float v0y = v0.z;
     
            float v1x = v1.x;
            float v1y = v1.z;
     
            float v2x = v2.x;
            float v2y = v2.z;
     
            float t = triangleArea(v0x, v0y, v1x, v1y, v2x, v2y);
            float a = triangleArea(v0x, v0y, v1x, v1y, x, y) + triangleArea(v0x, v0y, x, y, v2x, v2y) + triangleArea(x, y, v1x, v1y, v2x, v2y);
     
            if (Mathf.Abs(t - a) <= 0.01f)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
     
     
        private static float Multiply(float p1x, float p1y, float p2x, float p2y, float p0x, float p0y)
        {
            return ((p1x - p0x) * (p2y - p0y) - (p2x - p0x) * (p1y - p0y));
        }
     
        public static bool isINRect(Vector3 point, Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3)
        {
            float x = point.x;
            float y = point.z;
     
            float v0x = v0.x;
            float v0y = v0.z;
     
            float v1x = v1.x;
            float v1y = v1.z;
     
            float v2x = v2.x;
            float v2y = v2.z;
     
            float v3x = v3.x;
            float v3y = v3.z;
     
            if (Multiply(x, y, v0x, v0y, v1x, v1y) * Multiply(x, y, v3x, v3y, v2x, v2y) <= 0 && Multiply(x, y, v3x, v3y, v0x, v0y) * Multiply(x, y, v2x, v2y, v1x, v1y) <= 0)
                return true;
            else
                return false;
     
        }
    }
  • 相关阅读:
    [C++]Linux之进程间通信小结【待完善】
    [转] thrift的使用介绍
    [转] splice系列系统调用
    [转] gdb中忽略信号处理
    [转] 确定性投资的框架
    [转] 投资策略及投资体系
    [转] 为什么医疗咨询服务公司Evolent Health仅用4年就华丽上市?
    [转] When exactly does the virtual table pointer (in C++) gets set for an object?
    [转] Linux写时拷贝技术(copy-on-write)
    [转] .bss段和.data段的区别
  • 原文地址:https://www.cnblogs.com/joeshifu/p/5489525.html
Copyright © 2020-2023  润新知