使用xna在c#或vb.net中相交两个线段吗?

时间:2012-10-18 20:58:32

标签: c# .net vb.net xna collision-detection

我一直在寻找适合寻找两个线段(每组2个x,y组合)的截距的合适方法的年龄。我见过很多(包括:How do you detect where two line segments intersect?),但我见过的所有人都有瑕疵。主要是如果线条平行但彼此重叠,它们不会检测到碰撞。

我也不需要返回交叉点,只需要一个布尔值即可。

如果有人能指出我正确的方向,我会非常感激,因为我显然是在吮吸几何。 :(

2 个答案:

答案 0 :(得分:5)

有一些数学上优雅的方法可以做到这一点,但如果你正在寻找一个使用基本代数的易于理解的算法,试试这个(这不是代码):

让我们按端点定义两个线段:

l0 : { (x0, y0), (x1, y1) }
l1 : { (x2, y2), {x3, y3) }

首先,获得每条线的斜率截距形式。您可以查找m,b的公式或自己导出它们:

l0 : m0 * x + b0
l1 : m1 * x + b1

如果(m0 != m1)行不平行。要找到潜在交叉点解决l0 = l1

x = (b1 - b0) / (m0 - m1)
y = m0 * x + b0

当且仅当(x, y)位于两个片段上时,片段才会相交。请注意,只检查x坐标就足够了,因为我们已经确定(x, y)在两行上都是:

[编辑反映来自@KenoguLabz的优秀意见]

(x0 <= x <= x1) AND (x2 <= x <= x3) AND (y0 <= y <= y1) AND (y2 <= y <= y3)

min(x0, x1) <= x <= max(x0, x1) AND min(x2, x3) <= x <= max(x2, x3)

如果这些线是平行的并且你想知道它们是否重叠,那么用一行的端点代替上面的x(你只需要对着相反的线进行测试)

希望这会有所帮助。祝你好运!

答案 1 :(得分:2)

这是我最近写的一个小班。斜率和角度的+/-可能并不总是正确的(例如,当角度应为-90时,它返回90,但我使用的trig函数不受此影响)。您可能最感兴趣的函数是GetIntersection,它为并行线返回Nothing(null),否则返回Point。这是代码:

Public Class LineData
    Public Property Point1() As Point
    Public Property Point2() As Point
    Public ReadOnly Property Slope() As Double
        Get
            # 0=Horizontal Line, NaN=Vertical Line
            Return If(Me.Point1.X = Me.Point2.X, Double.NaN, (Me.Point1.Y - Me.Point2.Y) / (Me.Point1.X - Me.Point2.X))
        End Get
    End Property
    Public ReadOnly Property YIntercept() As Double
        Get
            Return If(Double.IsNaN(Me.Slope), Double.NaN, Me.Point1.Y - Me.Slope * Me.Point1.X)
        End Get
    End Property
    Public ReadOnly Property Angle() As Double
        Get
            Return If(Double.IsNaN(Me.Slope), Math.PI / 2, Math.Atan(Me.Slope))
        End Get
    End Property

    Public Sub New(pt1 As Point, pt2 As Point)
        Me.Point1 = pt1
        Me.Point2 = pt2
    End Sub
    Public Sub New(x1 As Double, y1 As Double, x2 As Double, y2 As Double)
        Me.Point1 = New Point(x1, y1)
        Me.Point2 = New Point(x2, y2)
    End Sub
    Public Sub New(ln As Line)
        Me.New(ln.X1, ln.Y1, ln.X2, ln.Y2)
    End Sub

    Public Function GetParallel(spacing As Double) As LineData
        Return Me.GetParallel(spacing, ParallelPosition.Below)
    End Function

    Public Function GetParallel(spacing As Double, pos As ParallelPosition) As LineData
        If Me.Slope = 0 Then # Horizontal Line
            If pos = ParallelPosition.Above OrElse pos = ParallelPosition.Left Then : Return If(Me.Point2.X > Me.Point1.X, New LineData(Me.Point1.X - spacing, Me.Point1.Y - spacing, Me.Point2.X + spacing, Me.Point2.Y - spacing), New LineData(Me.Point1.X + spacing, Me.Point1.Y - spacing, Me.Point2.X - spacing, Me.Point2.Y - spacing))
            Else : Return If(Me.Point2.X > Me.Point1.X, New LineData(Me.Point1.X - spacing, Me.Point1.Y + spacing, Me.Point2.X + spacing, Me.Point2.Y + spacing), New LineData(Me.Point1.X + spacing, Me.Point1.Y + spacing, Me.Point2.X - spacing, Me.Point2.Y + spacing))
            End If
        ElseIf Double.IsNaN(Me.Slope) Then # Vertical Line
            If pos = ParallelPosition.Above OrElse pos = ParallelPosition.Left Then : Return If(Me.Point2.Y > Me.Point1.Y, New LineData(Me.Point1.X - spacing, Me.Point1.Y - spacing, Me.Point2.X - spacing, Me.Point2.Y + spacing), New LineData(Me.Point1.X - spacing, Me.Point1.Y + spacing, Me.Point2.X - spacing, Me.Point2.Y - spacing))
            Else : Return If(Me.Point2.Y > Me.Point1.Y, New LineData(Me.Point1.X + spacing, Me.Point1.Y - spacing, Me.Point2.X + spacing, Me.Point2.Y + spacing), New LineData(Me.Point1.X + spacing, Me.Point1.Y + spacing, Me.Point2.X + spacing, Me.Point2.Y - spacing))
            End If
        Else #Sloped Line
            Dim verticalshift As Double = Math.Abs(spacing / Math.Cos(-Me.Angle))
            Dim horizontalshift As Double = Math.Abs(spacing / Math.Sin(-Me.Angle))
            If Math.Sign(Me.Slope) = -1 Then
                If Me.Point2.X > Me.Point1.X Then
                    If pos = ParallelPosition.Above OrElse pos = ParallelPosition.Left Then : Return New LineData(Me.Point1.X - horizontalshift, Me.Point1.Y, Me.Point2.X, Me.Point2.Y - verticalshift)
                    Else : Return New LineData(Me.Point1.X, Me.Point1.Y + verticalshift, Me.Point2.X + horizontalshift, Me.Point2.Y)
                    End If
                Else
                    If pos = ParallelPosition.Above OrElse pos = ParallelPosition.Left Then : Return New LineData(Me.Point1.X, Me.Point1.Y - verticalshift, Me.Point2.X - horizontalshift, Me.Point2.Y)
                    Else : Return New LineData(Me.Point1.X + horizontalshift, Me.Point1.Y, Me.Point2.X, Me.Point2.Y + verticalshift)
                    End If
                End If
            Else
                If Me.Point2.X > Me.Point1.X Then
                    If pos = ParallelPosition.Above OrElse pos = ParallelPosition.Right Then : Return New LineData(Me.Point1.X, Me.Point1.Y - verticalshift, Me.Point2.X + horizontalshift, Me.Point2.Y)
                    Else : Return New LineData(Me.Point1.X - horizontalshift, Me.Point1.Y, Me.Point2.X, Me.Point2.Y + verticalshift)
                    End If
                Else
                    If pos = ParallelPosition.Above OrElse pos = ParallelPosition.Right Then : Return New LineData(Me.Point1.X + horizontalshift, Me.Point1.Y, Me.Point2.X, Me.Point2.Y - verticalshift)
                    Else : Return New LineData(Me.Point1.X, Me.Point1.Y + verticalshift, Me.Point2.X - horizontalshift, Me.Point2.Y)
                    End If
                End If
            End If
        End If
    End Function

    Public Function CalculateX(y As Double) As Double
        If Me.Slope = 0 Then # Horizontal Line
            If y = Me.Point1.Y OrElse y = Me.Point2.Y Then Return 0 Else Return Double.NaN
        ElseIf Double.IsNaN(Me.Slope) Then # Vertical Line
            Return Me.Point1.X
        Else
            Return (y - Me.YIntercept) / Me.Slope
        End If
    End Function
    Public Function CalculateY(x As Double) As Double
        If Me.Slope = 0 Then # Horizontal Line
            Return Me.Point1.Y
        ElseIf Double.IsNaN(Me.Slope) Then # Vertical Line
            If x = Me.Point1.X OrElse x = Me.Point2.X Then Return 0 Else Return Double.NaN
        Else
            Return Me.Slope * x + Me.YIntercept
        End If
    End Function

    Public Function GetIntersection(ln As LineData) As Point
        If Me.Slope = ln.Slope OrElse (Double.IsNaN(Me.Slope) AndAlso Double.IsNaN(ln.Slope)) Then : Return Nothing
        Else
            If Double.IsNaN(Me.Slope) Then : Return New Point(Me.Point1.X, ln.CalculateY(Me.Point1.X))
            ElseIf Double.IsNaN(ln.Slope) Then : Return New Point(ln.Point1.X, Me.CalculateY(ln.Point1.X))
            ElseIf Me.Slope = 0 Then : Return New Point(ln.CalculateX(Me.Point1.Y), Me.Point1.Y)
            ElseIf ln.Slope = 0 Then : Return New Point(Me.CalculateX(ln.Point1.Y), ln.Point1.Y)
            Else
                Dim x As Double = (Me.YIntercept - ln.YIntercept) / (ln.Slope - Me.Slope)
                Return New Point(x, Me.CalculateY(x))
            End If
        End If
    End Function

    Public Function GetLine() As Line
        Dim templine As New Line
        templine.X1 = Me.Point1.X
        templine.Y1 = Me.Point1.Y
        templine.X2 = Me.Point2.X
        templine.Y2 = Me.Point2.Y
        Return templine
    End Function
End Class

Public Enum ParallelPosition As Byte
    Above
    Below
    Left
    Right
End Enum

希望这有帮助!