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