当前位置: 首页 > news >正文

Unity--判断一个点是否在扇形区域里面(点乘和叉乘的应用)

问题分享:https://www.bilibili.com/video/BV1zLetz1Ew8

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endifpublic class SectorCheck : MonoBehaviour
{[Tooltip("扇形圆心")] public Transform center;[Tooltip("目标点")] public Transform point;[Tooltip("扇形朝向")] public Vector2 direction = Vector2.right;[Tooltip("扇形半径")] public float radius = 5f;[Tooltip("扇形角度")] [Range(0f,360f)] public float angle = 60f;[Header("Gizmo")][Tooltip("扇形段数")] [Range(4,256)] public int segments = 40;public Color outlineColor = new Color(1f, 0f, 0f, 1f);public Color insidePointColor = Color.green;public Color outsidePointColor = Color.red;void FixedUpdate(){if (center == null || point == null) return;bool inside = PointInSector_Dot(point.position, center.position, direction, angle, radius);Debug.Log(inside ? "点在扇形内" : "点不在扇形内");}/// <summary>/// 点乘方法/// </summary>/// <param name="targetPoint">目标点</param>/// <param name="sectorCenter">扇形中心</param>/// <param name="sectorDir">扇形朝向</param>/// <param name="angleDeg">扇形弧度</param>/// <param name="radius">扇形半径</param>/// <returns>是否在指定扇形里</returns>public static bool PointInSector_Dot(Vector2 targetPoint, Vector2 sectorCenter, Vector2 sectorDir, float angleDeg, float radius){Vector2 dir = targetPoint - sectorCenter;float dist = dir.magnitude;if (dist > radius) return false;if (dist == 0f) return true;Vector2 dirNorm = dir.normalized;Vector2 sectorNorm = sectorDir.normalized;float dot = Vector2.Dot(sectorNorm, dirNorm);float cosHalf = Mathf.Cos((angleDeg * 0.5f) * Mathf.Deg2Rad);// 若 dot >= cosHalf,则夹角 <= halfAngle,即在扇形内return dot >= cosHalf;}/// <summary>/// 将一个向量旋转指定度数/// </summary>/// <param name="v">指定向量</param>/// <param name="degrees">旋转度数</param>/// <returns>旋转后的新向量</returns>private static Vector2 Rotate(Vector2 v, float degrees) {// 将角度转换为弧度,因为 Mathf.Sin 和 Mathf.Cos 函数使用弧度制float rad = degrees * Mathf.Deg2Rad;float c = Mathf.Cos(rad);float s = Mathf.Sin(rad);return new Vector2(v.x * c - v.y * s, v.x * s + v.y * c);}// 2D 叉乘(返回 z 分量)private static float Cross(Vector2 a, Vector2 b){return a.x * b.y - a.y * b.x;}/// <summary>/// 叉乘方法/// </summary>/// <param name="targetPoint">目标点</param>/// <param name="sectorCenter">扇形中心</param>/// <param name="sectorDir">扇形朝向</param>/// <param name="angleDeg">扇形弧度</param>/// <param name="radius">扇形半径</param>/// <returns>是否在指定扇形里</returns>public static bool PointInSector_Cross(Vector2 targetPoint, Vector2 sectorCenter, Vector2 sectorDir, float angleDeg, float radius) {Vector2 dir = targetPoint - sectorCenter;float dist = dir.magnitude;if (dist > radius) return false;if (dist == 0f) return true;float half = angleDeg * 0.5f;Vector2 fwd = sectorDir.normalized;Vector2 left = Rotate(fwd, half);//左边界向量Vector2 right = Rotate(fwd, -half);//右边界向量float crossLeft = Cross(left, dir);float crossRight = Cross(right, dir);// crossLeft <= 0 && crossRight >= 0 表示 dir 在 right 与 left 之间return crossLeft <= 0f && crossRight >= 0f;}// 在 Scene 视图绘制扇形private void OnDrawGizmos(){if (center == null) return;// 计算基础数据Vector3 centerPos = center.position;Vector3 fromDir3 = new Vector3(direction.x, direction.y, 0f);if (fromDir3.sqrMagnitude <= 0.0001f) fromDir3 = Vector3.up;fromDir3 = fromDir3.normalized;// 画扇形边框与辐条Gizmos.color = outlineColor;DrawWireSector(centerPos, fromDir3, angle, radius, segments);// 若有指定点,画出点并根据是否在扇形内标色if (point != null){bool inside = PointInSector_Dot(point.position, centerPos, direction, angle, radius);Gizmos.color = inside ? insidePointColor : outsidePointColor;Gizmos.DrawSphere(point.position, Mathf.Max(0.05f, radius * 0.02f));}}//用线段绘制扇形边界并画从中心到弧上点的辐条private void DrawWireSector(Vector3 centerPos, Vector3 fromDir3, float angleDeg, float radius, int segs){if (segs < 3) segs = 3;float half = angleDeg * 0.5f;Vector3 prev = centerPos + Quaternion.Euler(0f, 0f, -half) * fromDir3 * radius;// 绘制弧for (int i = 1; i <= segs; i++){float t = (float)i / segs;float ang = -half + t * angleDeg;Vector3 cur = centerPos + Quaternion.Euler(0f, 0f, ang) * fromDir3 * radius;Gizmos.DrawLine(prev, cur);prev = cur;}// 两条边到中心Vector3 left = centerPos + Quaternion.Euler(0f, 0f, -half) * fromDir3 * radius;Vector3 right = centerPos + Quaternion.Euler(0f, 0f, half) * fromDir3 * radius;Gizmos.DrawLine(centerPos, left);Gizmos.DrawLine(centerPos, right);//绘制若干辐条int spokes = Mathf.Clamp(segs / 6, 0, segs);if (spokes > 0){for (int i = 0; i <= spokes; i++){float t = (float)i / spokes;float ang = -half + t * angleDeg;Vector3 p = centerPos + Quaternion.Euler(0f, 0f, ang) * fromDir3 * radius;Gizmos.DrawLine(centerPos, p);}}}
}

http://www.xdnf.cn/news/1345879.html

相关文章:

  • 视觉语言大模型应用开发——基于 CLIP、Gemini 与 Qwen2.5-VL 的视频理解内容审核全流程实现
  • ref 简单讲解
  • flutter geolocator Android国内定位失败问题解决
  • JVM 调优全流程案例:从频繁 Full GC 到百万 QPS 的实战蜕变
  • 【大模型本地运行与部署框架】Ollama的cmd常用命令
  • Linux 软件编程(九)网络编程:IP、端口与 UDP 套接字
  • 【Python】两条命令永久切国内源
  • 本地组策略编辑器图形化工具
  • 力扣(在排序数组中查找元素的第一个和最后一个位置)
  • 当我们想用GPU(nlp模型篇)
  • 开源 python 应用 开发(十)音频压缩
  • 开源 python 应用 开发(十一)短语音转文本
  • ZKmall模块商城的跨境电商支付安全方案:加密与权限的双重防护
  • 数据结构 -- 树
  • STM32G4-比较器
  • 亚马逊老品怎么再次爆发流量?
  • 计算机内存中的整型存储奥秘、大小端字节序及其判断方法
  • 量子计算基础
  • 豆包AI PPT与秒出PPT对比评测:谁更适合你?
  • 树莓派安装pyqt5 opencv等库一些问题
  • 使用 YAML 文件,如何优雅地删除 k8s 资源?
  • 高并发用户数峰值对系统架构设计有哪些影响?
  • .java->.class->java 虚拟机中运行
  • 设计模式:抽象工厂模式
  • 实验二 Cisco IOS Site-to-Site Pre-share Key
  • 异质结3.0时代的降本提效革命:捷造科技设备技术创新与产业拐点分析
  • 高级SQL优化 | 告别 Hive 中 GROUP BY 的大 KEY 数据倾斜!PawSQL 自适应优化算法详解
  • Logstash——输出(Output)
  • 大视协作码垛机:颠覆传统制造,开启智能工厂新纪元
  • 【CV】OpenCV①——图形处理简介