bbo*_*sak 5 c# collision-detection opentk
我正在开发一个新游戏,并试图根据玩家相对于斜坡坐标的坐标来检测玩家(在斜坡上)是否与给定的网格发生碰撞。我正在使用这个功能,它似乎不起作用(斜率似乎太小或什么)
//Slopes
float slopeY = max.Y-min.Y;
float slopeZ = max.Z-min.Z;
float slopeX = max.X-min.X;
float angle = (float)Math.Atan(slopeZ/slopeY);
//Console.WriteLine(OpenTK.Math.Functions.RadiansToDegrees((float)Math.Atan(slopeZ/slopeY)).ToString()+" degrees incline");
slopeY = slopeY/slopeZ;
float slopeZX = slopeY/slopeX;
//End slopes
float surfaceposX = max.X-coord.X;
float surfaceposY = max.Y-coord.Y;
float surfaceposZ = min.Z-coord.Z;
min-=sval;
max+=sval;
//Surface coords
//End surface coords
//Y SHOULD = mx+b, where M = slope and X = surfacepos, and B = surfaceposZ
if(coord.X<max.X& coord.X>min.X&coord.Y>min.Y&coord.Y<max.Y&coord.Z>min.Z&coord.Z<max.Z) {
if(slopeY !=0) {
Console.WriteLine("Slope = "+slopeY.ToString()+"SlopeZX="+slopeZX.ToString()+" surfaceposZ="+surfaceposZ.ToString());
Console.WriteLine(surfaceposY-(surfaceposY*slopeY));
//System.Threading.Thread.Sleep(40000);
if(surfaceposY-(surfaceposZ*slopeY)<3 || surfaceposY-(surfaceposX*slopeZX)<3) {
return true;
} else {
return false;
}
} else {
return true;
}
} else {
return false;
}
Run Code Online (Sandbox Code Playgroud)
有什么建议?
示例输出:
59.86697
6.225558 2761.331
68.3019 度倾斜
59.86698,46.12445
59.86698
6.225558 2761.332
0 度倾斜

编辑:部分解决了问题。坡度检测有效,但现在我可以穿墙了???
//Slopes
float slopeY = max.Y-min.Y;
float slopeZ = max.Z-min.Z;
float slopeX = max.X-min.X;
float angle = (float)Math.Atan(slopeZ/slopeY);
//Console.WriteLine(OpenTK.Math.Functions.RadiansToDegrees((float)Math.Atan(slopeZ/slopeY)).ToString()+" degrees incline");
slopeY = slopeY/slopeZ;
float slopey = slopeY+1/slopeZ;
float slopeZX = slopeY/slopeX;
//End slopes
float surfaceposX = min.X-coord.X;
float surfaceposY = max.Y-coord.Y;
float surfaceposZ = min.Z-coord.Z;
min-=sval;
max+=sval;
//Surface coords
//End surface coords
//Y SHOULD = mx+b, where M = slope and X = surfacepos, and B = surfaceposZ
if(coord.X<max.X& coord.X>min.X&coord.Y>min.Y&coord.Y<max.Y&coord.Z>min.Z&coord.Z<max.Z) {
if(slopeY !=0) {
Console.WriteLine("Slope = "+slopeY.ToString()+"SlopeZX="+slopeZX.ToString()+" surfaceposZ="+surfaceposZ.ToString());
Console.WriteLine(surfaceposY-(surfaceposY*slopeY));
//System.Threading.Thread.Sleep(40000);
surfaceposZ = Math.Abs(surfaceposZ);
if(surfaceposY>(surfaceposZ*slopeY) & surfaceposY-2<(surfaceposZ*slopeY) || surfaceposY>(surfaceposX*slopeZX) & surfaceposY-2<(surfaceposX*slopeZX)) {
return true;
} else {
return false;
}
} else {
return true;
}
} else {
return false;
}
Run Code Online (Sandbox Code Playgroud)
您是否考虑过实现 BSP 树?即使您使用现在使用的代码解决了错误,对于任何像样的大小/复杂性的网格来说,速度都会很慢。BSP 或四叉树对于简化代码和提高性能大有帮助,而且它们非常容易实现。
编辑
如果您只关心地形(没有垂直的墙壁、门等),四叉树可能更合适:
这两种算法都旨在将几何图形划分为树,以便于搜索。就您而言,您正在搜索用于碰撞目的的多边形。构建 BSP 树(非常简单):
定义树中节点的结构:
public class BspNode
{
public List<Vector3> Vertices { get; set; }
// plane equation coefficients
float A, B, C, D;
BspNode front;
BspNode back;
public BspNode(Vector3 v1, Vector3 v2, Vector3 v3)
{
Vertices = new List<Vector3>();
Vertices.AddRange(new[] { v1, v2, v3 });
GeneratePlaneEquationCoefficients();
}
void GeneratePlaneEquationCoefficients()
{
// derive the plane equation coefficients A,B,C,D from the input vertex list.
}
bool IsInFront(Vector3 point)
{
bool pointIsInFront=true;
// substitute point.x/y/z into the plane equation and compare the result to D
// to determine if the point is in front of or behind the partition plane.
if (pointIsInFront && front!=null)
{
// POINT is in front of this node's plane, so check it against the front list.
pointIsInFront = front.IsInFront(point);
}
else if (!pointIsInFront && back != null)
{
// POINT is behind this plane, so check it against the back list.
pointIsInFront = back.IsInFront(point);
}
/// either POINT is in front and there are no front children,
/// or POINT is in back and there are no back children.
/// Either way, recursion terminates here.
return pointIsInFront;
}
/// <summary>
/// determines if the line segment defined by v1 and v2 intersects any geometry in the tree.
/// </summary>
/// <param name="v1">vertex that defines the start of the ray</param>
/// <param name="v2">vertex that defines the end of the ray</param>
/// <returns>true if the ray collides with the mesh</returns>
bool SplitsRay(Vector3 v1, Vector3 v2)
{
var v1IsInFront = IsInFront(v1);
var v2IsInFront = IsInFront(v2);
var result = v1IsInFront!=v2IsInFront;
if (!result)
{
/// both vertices are on the same side of the plane,
/// so this node doesn't split anything. Check it's children.
if (v1IsInFront && front != null)
result = front.SplitsRay(v1, v2);
else if (!v1IsInFront && back != null)
result = back.SplitsRay(v1, v2);
}
else
{
/// this plane splits the ray, but the intersection point may not be within the face boundaries.
/// 1. calculate the intersection of the plane and the ray : intersection
/// 2. create two new line segments: v1->intersection and intersection->v2
/// 3. Recursively check those two segments against the rest of the tree.
var intersection = new Vector3();
/// insert code to magically calculate the intersection here.
var frontSegmentSplits = false;
var backSegmentSplits = false;
if (front!=null)
{
if (v1IsInFront) frontSegmentSplits=front.SplitsRay(v1,intersection);
else if (v2IsInFront) frontSegmentSplits=front.SplitsRay(v2,intersection);
}
if (back!=null)
{
if (!v1IsInFront) backSegmentSplits=back.SplitsRay(v1,intersection);
else if (!v2IsInFront) backSegmentSplits=back.SplitsRay(v2,intersection);
}
result = frontSegmentSplits || backSegmentSplits;
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
从网格中选择一个“分区”平面(面),将网格的其余部分大致分成两部分。对于复杂的几何体来说,这要容易得多,因为完全凸的项目(球体等)往往看起来像列表而不是树。
BspNode从定义分区平面的顶点创建一个新实例。
检查碰撞时,您有两种选择。
单点:通过调用根节点来检查角色或对象相对树移动的坐标.IsInFront(moveDestination)。如果该方法返回 false,则目标点位于网格“内部”,并且发生碰撞。如果该方法返回 true,则目标点位于网格“外部”,并且没有发生碰撞。
射线相交。这有点棘手。.SplitsRay()使用对象的当前位置和目标位置调用根节点的方法。如果方法返回true,则在两个位置之间移动将通过网格进行过渡。这是一种高级(尽管更复杂)的检查,因为它会捕获边缘情况,例如当所需的移动将一个对象一步完全穿过一个对象时。
我只是快速地将示例代码组合在一起;它不完整,甚至可能无法编译,但它应该让您朝着正确的方向前进。
BSP 的另一个好处是:使用该.SplitsRay()方法,您可以确定地图上的一个点从另一个点是否可见。有些游戏用它来确定 NPC/AI 是否可以看到对方或真正的玩家。您可以对其稍加修改来确定他们是否可以听到彼此的行走声等。
这可能看起来比您原来的方法复杂得多,但它最终更加强大和灵活。值得你花时间去调查。
| 归档时间: |
|
| 查看次数: |
1113 次 |
| 最近记录: |