Unity个人常用数学运算函数总结

下面是个人在开发中编写的常用数学运算函数,具体的意义会在后面解释,废话不说,先上代码:

注意一些具有方向的函数时建立在XZ平面上的计算。

 

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class MathTools
{
    /// <summary>
    /// 获取从起点到末点的固定点表路径-包含起点和末点,包含起点
    /// </summary>
    /// <param name="pointWay">路径点表,</param>
    /// <param name="space">点与点之间的距离</param>
    /// <returns></returns>
    public static List<Vector3> GetEqualySpacePoints(List<Vector3> pointWay, float space)
    {
        List<Vector3> points = new List<Vector3>();
        if (pointWay == null || pointWay.Count == 0) return points;
        Vector3 indexPoint = pointWay[0];
        float tempSpaceDistance = 0;
        points.Add(pointWay[0]);
        foreach (Vector3 point in pointWay)
        {
            while (indexPoint != point)
            {
                Vector3 tempPoint = indexPoint;
                indexPoint = Vector3.MoveTowards(indexPoint, point, 0.02f);
                tempSpaceDistance += Vector3.Distance(tempPoint, indexPoint);
                if (tempSpaceDistance >= space)
                {
                    tempSpaceDistance = 0;
                    points.Add(indexPoint);
                }
            }
        }

        return points;
    }

    /// <summary>
    /// 获取从起点到末点的固定点表路径-包含起点和末点,包含起点
    /// </summary>
    /// <param name="pointWay">路径点表</param>
    /// <param name="space">间隔距离</param>
    /// <returns></returns>
    public static List<Vector3> GetEqualySpacePointsQuickly(List<Vector3> pointWay,float space)
    {
        List<Vector3> points = new List<Vector3>();

        #region 移动索引点
        int index = 0;
        float offset = 0;
        #endregion

        float distance = 0;
        while (index < pointWay.Count - 1)
        {
            if (space <= 0) break;

            Vector3 indexPoint = pointWay[index] + (pointWay[index + 1] - pointWay[index]).normalized * offset;
            float dis = Vector3.Distance(indexPoint, pointWay[index + 1]);
            float tempDistance = dis + distance;
            if (tempDistance >= space)
            {
                offset += (space - distance);
                if (distance == 0&&offset!=0) points.Add(indexPoint);//此处offset==0说明发生了两个相邻的点重合的情况,所以相邻的后一个点不需要被加入表
                distance = 0;
            }
            else
            {
                distance = tempDistance;
                if (offset != 0 || index == 0) points.Add(indexPoint);
                offset = 0;
                index += 1;
            }
        }

        return points;
    }

    /// <summary>
    /// 从一个点表中获取一个线性距离距离内的点,最后一点可以是截取的一个点
    /// </summary>
    /// <param name="pointWay"></param>
    /// <param name="distance"></param>
    /// <returns></returns>
    public static List<Vector3> GetDistancePoints(List<Vector3> pointWay,float distance)
    {
        List<Vector3> points = new List<Vector3>();
        float tDistance=0;
        for(int i = 0; i < pointWay.Count; i++)
        {
            if (points.Count == 0)
            {
                points.Add(pointWay[0]);
                continue;
            }

            float dis = Vector3.Distance(pointWay[i - 1], pointWay[i]);
            float tDis = tDistance + dis;

            if (tDis < distance)
            {
                points.Add(pointWay[i]);
                tDistance = tDis;
            }else if(tDis == distance)
            {
                points.Add(pointWay[i]);
                tDistance = tDis;
                break;
            }else if(tDis > distance) //生成新的点,并添加到points
            {
                Vector3 dir = pointWay[i] - pointWay[i - 1];
                Vector3 newPoint = pointWay[i - 1] + dir.normalized * (distance - tDistance);
                points.Add(newPoint);
                tDistance = distance;
                break;
            }
        }
        if (tDistance != distance) points = new List<Vector3>();
        return points;
    }

    ///// <summary>
    ///// 从一个点表中,砍掉从起点开始的一个线性距离范围的点
    ///// </summary>
    ///// <param name="pointWay"></param>
    ///// <param name="distance"></param>
    //public void CutDistancePoints(ref List<Vector3> pointWay,float distance)
    //{
    //    List<Vector3> points = new List<Vector3>();
    //    float tDistance = 0;
    //    while (tDistance < distance)
    //    {

    //    }
    //}

    /// <summary>
    /// 获取一个路径的线性长度
    /// </summary>
    /// <param name="pointWay"></param>
    /// <returns></returns>
    public static float GetPathLength(List<Vector3> pointWay)
    {
        float distance = 0;
        Vector3 tempPoint=Vector3.zero;
        if (pointWay.Count > 0) tempPoint = pointWay[0];
        foreach(Vector3 v in pointWay)
        {
            distance += Vector3.Distance(v, tempPoint);
            tempPoint = v;
        }
        return distance;
    }

    /// <summary>
    /// 获取一个线性布局的点集(1010101),点之间等距,靠中间布局,即当原子数量只有一个的时候,放在中间
    /// </summary>
    /// <param name="centerPos">中心位置</param>
    /// <param name="dir">布局方向</param>
    /// <param name="length">布局长度</param>
    /// <param name="count">原子数量</param>
    /// <returns></returns>
    public static List<Vector3> GetLineGridWithCenterPoints(Vector3 centerPos, Vector3 dir, float length, int count, UnityAction<Vector3> del = null)
    {
        List<Vector3> points = new List<Vector3>();

        float angleSpace = length / (count - 1);
        float firstAngle = length / 2;

        if (count == 1)
        {
            points.Add(centerPos);

            if (del != null) del(centerPos);
            return points;
        }

        for (int i = 0; i < count; i++)
        {
            Vector3 pos = centerPos + dir * (firstAngle - angleSpace * i);
            points.Add(pos);
            if (del != null) del(pos);
        }
        return points;
    }

    /// <summary>
    /// 获取一个扇形上的固定数量的点,坐标系为世界坐标
    /// 1010101010101
    /// </summary>
    /// <param name="count"></param>
    /// <param name="pos"></param>
    /// <param name="angel"></param>
    /// <param name="radius"></param>
    /// <param name="del"></param>
    /// <returns></returns>
    public static List<TransformGeoData> GetSectorStaticCountDatas(int count, Vector3 pos, float angel, float radius, UnityAction<TransformGeoData> del = null)
    {
        List<TransformGeoData> trans = new List<TransformGeoData>();

        //0101010
        float angleSpace = angel / (count - 1);
        float firstAngle = angel / 2;
        if (count == 1)
        {
            TransformGeoData transformGeoData = new TransformGeoData();
            transformGeoData.position = pos + Vector3.forward * radius;
            transformGeoData.rotation = Quaternion.Euler(0, 0, 0);
            if (del != null) del(transformGeoData);
            trans.Add(transformGeoData);
            return trans;
        }

        for (int i = 0; i < count; i++)
        {
            TransformGeoData transformGeoData = new TransformGeoData();
            transformGeoData.rotation = Quaternion.Euler(0, firstAngle - angleSpace * i, 0);
            transformGeoData.position = pos + (transformGeoData.rotation * Vector3.forward) * radius;
            if (del != null) del(transformGeoData);
            trans.Add(transformGeoData);
        }

        return trans;

    }

    /// <summary>
    /// 获取一个环上的点表,相邻点之间的距离相等
    /// </summary>
    /// <param name="centerPos"></param>
    /// <param name="radius"></param>
    /// <param name="count"></param>
    /// <param name="del"></param>
    /// <returns></returns>
    public static List<Vector3> GetRingStaticCountPoints(Vector3 centerPos, float radius, int count, Vector3 forward, UnityAction<Vector3> del = null)
    {
        List<Vector3> points = new List<Vector3>();

        float length = radius * Mathf.PI * 2;//获取圆圈周长
        if (count == 0) return points;

        float angle = 360f / count;

        for (int i = 0; i < count; i++)
        {
            Vector3 dir;
            if (i == 0)
            {
                dir = forward;
            }
            else
            {
                dir = Quaternion.Euler(0f, angle * i, 0f) * forward;
            }
            Vector3 pos = centerPos + dir * radius;
            if (del != null) del(pos);
            points.Add(pos);
        }

        return points;
    }

    /// <summary>
    /// 目标是否在扇形区域内(也可认为是锥形区域)
    /// </summary>
    /// <param name="centerPos">扇形中心</param>
    /// <param name="forward">中心方向</param>
    /// <param name="angle">角度范围</param>
    /// <param name="radius">半径</param>
    /// <param name="targetPos">目标位置</param>
    /// <returns></returns>
    public static bool InAngleRange(Vector3 centerPos, Vector3 forward, float angle, float radius, Vector3 targetPos)
    {
        Vector3 dir = targetPos - centerPos;
        float ang1 = Vector3.Angle(forward, dir);
        if (ang1 > Mathf.Abs(angle / 2)) return false;
        float dis1 = Vector3.Distance(targetPos, centerPos);
        if (dis1 > radius) return false;
        return true;
    }

    //public O GetNearstTransform<T,O>(T target,List<T> objs)
    //{
    //    O o=objs.Count>0?objs[0].GetComponent<O> 

    //    return default(O);
    //}
}

/// <summary>
/// 一个Transfor的几何信息
/// </summary>
public struct TransformGeoData
{
    public Vector3 position;
    public Quaternion rotation;
}

 

 

 

1.获取从起点到终点的固定点表路径,点与点之间的距离为space,并且如果末尾出现盈余,那么最后原来的终点将会被抛弃,

GetEqualySpacePoints(List<Vector3> pointWay, float space)

注意这里是点路径移动计算,因此并不是绝对精确

2.获取一个线性布局的点集(1010101),点之间等距,靠中间布局,即当原子数量只有一个的时候,放在中间

public static List<Vector3> GetLineGridWithCenterPoints(Vector3 centerPos,Vector3 dir,float length,int count,UnityAction<Vector3> del=null)

其中del是可以在这个点进行一些操作,比如生成一个物体等,从而可以避免在获取这些点后进行第二次循环

3.获取一个环上的点表,相邻点之间的距离相等

public static List<Vector3> GetRingStaticCountPoints(Vector3 centerPos,float radius,int count,Vector3 forward,UnityAction<Vector3> del=null)

其中forward的方向是当前的方向,这里的意义是,首先计算的第一个结果是以世界默认旋转为0计算的,然后在整体中心旋转到forward方向;或者可以理解为先以局部坐标获得结果,再转换为世界坐标方向。

4.目标是否在扇形区域内(也可认为是锥形区域)

public static bool InAngleRange(Vector3 centerPos,Vector3 forward,float angle,float radius,Vector3 targetPos)

 5.获取一个扇形上的固定数量的点,坐标系为世界坐标,这里没有做forwar处理,有兴趣的可以自己添加,即旋转叠加

public static List<TransformGeoData> GetSectorStaticCountDatas(int count, Vector3 pos, float angel, float radius, UnityAction<TransformGeoData> del = null)

 

posted @ 2020-11-07 21:33  小辉歌  阅读(364)  评论(0编辑  收藏  举报