unity 一个点在不规则图形内限制移动
2022 06 15
1判断 菱形两个相邻的点 和坐标原点 形成的三角区域
判断这个点 是否在这个扇形区域
private bool TestCross(Vector3 a, Vector3 b)
{
//计算向量 a、b 的叉积,结果为 向量
Vector3 c = Vector3.Cross(a, b);
// 通过反正弦函数获取向量 a、b 夹角(默认为弧度)
float radians = Mathf.Asin(Vector3.Distance(Vector3.zero, Vector3.Cross(a.normalized, b.normalized)));
float angle = radians * Mathf.Rad2Deg;
// 判断顺时针、逆时针方向,是在 2D 平面内的,所以需指定一个平面,
//下面以X、Z轴组成的平面为例 , (Y 轴为纵轴),
// 在 X、Z 轴平面上,判断 b 在 a 的顺时针或者逆时针方向,
if (c.y > 0)
{
return true;
// b 在 a 的顺时针方向
}
else if (c.y == 0)
{
return true;
// b 和 a 方向相同(平行)
}
else
{
return false;
// b 在 a 的逆时针方向
}
}
2 在计算这个点是否 封闭三角区域移动的最大对应的坐标 进行限制
private Vector3 RetDisTanceV3(Vector3 ve, Vector3 VeMin, Vector3 VeMax)
{
Vector3 veOut = Vector3.zero;
ve.y = 0;
VeMin.y = 0;
VeMax.y = 0;
Vector3 MinOrmax = new Vector3(VeMax.x - VeMin.x, 0, VeMax.z - VeMin.z);//向量 vemin--vemax
Vector3 minOrZero = -VeMin;
float DotMinMax = Vector3.Angle(MinOrmax, minOrZero);//最小位置 和原点 夹角
Vector3 veOrVemin = new Vector3(ve.x - VeMin.x, 0, ve.z - VeMin.z);//min到ve的向量
float currentAngle = Vector3.Angle(veOrVemin, MinOrmax);//算出 min到max向量 和min 到ve向量的夹角
float maxOrAng = Vector3.Angle(minOrZero, veOrVemin);//算出 min到ve向量 和min 到原点向量的夹角
float minOrVeDis = Mathf.Sqrt((VeMin.x - ve.x) * (VeMin.x - ve.x) + (VeMin.z - ve.z) * (VeMin.z - ve.z));//算出最小点到 当前位置的距离
if (!Mathf.Approximately(maxOrAng, DotMinMax))
{
float minAndveDis = minOrVeDis * Mathf.Cos(currentAngle * Mathf.Deg2Rad);
//在我的 范围内
float r = Mathf.Sqrt((VeMin.x - VeMax.x) * (VeMin.x - VeMax.x) + (VeMin.z - VeMax.z) * (VeMin.z - VeMax.z));
veOut.z = (minAndveDis * (VeMax.z - VeMin.z)) / r + VeMin.z;
veOut.x = (minAndveDis * (VeMax.x - VeMin.x)) / r + VeMin.x;
}
else
{
//刚好在我的范围
veOut = ve;
}
return veOut;
}
3列如 我进行一个菱形测试(需要多边形 传入多个点信息)
/// <summary>
/// 限制的四个 最大边界
/// 要求 以 ABCD 的排序 顺时针添加
/// 可以以任意点 为起点的 (必须为顺时针 添加)
/// </summary>
Vector3 MaximizeBoundaryA = new Vector3(20, 0, 0);
Vector3 MaximizeBoundaryB = new Vector3(0, 0, 20);
Vector3 MaximizeBoundaryC = new Vector3(-20, 0, 0);
Vector3 MaximizeBoundaryD = new Vector3(0, 0, -20);
private Vector3 SetProPistion(Vector3 ve)
{
Vector3 veou = Vector3.zero;
if (TestCross(ve, MaximizeBoundaryA) && !TestCross(ve, MaximizeBoundaryB))
{
veou = RetDisTanceV3(ve, MaximizeBoundaryA, MaximizeBoundaryB);
}
else if (TestCross(ve, MaximizeBoundaryD) && !TestCross(ve, MaximizeBoundaryA))
{
veou = RetDisTanceV3(ve, MaximizeBoundaryD, MaximizeBoundaryA);
}
else if (TestCross(ve, MaximizeBoundaryB) && !TestCross(ve, MaximizeBoundaryC))
{
veou = RetDisTanceV3(ve, MaximizeBoundaryB, MaximizeBoundaryC);
}
else //(TestCross(ve, MaximizeBoundaryC) && !TestCross(ve, MaximizeBoundaryD))
{
veou = RetDisTanceV3(ve, MaximizeBoundaryC, MaximizeBoundaryD);
}
return veou;
}
2022 06 24
上面 代码 修改已知BUG 如果检查不规则多边形 会有问题
//把上面的的 private bool TestCross(Vector3 a, Vector3 b) 改为下面的这个方法
private bool TestCross(Vector3 start, Vector3 a,Vector3 b)
{
var v1=a-start;
var v2=b-start;
return v1.x*v2.z-v2.x*v1.z<0
}