当前位置: 首页 > 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.dtcms.com/a/346367.html

相关文章:

  • Day2--HOT100--283. 移动零,11. 盛最多水的容器,15. 三数之和
  • 94. 城市间货物运输 I, Bellman_ford 算法, Bellman_ford 队列优化算法
  • 【Android】 连接wifi时,强制应用使用流量
  • 反射【Reflect】
  • 深入浅出【最小生成树】:Prim与Kruskal算法详解
  • 111、【OS】【Nuttx】【周边】效果呈现方案解析:-print0 选项
  • AQS模板方法
  • 使用 Google 开源 AI 工具 LangExtract 进行结构化信息抽取
  • 单片机---------WIFI模块
  • Seaborn数据可视化实战:Seaborn数据可视化入门-绘制统计图表与数据分析
  • Dify 从入门到精通(第 49/100 篇):Dify 的自动化测试
  • STM32 硬件I2C读写MPU6050
  • 【链表 - LeetCode】24. 两两交换链表中的节点
  • 纯手撸一个RAG
  • 黄飞对话小熊电器流程与IT负责人:企业数字化进阶与AI实践如何落地?
  • QIcon::actualSize的作用和用法
  • 2025/8/22 xxl-job速通
  • 解决 微信开发者工具 :下载基础库版本 2.31.0 失败
  • RAG和微调是什么?两者的区别?什么场景使用RAG或微调?判断依据是什么?
  • LINUX网络编程--网络的发展与通信
  • AI赋能环保精准治理:AI水质监测溯源快、空气质量预测施策准,守护生态新效能
  • 关于 java+gradle的弹窗多选应用app
  • 【GPT入门】第54课 量化位数与存储大小的影响
  • Java 面试题训练助手 Web 版本
  • 网络通信——UDP协议。
  • Kubernetes 1.28 集群部署指南(基于 Containerd 容器运行时)
  • 笔记:二叉树构建方法
  • 从“配置化思维”到“前端效率革命”:xiangjsoncraft 如何用 JSON 简化页面开发?
  • 【源码】MES系统:从下达计划、执行反馈、异常预警到过程控制的一整套执行中枢。
  • FastTracker:实时准确的视觉跟踪