【第012问 Unity如何判断某两个点在某条直线的哪侧?】

B站课程

一、背景

在进行游戏开发的时候,有时候会用到判断一个点是否在三角形内,那么其中的一种判定前提就是需判定该点和和三角形的几条向量之间的位置关系;这里的点的关系就是本节内容需要总结的一个知识点。

二、二维中如何判定某点和直线的关系

2.1、某点和直线的关系有三种情况:
  • 点在直线的顺时针方向
  • 点在直线的逆时针方向
  • 点在直线上
2.2、如何计算位置关系

二维中的点我们可以考虑叉乘的做法来计算,计算结果有以下三种情况:

  • 结果大于0【点在直线的逆时针方向】
  • 结果等于0【点在直线上】
  • 结果小于0【点在直线的顺时针方向】
2.3、计算公式
public static class Vector2Extend
{
    /// 
    /// 该扩展方法为静态类型 扩展二维向量的叉乘
    /// 
    /// 第一个参数使用this + 扩展类型 + 该类型对象 
    /// 
    /// 返回叉乘结果
    public static float Cross(this Vector2 vectorA, Vector2 vectorB)
    {
        return vectorA.x * vectorB.y - vectorB.x * vectorA.y;
    }
}

三、动画演示


从上面的效果演示中可以看出点B、点C和OA的关系上在不断变化的,通过这种方式可以直观的看出结果;

四、源码

using UnityEditor;
using UnityEngine;

[ExecuteInEditMode]
public class Vector2Test : MonoBehaviour
{
    [SerializeField] private Transform transformA;
    [SerializeField] private Transform transformB;
    [SerializeField] private Transform transformC;

    private Vector3 positionO = Vector3.zero;
    private Vector3 positionA = Vector3.zero;
    private Vector3 positionB = Vector3.zero;
    private Vector3 positionC = Vector3.zero;

    Vector2 labelSize = new Vector2(40, 40);


    Vector2 posA = Vector2.zero;
    Vector2 posB = Vector2.zero;
    Vector2 posC = Vector2.zero;

    private void OnDrawGizmos()
    {
        posA.x = positionA.x = transformA.position.x;
        posA.y = positionA.z = transformA.position.z;

        posB.x = positionB.x = transformB.position.x;
        posB.y = positionB.z = transformB.position.z;


        posC.x = positionC.x = transformC.position.x;
        posC.y = positionC.z = transformC.position.z;

        //设置为边界线
        Debug.DrawLine(positionO, positionA, Color.green);
        Debug.DrawLine(positionO, positionB, Color.yellow);
        Debug.DrawLine(positionO, positionC, Color.red);

        DrawLabel(positionO, "O", Color.magenta, labelSize);
        DrawLabel(positionA, "A", Color.green, labelSize);
        DrawLabel(positionB, "B", Color.yellow, labelSize);
        DrawLabel(positionC, "C", Color.red, labelSize);


        //计算OA cross  OB 
        float resultA = posA.Cross(posB); //  positionA.x * positionB.z - positionB.x * positionA.z;
        string axb = "OAxOB=" + resultA;
        DrawLabel(new Vector3(-30, 0, 22), axb, Color.cyan, new Vector2(300, 40));

        float resultB = posA.Cross(posC); // positionA.x * positionC.z - positionC.x * positionA.z;
        string axc = "OAxOC=" + resultB;
        DrawLabel(new Vector3(20, 0, 22), axc, Color.cyan, new Vector2(300, 40));

        string descA = "B和A在同一条直线上";
        if (resultA > 0 || resultA < 0)
        {
            descA = resultA > 0 ? "B点在A点的逆时针方向" : "B点在A点的顺时针方向";
        }

        string descB = "C和A在同一条直线上";
        if (resultB > 0 || resultB < 0)
        {
            descB = resultB > 0 ? "C点在A点的逆时针方向" : "C点在A点的顺时针方向";
        }


        float result = resultA * resultB;
        string desc = "ABC三点共线";
        if (result > 0 || result < 0)
        {
            desc = result > 0 ? "BC在同一侧" : "BC点不在同一侧";
        }

        DrawLabel(new Vector3(-35, 0, 15), descA, Color.magenta, new Vector2(400, 40));
        DrawLabel(new Vector3(25, 0, 15), descB, Color.magenta, new Vector2(400, 40));
        DrawLabel(new Vector3(-5, 0, -15), desc, Color.yellow, new Vector2(400, 40));
    }


    void DrawLabel(Vector3 pos, string text, Color color, Vector2 size)
    {
        Vector2 pos2D = HandleUtility.WorldToGUIPoint(pos);
        Handles.BeginGUI();
        GUI.skin.label.fontSize = 35;

        GUI.skin.label.normal.textColor = color;
        GUI.Label(new Rect(pos2D.x - 15, pos2D.y - 15, size.x, size.y), text);
        HandleUtility.Repaint();
        Handles.EndGUI();
    }
}

结语:
别把工作带入生活【valaki】

你可能感兴趣的:(【Unity之十万个为什么】,unity,mesh,游戏引擎)