問題分享: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);}}}
}