算法实现2D OBB碰撞

box

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

public class DrawLine : MonoBehaviour {
    public Vector3[] p = new Vector3[4];

    public Vector3 up { get; set; }
    public Vector3 right { get; set; }

    private Cube _cube1;
    public Cube cube1 {
        get {
            if (_cube1 == null) {
                _cube1 = new Cube();
                _cube1.halfScale = 1;
            }
            return _cube1;
        }
    }

    public Matrix4x4 matrix;
    public Color color = Color.green;


    private void OnDrawGizmos() {
        Gizmos.color = color;
        Vector3 pos = transform.position;
        //设置与transform相同矩阵
        matrix = Matrix4x4.TRS(pos, transform.rotation, transform.lossyScale);

        up = new Vector3(matrix[0, 1], matrix[1, 1], matrix[2, 1]);
        right = new Vector3(matrix[0, 0], matrix[1, 0], matrix[2, 0]);
        
        p[0] = up - right + pos;
        p[1] = -up - right + pos;
        p[2] = -up + right + pos;
        p[3] = up + right + pos;

        Gizmos.DrawLine(p[0], p[1]);
        Gizmos.DrawLine(p[1], p[2]);
        Gizmos.DrawLine(p[2], p[3]);
        Gizmos.DrawLine(p[3], p[0]);
    }
}

public class Cube {
    public Vector3 center;
    public float halfScale;
    public Quaternion rotate;

    public Vector3 GetPoint1 => center + new Vector3(-halfScale, halfScale, 0);
    public Vector3 GetPoint2 => center + new Vector3(-halfScale, -halfScale, 0);
    public Vector3 GetPoint3 => center + new Vector3(halfScale, -halfScale, 0);
    public Vector3 GetPoint4 => center + new Vector3(halfScale, halfScale, 0);
}

 

检查是否碰撞

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

public class ColliderCheck : MonoBehaviour {
    public DrawLine cube1x;
    public DrawLine cube2x;
    public float lineLength;
    public bool check;
    
    // Start is called before the first frame update
    void Start()
    {
        
    }

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

    private void OnDrawGizmos() {
        //判断 cube1 与 cube2 是否相交
        //获取cube2 在 cube的up 和 right 轴上的投影

        check = CheckIsAxis(cube1x, cube2x) && CheckIsAxis(cube2x, cube1x);
        if (check) {
            cube1x.color = Color.red;
            cube2x.color = Color.red;
        } else {
            cube1x.color = Color.green;
            cube2x.color = Color.green;
        }

        if (Input.GetKeyDown(KeyCode.K)) {
            
        }
    }

    /// <summary>
    /// 从矩阵获取坐标
    /// </summary>
    /// <param name="matrix"></param>
    /// <returns></returns>
    public Vector3 GetPosition(Matrix4x4 matrix) {
        var x = matrix.m03;
        var y = matrix.m13;
        var z = matrix.m23;

        return new Vector3(x, y, z);
    }

    /// <summary>
    /// 从矩阵获取旋转
    /// </summary>
    /// <param name="matrix"></param>
    /// <returns></returns>
    public Quaternion GetRotation(Matrix4x4 matrix) {
        //m11 + m22 + m33 = 4w^2
        float qw = Mathf.Sqrt(1f + matrix.m00 + matrix.m11 + matrix.m22) / 2;
        float w = 4 * qw;
        float qx = (matrix.m21 - matrix.m12) / w;
        float qy = (matrix.m02 - matrix.m20) / w;
        float qz = (matrix.m10 - matrix.m01) / w;
        return new Quaternion(qx, qy, qz, qw);
    }

    /// <summary>
    /// 从矩阵获取缩放
    /// </summary>
    /// <param name="m"></param>
    /// <returns></returns>
    public static Vector3 GetScale(Matrix4x4 m) {
        var x = Mathf.Sqrt(m.m00 * m.m00 + m.m01 * m.m01 + m.m02 * m.m02);
        var y = Mathf.Sqrt(m.m10 * m.m10 + m.m11 * m.m11 + m.m12 * m.m12);
        var z = Mathf.Sqrt(m.m20 * m.m20 + m.m21 * m.m21 + m.m22 * m.m22);

        return new Vector3(x, y, z);
    }
    
    private bool CheckIsAxis(DrawLine cube1, DrawLine cube2) {
        //可得y轴上的最小值与最大值
        NewMethod(cube1, cube2, cube1.up, out var maxValue, out var minValue);
        //Debug.Log(minValue + "    " +maxValue);
        //判断y轴是否重合
        bool isOverLayY = false;
        if (maxValue <= cube1.cube1.halfScale && maxValue >= -cube1.cube1.halfScale) {
            isOverLayY = true;
        }

        if (minValue <= cube1.cube1.halfScale && minValue >= -cube1.cube1.halfScale) {
            isOverLayY = true;
        }

        //判断x轴
        NewMethod(cube1, cube2, cube1.right, out var maxValue2, out var minValue2);
        bool isOverLayX = false;
        if (maxValue2 <= cube1.cube1.halfScale && maxValue2 >= -cube1.cube1.halfScale) {
            isOverLayX = true;
        }

        if (minValue2 <= cube1.cube1.halfScale && minValue2 >= -cube1.cube1.halfScale) {
            isOverLayX = true;
        }


        if (isOverLayX && isOverLayY) {
            return true;
        }
        return false;
    }

    private void NewMethod(DrawLine cube1, DrawLine cube2, Vector3 onNormal ,out float maxValue, out float minValue) {
        float[] yArray = new float[4];
        maxValue = 0;
        minValue = 0;
        for (int i = 0; i < 4; i++) {
            Vector3 cube1Pos = cube1.transform.position;
            var line = Vector3.Project(cube2.p[i] - cube1Pos, onNormal);
            float yValue = line.magnitude;
            yArray[i] = yValue;
            //Debug.Log(yValue);
            if (i == 0) {
                maxValue = yValue;
                minValue = yValue;
            } else {
                if (yValue > maxValue) {
                    maxValue = yValue;
                }

                if (yValue < minValue) {
                    minValue = yValue;
                }
            }
        }
    }
}

 

 

 

 

2D凸多边形碰撞检测算法GJK + EPA

https://zhuanlan.zhihu.com/p/178841676

 

posted @ 2022-09-23 15:42  三页菌  阅读(124)  评论(0编辑  收藏  举报