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

B站课程

一、背景

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

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

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

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

  • 结果大于0【点在直线的逆时针方向】
  • 结果等于0【点在直线上】
  • 结果小于0【点在直线的顺时针方向】
2.3、计算公式
public static class Vector2Extend
{
    /// <summary>
    /// 该扩展方法为静态类型 扩展二维向量的叉乘
    /// </summary>
    /// <param name="vectorA">第一个参数使用this + 扩展类型 + 该类型对象 </param>
    /// <param name="vectorB"></param>
    /// <returns>返回叉乘结果</returns>
    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】

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值