碰撞检测(上篇)

游戏中的每个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;
 
    }
}
posted @ 2016-05-13 15:17  Joe师傅  阅读(760)  评论(0编辑  收藏  举报