Unity 实用方法 合集
- Unity 打字机效果
- 2D 坐标旋转计算
- 球面坐标求值
- 平滑移动
- 鼠标位置获取2D
- 屏幕坐标转世界坐标
- 物体朝向目标
- 多物体中心点生成
- 本地图片加载
- 画面线框显示
- 画面线框显示 搭载效果
- 贝塞尔曲线绘制
- 贝塞尔曲线绘制 搭载效果
- 网格弯曲
- 网格弯曲 搭载效果
- Delaunay 模型生成
代码很简单没有难度,都有注解,可以收藏一下方便后期使用。
Unity 打字机效果
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 打字机效果
/// </summary>
public class TextWriter_ZH : MonoBehaviour
{
[Header("打字速度")]
public float _Delay = 0.1f;
[Header("完整的文字")]
public string _FullText;
// 当前显示的文字
private string _CurrentText = "";
// 计时器
private float _Timer;
// 当前字符索引
private int _CurrentIndex = 0;
void Start()
{
StartCoroutine(ShowText());
}
void Update()
{
if (Input.GetKeyDown(KeyCode.T))
{
// 获取当前时间,精确到秒级
float _CurrentTime = Time.time;
// 将秒级时间转换为毫秒级时间
int _Milliseconds = (int)((_CurrentTime - Mathf.Floor(_CurrentTime)) * 1000);
Debug.Log("Current Time: " + System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss." + _Milliseconds.ToString("000")));
_FullText = "当前时间是: " + System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss." + _Milliseconds.ToString("000"));
//初始化
GetComponent<Text>().text = "";
_CurrentIndex = 0;
}
}
/// <summary>
/// 文字显示
/// </summary>
/// <returns></returns>
IEnumerator ShowText()
{
//字符长度判断
while (_CurrentIndex < _FullText.Length)
{
//时间累加
_Timer += Time.deltaTime;
if (_Timer >= _Delay)
{
//文字输出
_CurrentText += _FullText[_CurrentIndex];
//显示
GetComponent<Text>().text = _CurrentText;
//步进
_CurrentIndex++;
_Timer = 0;
}
yield return null;
}
}
}
2D 坐标旋转计算
原理:以自身为原点,计算增加半径 R 并且旋转 指定角度后 圆上坐标
应用:应用方向有很多吧 比如旋转动量计算,等边三角形遍历等
/// <summary>
/// 2D 坐标旋转计算
/// </summary>
public void AngleCalculation2D()
{
// 假设原坐标的 x 值为 3
double _X = 3;
// 假设原坐标的 y 值为 4
double _Y = 4;
// 假设半径为 5
double _Radius = 5;
// 假设旋转角度为 30 度
double _Angle = 30;
// 将角度转换为弧度
double _Radian = _Angle * Math.PI / 180;
// 计算旋转后的 X Y 坐标
double _NewX = _X * Math.Cos(_Radian) - _Y * Math.Sin(_Radian);
double _NewY = _X * Math.Sin(_Radian) + _Y * Math.Cos(_Radian);
// 计算旋转后点的距离原点的半径
double _NewRadius = Math.Sqrt(_NewX * _NewX + _NewY * _NewY);
// 考虑半径对坐标的缩放
double _FinalX = _NewX * _Radius / _NewRadius;
double _FinalY = _NewY * _Radius / _NewRadius;
Vector2 _Vector2 = new Vector2((float)_FinalX, (float)_FinalY);
Console.WriteLine("旋转后的坐标:({0})", _Vector2);
}
球面坐标求值
原理:根据给定的圆心坐标和目标坐标,得到圆心到目标位置的向量。根据要求的延长半径和旋转角度
再把夹角转换为弧度之后得到目标点的球面坐标值 并返回
应用:球面计算和均匀分配
/// <summary>
/// 3D 坐标旋转计算
/// </summary>
/// <param 圆心坐标="_Center"></param>
/// <param 半径="_Radius"></param>
/// <param 目标位置="_PointA"></param>
/// <param 旋转角度="_Angle"></param>
public void AngleCalculation3D(Vector3 _Center, float _Radius, Vector3 _PointA, float _Angle)
{
假设圆心坐标为 (1, 2, 3)
//Vector3 _Center = new Vector3(1, 2, 3);
假设半径为 5
//float _Radius = 5;
假设三维坐标点 a 为 (4, 5, 6)
//Vector3 _PointA = new Vector3(4, 5, 6);
假设旋转角度为 30 度
//float _Angle = 30;
//转换后球面坐标值
Vector3 _RotatedPoint = RotatePoint(_Center, _PointA, _Radius, _Angle);
Console.WriteLine("旋转后的球面坐标:");
//magnitude 返回该向量的长度
Console.WriteLine("半径:{0}", _RotatedPoint.magnitude);
//Rad2Deg 弧度到度数的转换常数
Console.WriteLine("纬度:{0}", Mathf.Rad2Deg * Mathf.Asin(_RotatedPoint.normalized.y));
Console.WriteLine("经度:{0}", Mathf.Rad2Deg * Mathf.Atan2(_RotatedPoint.normalized.z, _RotatedPoint.normalized.x));
}
/// <summary>
/// 球面坐标求值
/// </summary>
/// <param 圆心坐标="_Center"></param>
/// <param 目标位置="_Point"></param>
/// <param 半径="_Radius"></param>
/// <param 旋转角度="_Angle"></param>
/// <returns></returns>
public static Vector3 RotatePoint(Vector3 _Center, Vector3 _Point, float _Radius, float _Angle)
{
// 统一坐标系
Vector3 _ShiftedPoint = _Point - _Center;
// 计算旋转后的坐标
float _Radian = _Angle * Mathf.Deg2Rad;
float _RotatedX = _ShiftedPoint.x * Mathf.Cos(_Radian) - _ShiftedPoint.z * Mathf.Sin(_Radian);
float _RotatedY = _ShiftedPoint.y;
float _RotatedZ = _ShiftedPoint.x * Mathf.Sin(_Radian) + _ShiftedPoint.z * Mathf.Cos(_Radian);
// 计算旋转后的球面坐标
Vector3 _RotatedPoint = new Vector3(_RotatedX, _RotatedY, _RotatedZ).normalized * _Radius;
// 返回旋转后的点
return _RotatedPoint;
}
平滑移动
原理:Vector3.Lerp 插值计算 然后返回趋近值
应用:字面意思 平滑 可以应用到双曲线螺旋
/// <summary>
/// 平滑移动
/// </summary>
/// <param name="_ObjectToMove"></param>
/// <param name="_TargetPosition"></param>
/// <param name="_Duration"></param>
/// <returns></returns>
public IEnumerator SmoothMoveObject(Transform _ObjectToMove, Vector3 _TargetPosition, float _Duration)
{
float _ElapsedTime = 0f;
Vector3 _StartingPosition = _ObjectToMove.position;
while (_ElapsedTime < _Duration)
{
_ObjectToMove.position = Vector3.Lerp(_StartingPosition, _TargetPosition, _ElapsedTime / _Duration);
_ElapsedTime += Time.deltaTime;
yield return null;
}
_ObjectToMove.position = _TargetPosition;
}
鼠标位置获取2D
原理:Camera.main.ScreenToWorldPoint
应用:获取鼠标在2D空间中的位置,通常用于2D游戏的鼠标交互
/// <summary>
/// 鼠标位置获取
/// </summary>
/// <returns></returns>
public Vector2 GetMousePosition2D()
{
Vector3 _MousePosition = Input.mousePosition;
_MousePosition.z = -Camera.main.transform.position.z;
return Camera.main.ScreenToWorldPoint(_MousePosition);
}
屏幕坐标转世界坐标
原理:Camera.main.ScreenToWorldPoint
应用:将屏幕坐标转换为世界坐标,通常用于将鼠标点击位置转换为游戏世界中的坐标
/// <summary>
/// 屏幕坐标转世界坐标
/// </summary>
/// <param name="screenPosition"></param>
/// <returns></returns>
public Vector3 ScreenToWorldPoint(Vector3 _ScreenPosition)
{
return Camera.main.ScreenToWorldPoint(_ScreenPosition);
}
物体朝向目标
原理: Quaternion.LookRotation()
应用:使物体的正面朝向目标位置
/// <summary>
/// 物体朝向目标
/// </summary>
/// <param 当前物体 ="_ObjectToRotate"></param>
/// <param 朝向目标 ="_TargetPosition"></param>
public void LookAtTarget(Transform _ObjectToRotate, Vector3 _TargetPosition)
{
Vector3 _Direction = _TargetPosition - _ObjectToRotate.position;
Quaternion _Rotation = Quaternion.LookRotation(_Direction);
_ObjectToRotate.rotation = _Rotation;
}
多物体中心点生成
原理:所有位置向量累加并除以数量得到平均值
应用:鱼群算法中心计算、多物体连线等
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 多物体中心点判定
/// </summary>
public class ObjectsCenterPoint_ZH : MonoBehaviour
{
public List<GameObject> _GameObject; // 存储多个物体的数组
private void Start()
{
// 计算中心点
Vector3 _CenterPoint = CalculateCenterPoint();
// 在场景中创建一个表示中心点的标记物体
CreateCenterPointMarker(_CenterPoint);
}
/// <summary>
/// 中心点坐标
/// </summary>
/// <returns></returns>
Vector3 CalculateCenterPoint()
{
Vector3 _CenterPoint = Vector3.zero;
// 累加所有物体的位置
foreach (GameObject obj in _GameObject)
{
_CenterPoint += obj.transform.position;
}
// 求取平均位置
_CenterPoint /= _GameObject.Count;
return _CenterPoint;
}
/// <summary>
/// 中心点位置 物体生成
/// </summary>
/// <param 中心点位置="_CenterPoint"></param>
void CreateCenterPointMarker(Vector3 _CenterPoint)
{
// 在场景中创建一个标记物体表示中心点
GameObject _Marker = GameObject.CreatePrimitive(PrimitiveType.Sphere);
_Marker.transform.position = _CenterPoint;
_Marker.transform.localScale = Vector3.one * 0.5f;
_Marker.GetComponent<Renderer>().material.color = Color.red;
}
}
本地图片加载
原理:IO流 读取
应用:场景加载界面或则动态变更图标
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 图片加载
/// </summary>
public class ImageLoader_ZH : MonoBehaviour
{
public string _ImagePath;
public RawImage _RawImage;
private void Start()
{
// 加载本地图片
Texture2D _Texture = LoadLocalImage(_ImagePath);
if (_Texture != null)
{
// 将纹理设置给RawImage组件进行显示
_RawImage.texture = _Texture;
}
else
{
Debug.LogError("没有显示载体。");
}
}
private Texture2D LoadLocalImage(string _Path)
{
// 使用Unity的API加载本地图片
// 创建一个空的Texture2D对象
Texture2D _Texture = new Texture2D(2, 2);
// 读取图片数据
byte[] _ImageData = System.IO.File.ReadAllBytes(_Path);
// 将图片数据加载到Texture2D对象中
bool _Success = _Texture.LoadImage(_ImageData);
if (_Success)
{
return _Texture;
}
else
{
Destroy(_Texture); // 加载失败时销毁Texture2D对象
return null;
}
}
}
画面线框显示
原理: 就是 GL 绘画应用变形
应用:画面标注、主题框选等
/// <summary>
/// 在渲染后执行
/// 屏幕框选
/// </summary>
private void OnPostRender()
{
//画线这种操作推荐在 OnPostRender()里进行 而不是直接放在Update,所以需要标志来开启
if (_IsSelecting)
{
//开始绘图位置
var startMousePosition = MousePosition;
//鼠标当前位置
Vector3 _MouseEnd = Input.mousePosition;
//保存摄像机变换矩阵
GL.PushMatrix();
//显示材质
if (!_RectMat)
{
return;
}
else
{
//生成画线的材质
_RectMat = new Material(Shader.Find("UI/Default"));
//GameObject(游戏对象)没有显示在层次结构中,没有保存到场景中,也没有被Resources.UnloadUnusedAssets卸载。
_RectMat.hideFlags = HideFlags.HideAndDontSave;
//Gameobject(游戏对象)没有显示在层次结构中,没有保存到场景中,也没有被Resources.UnloadUnusedAssets卸载
_RectMat.shader.hideFlags = HideFlags.HideAndDontSave;
}
_RectMat.SetPass(0);
//设置用屏幕坐标绘图
GL.LoadPixelMatrix();
GL.Begin(GL.QUADS);
//设置颜色和透明度,方框内部透明
GL.Color(new Color(_RectColor.r, _RectColor.g, _RectColor.b, 0.1f));
GL.Vertex3(startMousePosition.x, startMousePosition.y, 0);
GL.Vertex3(_MouseEnd.x, startMousePosition.y, 0);
GL.Vertex3(_MouseEnd.x, _MouseEnd.y, 0);
GL.Vertex3(startMousePosition.x, _MouseEnd.y, 0);
GL.End();
GL.Begin(GL.LINES);
//设置方框的边框颜色 边框不透明
GL.Color(_RectColor);
GL.Vertex3(startMousePosition.x, startMousePosition.y, 0);
GL.Vertex3(_MouseEnd.x, startMousePosition.y, 0);
GL.Vertex3(_MouseEnd.x, startMousePosition.y, 0);
GL.Vertex3(_MouseEnd.x, _MouseEnd.y, 0);
GL.Vertex3(_MouseEnd.x, _MouseEnd.y, 0);
GL.Vertex3(startMousePosition.x, _MouseEnd.y, 0);
GL.Vertex3(startMousePosition.x, _MouseEnd.y, 0);
GL.Vertex3(startMousePosition.x, startMousePosition.y, 0);
GL.End();
//恢复摄像机投影矩阵
GL.PopMatrix();
}
}
画面线框显示 搭载效果
贝塞尔曲线绘制
原理:P(t) = (1 - t)^2 * P0 + 2 * (1 - t) * t * P1 + t^2 * P2
曲线上的点可以通过参数t(取值范围为0到1)来表示。参数t表示曲线上某一点的位置,其中t=0表示起点,t=1表示终点。对于给定的t值,可以使用以下公式计算曲线上的点P(t)的坐标:
其中,P0、P1和P2分别是起点、控制点和终点的坐标。
应用:物体弯曲,道路生成,画面扭曲等
扩展:
三次贝塞尔曲线:三次贝塞尔曲线由四个锚点(起点、终点和两个控制点)组成。
P(t) = (1 - t)^3 * P0 + 3 * (1 - t)^2 * t * P1 + 3 * (1 - t) * t^2 * P2 + t^3 * P3
P0、P1、P2和P3分别是起点、两个控制点和终点的坐标。
通过调整控制点的位置,可以改变贝塞尔曲线的形状。控制点的位置决定了曲线的弯曲程度和方向。
using UnityEngine;
/// <summary>
/// 贝塞尔曲线绘制
/// </summary>
public class BezierCurve_ZH : MonoBehaviour
{
[Header("开始位置")]
public Transform _StartPoint;
[Header("控制带你")]
public Transform _ControlPoint;
[Header("结束位置")]
public Transform _EndPoint;
[Header("精度")]
//越高越平滑 性能消耗越大
public int _Resolution = 10;
private void OnDrawGizmos()
{
DrawBezierCurve();
}
/// <summary>
/// 贝塞尔曲线绘制
/// </summary>
private void DrawBezierCurve()
{
//曲线数组
Vector3[] _Points = new Vector3[_Resolution + 1];
//数组变更
for (int i = 0; i <= _Resolution; i++)
{
float t = i / (float)_Resolution;
_Points[i] = CalculatePointOnCurve(t);
}
//绘制颜色
Gizmos.color = Color.cyan;
//曲线绘制
for (int i = 0; i < _Resolution; i++)
{
Gizmos.DrawLine(_Points[i], _Points[i + 1]);
}
}
/// <summary>
/// 计算曲线上的点
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
private Vector3 CalculatePointOnCurve(float t)
{
float u = 1 - t;
float tt = t * t;
float uu = u * u;
Vector3 point = uu * _StartPoint.position;
point += 2 * u * t * _ControlPoint.position;
point += tt * _EndPoint.position;
return point;
}
}
贝塞尔曲线绘制 搭载效果
网格弯曲
原理:使用 三次贝塞尔曲线 得到变形后的顶点,然后根据变形后的顶点进行网格重组
应用:物体弯曲,道路生成,画面扭曲等
using UnityEngine;
/// <summary>
/// 网格弯曲
/// </summary>
public class ObjectBender_ZH : MonoBehaviour
{
//起始点
public Transform _StartPoint;
//控制点 1
public Transform _ControlPoint1;
//控制点 2
public Transform _ControlPoint2;
//结束点
public Transform _EndPoint;
//精细程度
public int _Eesolution = 10;
//变形网格
public MeshFilter _MeshFilter;
//出十万个
private Mesh _OriginalMesh;
//变形网格
private Mesh _BentMesh;
private void Start()
{
//初始化
//_MeshFilter = GetComponent<MeshFilter>();
_OriginalMesh = _MeshFilter.mesh;
_BentMesh = new Mesh();
_MeshFilter.mesh = _BentMesh;
BendObject();
}
private void Update()
{
BendObject();
}
/// <summary>
/// 网格变形方法
/// </summary>
private void BendObject()
{
//顶点数组
Vector3[] _Vertices = _OriginalMesh.vertices;
//变形顶点数组
Vector3[] _BentVertices = new Vector3[_Vertices.Length];
//变形顶点 遍历赋值
for (int i = 0; i < _Vertices.Length; i++)
{
Vector3 vertex = _Vertices[i];
Vector3 bentPosition = BendVertex(vertex);
_BentVertices[i] = bentPosition;
}
//顶点 三角面 法线 设置
_BentMesh.vertices = _BentVertices;
_BentMesh.triangles = _OriginalMesh.triangles;
_BentMesh.RecalculateNormals();
}
/// <summary>
/// 顶点变形 重组
/// </summary>
/// <param name="_Vertex"></param>
/// <returns></returns>
private Vector3 BendVertex(Vector3 _Vertex)
{
float t = _Vertex.x / (float)(_OriginalMesh.bounds.size.x);
Vector3 _StartPointPosition = _StartPoint.position;
Vector3 _ControlPoint1Position = _ControlPoint1.position;
Vector3 _ControlPoint2Position = _ControlPoint2.position;
Vector3 _EndPointPosition = _EndPoint.position;
Vector3 _BentPosition = CalculatePointOnCurve(t, _StartPointPosition, _ControlPoint1Position, _ControlPoint2Position, _EndPointPosition);
return _BentPosition;
}
/// <summary>
/// 曲线计算
/// 三次贝塞尔曲线
/// </summary>
/// <param 变形 t ="t"></param>
/// <param 开始位置="_StartPoint"></param>
/// <param 控制点01="_ControlPoint1"></param>
/// <param 控制点02 ="_ControlPoint2"></param>
/// <param 结束位置="_EndPoint"></param>
/// <returns></returns>
private Vector3 CalculatePointOnCurve(float t, Vector3 _StartPoint, Vector3 _ControlPoint1, Vector3 _ControlPoint2, Vector3 _EndPoint)
{
float t2 = t * t;
float t3 = t2 * t;
Vector3 _Point =
0.5f * ((2.0f * _ControlPoint1) +
(-_StartPoint + _EndPoint) * t +
(2.0f * _StartPoint - 5.0f * _ControlPoint1 + 4.0f * _ControlPoint2 - _EndPoint) * t2 +
(-_StartPoint + 3.0f * _ControlPoint1 - 3.0f * _ControlPoint2 + _EndPoint) * t3);
return _Point;
}
}
网格弯曲 搭载效果
注意需要勾选导入模型的读写权限
变形前
变形后
Delaunay 模型生成
原理:就是使用 Delaunay 算法进行 外接圆判断
应用:模型生成、动态模型补面、最大面积计算等
有一点不完善,过两天抽时间单独研究研究,再出一篇看看。
填坑了哈,大家如果有兴趣可以去看看。
Delaunay 算法 的 解析 : Unity Delaunay三角剖分算法
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// Delaunay 模型生成
/// </summary>
public class DelaunayAlgorithm : MonoBehaviour
{
[Header("存储要生成 Delaunay 物体")]
public List<Transform> _TraList = new List<Transform>();
[Header("存储要生成 Delaunay 三角网格的点")]
private List<Vector2> _Points = new List<Vector2>();
// 存储生成的三角形
private List<Triangle> _Triangles = new List<Triangle>();
private void Start()
{
for (int i = 0; i < _TraList.Count; i++)
{
_Points.Add(new Vector2(_TraList[i].position.x, _TraList[i].position.z));
}
GenerateDelaunay();
}
/// <summary>
/// Delaunay 三角形生成
/// </summary>
void GenerateDelaunay()
{
// 在点集中加入一个超级三角形
float _MinX = float.MaxValue;
float _MinY = float.MaxValue;
float _MaxX = float.MinValue;
float _MaxY = float.MinValue;
//最大值最小值判定
foreach (Vector2 _Point in _Points)
{
if (_Point.x < _MinX) _MinX = _Point.x;
if (_Point.y < _MinY) _MinY = _Point.y;
if (_Point.x > _MaxX) _MaxX = _Point.x;
if (_Point.y > _MaxY) _MaxY = _Point.y;
}
float _DeltaX = _MaxX - _MinX;
float _DeltaY = _MaxY - _MinY;
float _DeltaMax = Mathf.Max(_DeltaX, _DeltaY);
float _MidX = (_MinX + _MaxX) / 2f;
float _MidY = (_MinY + _MaxY) / 2f;
Vector2 p1 = new Vector2(_MidX - 20 * _DeltaMax, _MidY - _DeltaMax);
Vector2 p2 = new Vector2(_MidX, _MidY + 20 * _DeltaMax);
Vector2 p3 = new Vector2(_MidX + 20 * _DeltaMax, _MidY - _DeltaMax);
//三角形片元 添加
_Triangles.Add(new Triangle(p1, p2, p3));
// 逐个加入点并更新三角形
foreach (Vector2 _Point in _Points)
{
List<Edge> _Polygon = new List<Edge>();
for (int i = _Triangles.Count - 1; i >= 0; i--)
{
//如果是外接圆就证明 当前三角形是 Delaunay 三角形
//如果有任何一个点在其他三角形的外接圆内,则该三角形不是Delaunay三角形。
if (_Triangles[i].CircumcircleContains(_Point))
{
_Polygon.Add(_Triangles[i].e1);
_Polygon.Add(_Triangles[i].e2);
_Polygon.Add(_Triangles[i].e3);
_Triangles.RemoveAt(i);
}
}
//顶点移除
for (int i = _Polygon.Count - 2; i >= 0; i--)
{
for (int j = _Polygon.Count - 1; j >= i + 1; j--)
{
if (_Polygon[i] == _Polygon[j])
{
_Polygon.RemoveAt(j);
_Polygon.RemoveAt(i);
j--;
}
}
}
//加入片元 数组
foreach (Edge edge in _Polygon)
{
_Triangles.Add(new Triangle(edge.p1, edge.p2, _Point));
}
}
// 剔除超级三角形相关的三角形
List<Triangle> _TrianglesToRemove = new List<Triangle>();
foreach (Triangle _Triangle in _Triangles)
{
if (_Triangle.ContainsAnyVertex(p1, p2, p3))
{
_TrianglesToRemove.Add(_Triangle);
}
}
foreach (Triangle triangle in _TrianglesToRemove)
{
_Triangles.Remove(triangle);
}
// 在 Unity 中绘制生成的三角形 Delaunay
foreach (Triangle _Triangle in _Triangles)
{
//if (_Triangle.e1.IsDelaunayEdge(_Triangles))
//{
// Debug.DrawLine(_Triangle.p1, _Triangle.p2, Color.green, 15f);
//}
//if (_Triangle.e2.IsDelaunayEdge(_Triangles))
//{
// Debug.DrawLine(_Triangle.p2, _Triangle.p3, Color.green, 15f);
//}
//if (_Triangle.e3.IsDelaunayEdge(_Triangles))
//{
// Debug.DrawLine(_Triangle.p3, _Triangle.p1, Color.green, 15f);
//}
Debug.DrawLine(_Triangle.p1, _Triangle.p2, Color.green, 15f);
Debug.DrawLine(_Triangle.p2, _Triangle.p3, Color.green, 15f);
Debug.DrawLine(_Triangle.p3, _Triangle.p1, Color.green, 15f);
}
}
}
/// <summary>
/// 三角形数据类
/// </summary>
public class Triangle
{
// 三角形的顶点
public Vector2 p1, p2, p3;
// 三角形的边
public Edge e1, e2, e3;
/// <summary>
/// 三角形 片元
/// </summary>
/// <param 顶点="p1"></param>
/// <param 顶点="p2"></param>
/// <param 顶点="p3"></param>
/// <returns></returns>
public Triangle(Vector2 p1, Vector2 p2, Vector2 p3)
{
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
e1 = new Edge(p1, p2);
e2 = new Edge(p2, p3);
e3 = new Edge(p3, p1);
}
/// <summary>
/// 检查三角形的外接圆是否包含指定的点
/// 给定的点在三角形的外接圆内,返回true;否则,说明给定的点不在外接圆内,返回false
/// </summary>
/// <param 顶点="point"></param>
/// <returns></returns>
public bool CircumcircleContains(Vector2 point)
{
//计算三角形的外接圆的圆心和半径
float d1 = (p1.x - point.x) * (p1.x - point.x) + (p1.y - point.y) * (p1.y - point.y);
float d2 = (p2.x - point.x) * (p2.x - point.x) + (p2.y - point.y) * (p2.y - point.y);
float d3 = (p3.x - point.x) * (p3.x - point.x) + (p3.y - point.y) * (p3.y - point.y);
float a = (p1.x * (p2.y - p3.y) + p2.x * (p3.y - p1.y) + p3.x * (p1.y - p2.y)) * 2f;
if (Mathf.Abs(a) < 0.00001f)
{
return false;
}
//检查指定点与圆心的距离是否小于或等于半径的平方
float centerX = ((p1.x * p1.x + p1.y * p1.y) * (p2.y - p3.y) + (p2.x * p2.x + p2.y * p2.y) * (p3.y - p1.y) + (p3.x * p3.x + p3.y * p3.y) * (p1.y - p2.y)) / a;
float centerY = ((p1.x * p1.x + p1.y * p1.y) * (p3.x - p2.x) + (p2.x * p2.x + p2.y * p2.y) * (p1.x - p3.x) + (p3.x * p3.x + p3.y * p3.y) * (p2.x - p1.x)) / a;
float radius = Mathf.Sqrt((centerX - p1.x) * (centerX - p1.x) + (centerY - p1.y) * (centerY - p1.y));
float dist = (point.x - centerX) * (point.x - centerX) + (point.y - centerY) * (point.y - centerY);
return dist <= radius * radius;
}
/// <summary>
/// 检查三角形是否包含指定的顶点
/// 最大三角形判定
/// </summary>
/// <param name="v1"></param>
/// <param name="v2"></param>
/// <param name="v3"></param>
/// <returns></returns>
public bool ContainsAnyVertex(Vector2 v1, Vector2 v2, Vector2 v3)
{
return p1 == v1 || p1 == v2 || p1 == v3 ||
p2 == v1 || p2 == v2 || p2 == v3 ||
p3 == v1 || p3 == v2 || p3 == v3;
}
/ <summary>
/ Delaunay边 判定
/ 确定是否绘制当前三角形的边
/ </summary>
/ <returns></returns>
//public bool IsDelaunay()
//{
// // 检查三角形的每条边是否是Delaunay边
// //return e1.IsDelaunayEdge() && e2.IsDelaunayEdge() && e3.IsDelaunayEdge();
//}
}
/// <summary>
/// 三角边
/// 表示边的类
/// </summary>
public class Edge
{
// 边的两个顶点
public Vector2 p1, p2;
public Edge(Vector2 p1, Vector2 p2)
{
this.p1 = p1;
this.p2 = p2;
}
/// <summary>
/// 重写 Equals 方法,用于比较边的相等性
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
Edge other = (Edge)obj;
return (p1 == other.p1 && p2 == other.p2) || (p1 == other.p2 && p2 == other.p1);
}
/// <summary>
/// 重写 GetHashCode 方法,用于哈希表存储
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return p1.GetHashCode() ^ p2.GetHashCode();
}
/// <summary>
/// Delaunay 三角边判断
/// </summary>
/// <param 三角片元数组="_Triangles"></param>
/// <returns></returns>
public bool IsDelaunayEdge(List<Triangle> _Triangles)
{
// 检查当前边是否与其他三角形的外接圆相交
foreach (Triangle _Triangle in _Triangles)
{
if (_Triangle.CircumcircleContains(new Vector2(p1.x, p1.y)) || _Triangle.CircumcircleContains(new Vector2(p2.x, p2.y)))
{
return false;
}
}
return true;
}
}
最大三角形
生成物体分布
生成网格 有点问题 需要后期修改
暂时先这样吧,如果有时间的话就会更新,实在看不明白就留言,看到我会回复的。
路漫漫其修远兮,与君共勉。