Unity 实用方法 合集

Unity 实用方法 合集

代码很简单没有难度,都有注解,可以收藏一下方便后期使用。

Unity 打字机效果

javascript 复制代码
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 坐标旋转计算

javascript 复制代码
原理:以自身为原点,计算增加半径 R 并且旋转 指定角度后 圆上坐标
应用:应用方向有很多吧 比如旋转动量计算,等边三角形遍历等
javascript 复制代码
  /// <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);
    }

球面坐标求值

javascript 复制代码
原理:根据给定的圆心坐标和目标坐标,得到圆心到目标位置的向量。根据要求的延长半径和旋转角度
	  再把夹角转换为弧度之后得到目标点的球面坐标值 并返回
应用:球面计算和均匀分配
javascript 复制代码
 /// <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));
    }
javascript 复制代码
    /// <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;
    }

平滑移动

javascript 复制代码
原理:Vector3.Lerp 插值计算  然后返回趋近值
应用:字面意思  平滑 可以应用到双曲线螺旋
javascript 复制代码
  /// <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

javascript 复制代码
原理:Camera.main.ScreenToWorldPoint
应用:获取鼠标在2D空间中的位置,通常用于2D游戏的鼠标交互
javascript 复制代码
   /// <summary>
    /// 鼠标位置获取
    /// </summary>
    /// <returns></returns>

    public Vector2 GetMousePosition2D()
    {
        Vector3 _MousePosition = Input.mousePosition;
        _MousePosition.z = -Camera.main.transform.position.z;
        return Camera.main.ScreenToWorldPoint(_MousePosition);
    }

屏幕坐标转世界坐标

javascript 复制代码
原理:Camera.main.ScreenToWorldPoint
应用:将屏幕坐标转换为世界坐标,通常用于将鼠标点击位置转换为游戏世界中的坐标
javascript 复制代码
    /// <summary>
    /// 屏幕坐标转世界坐标
    /// </summary>
    /// <param name="screenPosition"></param>
    /// <returns></returns>
    public Vector3 ScreenToWorldPoint(Vector3 _ScreenPosition)
    {
        return Camera.main.ScreenToWorldPoint(_ScreenPosition);
    }

物体朝向目标

javascript 复制代码
原理: Quaternion.LookRotation()
应用:使物体的正面朝向目标位置
javascript 复制代码
   /// <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;
    }

多物体中心点生成

javascript 复制代码
原理:所有位置向量累加并除以数量得到平均值
应用:鱼群算法中心计算、多物体连线等
javascript 复制代码
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;
    }
}

本地图片加载

javascript 复制代码
原理:IO流 读取
应用:场景加载界面或则动态变更图标
javascript 复制代码
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;
        }
    }
}

画面线框显示

javascript 复制代码
原理: 就是 GL 绘画应用变形
应用:画面标注、主题框选等
javascript 复制代码
	/// <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();
        }

    }

画面线框显示 搭载效果

贝塞尔曲线绘制

javascript 复制代码
原理: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分别是起点、两个控制点和终点的坐标。
	通过调整控制点的位置,可以改变贝塞尔曲线的形状。控制点的位置决定了曲线的弯曲程度和方向。
javascript 复制代码
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;
    }
}

贝塞尔曲线绘制 搭载效果

网格弯曲

javascript 复制代码
原理:使用 三次贝塞尔曲线 得到变形后的顶点,然后根据变形后的顶点进行网格重组	 
应用:物体弯曲,道路生成,画面扭曲等
javascript 复制代码
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;
    }
}

网格弯曲 搭载效果

javascript 复制代码
注意需要勾选导入模型的读写权限
javascript 复制代码
变形前
javascript 复制代码
变形后

Delaunay 模型生成

javascript 复制代码
原理:就是使用 Delaunay 算法进行 外接圆判断
应用:模型生成、动态模型补面、最大面积计算等
有一点不完善,过两天抽时间单独研究研究,再出一篇看看。
javascript 复制代码
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;
    }
}
javascript 复制代码
最大三角形
javascript 复制代码
生成物体分布
javascript 复制代码
生成网格 有点问题 需要后期修改

暂时先这样吧,如果有时间的话就会更新,实在看不明白就留言,看到我会回复的。

路漫漫其修远兮,与君共勉。

相关推荐
Envyᥫᩣ1 小时前
C#语言:从入门到精通
开发语言·c#
charon87784 小时前
UE ARPG | 虚幻引擎战斗系统
游戏引擎
小春熙子5 小时前
Unity图形学之Shader结构
unity·游戏引擎·技术美术
IT技术分享社区7 小时前
C#实战:使用腾讯云识别服务轻松提取火车票信息
开发语言·c#·云计算·腾讯云·共识算法
Sitarrrr8 小时前
【Unity】ScriptableObject的应用和3D物体跟随鼠标移动:鼠标放置物体在场景中
3d·unity
极梦网络无忧8 小时前
Unity中IK动画与布偶死亡动画切换的实现
unity·游戏引擎·lucene
△曉風殘月〆14 小时前
WPF MVVM入门系列教程(二、依赖属性)
c#·wpf·mvvm
逐·風16 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
_oP_i17 小时前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
m0_6569747419 小时前
C#中的集合类及其使用
开发语言·c#