下面是个人在开发中编写的常用数学运算函数,具体的意义会在后面解释,废话不说,先上代码:
注意一些具有方向的函数时建立在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)