[BM V. 1.16] 2D Circle / Circle Kollision

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

Fetze

Betreff: [BM V. 1.16] 2D Circle / Circle Kollision

BeitragSa, März 25, 2006 11:35
Antworten mit Zitat
Benutzer-Profile anzeigen
Code: [AUSKLAPPEN]

'Notationskürzel "csp"
Type ColShape
   Global iCount            :Int
   
   Global sID               :String[]   
   Global iCircleNum         :Int[]      
   Global iCircleX            :Int[][]   '[ColShapeNum][CircleNum]
   Global iCircleY            :Int[][]   '[ColShapeNum][CircleNum]
   Global iCircleRadius      :Int[][]   '[ColShapeNum][CircleNum]
   
   Field iType               :Int
   Field fX               :Float
   Field fY               :Float
   Field fAngle            :Float
   'Temporär:
   Field fCircleXTemp         :Float[]
   Field fCircleYTemp         :Float[]
   
   
   Method New()
   End Method
   
   'fParXCam und fParYCam werden zur Position beim Zeichnen dazuaddiert
   Method Draw:Byte(fParXCam:Float = 0.0, fParYCam:Float = 0.0)
      Local iLoop:Int
      
      SetBlend ALPHABLEND
      SetAlpha 0.3
      SetColor 255, 0, 0
      For iLoop = 0 To iCircleNum[iType] - 1
         DrawOval fX + fCircleXTemp[iLoop] - iCircleRadius[iType][iLoop] + fParXCam, fY + fCircleYTemp[iLoop] - iCircleRadius[iType][iLoop] + fParYCam, 2 * iCircleRadius[iType][iLoop], 2 * iCircleRadius[iType][iLoop]
      Next
      SetAlpha 1.0
      SetColor 255, 255, 255
      SetBlend MASKBLEND
      
      Return True
   End Method
   
   Method Update:Byte(fParX:Float, fParY:Float, fParAngle:Float)
      
      If fAngle <> fParAngle Then
         For Local iLoop:Int = 0 To iCircleNum[iType] - 1
            fCircleXTemp[iLoop] = iCircleX[iType][iLoop]
            fCircleYTemp[iLoop] = iCircleY[iType][iLoop]
            If fCircleXTemp[iLoop] <> 0.0 Or fCircleYTemp[iLoop] <> 0.0 Then
               TransformCoord(fCircleXTemp[iLoop], fCircleYTemp[iLoop], fParAngle)
            End If
         Next
         fAngle = fParAngle
      End If
      
      fX = fParX
      fY = fParY
      
      Return True
   End Method
   
   Method CollidedWith:Byte(cspParShape:ColShape)
      Local iLoop:Int
      Local iLoop2:Int
      Local iMaxDistTemp:Int
      
      For iLoop = 0 To iCircleNum[iType] - 1
         For iLoop2 = 0 To iCircleNum[cspParShape.iType] - 1
            iMaxDistTemp = (iCircleRadius[iType][iLoop] + iCircleRadius[cspParShape.iType][iLoop2])
            If Abs((fX + fCircleXTemp[iLoop]) - (cspParShape.fX + cspParShape.fCircleXTemp[iLoop2])) < iMaxDistTemp And Abs((fY + fCircleYTemp[iLoop]) - (cspParShape.fY + cspParShape.fCircleYTemp[iLoop2])) < iMaxDistTemp Then
               If DistanceQuad((fX + fCircleXTemp[iLoop]), (fY + fCircleYTemp[iLoop]), (cspParShape.fX + cspParShape.fCircleXTemp[iLoop2]), (cspParShape.fY + cspParShape.fCircleYTemp[iLoop2])) < (iMaxDistTemp * iMaxDistTemp) Then
                  Return True
               End If
            End If
         Next
      Next
      
      Return False
   End Method
   
   'Wie CollidedWith, liefert aber im Fall einer Kollision noch Kollisionspunkt und resultierenden Vektor zurück.
   Method CollidedWith2:Byte(cspParShape:ColShape, fVarColX:Float[] Var, fVarColY:Float[] Var, fVarResXVec:Float Var, fVarResYVec:Float Var)
      Local iLoop:Int
      Local iLoop2:Int
      Local iMaxDistTemp:Int
      Local fDistTemp:Float
      Local bCollision:Byte
      Local fXDif:Float
      Local fYDif:Float
      
      fVarResXVec = 0.0
      fVarResYVec = 0.0
      fVarColX = New Float[0]
      fVarColY = New Float[0]
      
      For iLoop = 0 To iCircleNum[iType] - 1
         For iLoop2 = 0 To iCircleNum[cspParShape.iType] - 1
            iMaxDistTemp = (iCircleRadius[iType][iLoop] + iCircleRadius[cspParShape.iType][iLoop2])
            fXDif = ((cspParShape.fX + cspParShape.fCircleXTemp[iLoop2]) - (fX + fCircleXTemp[iLoop]))
            fYDif = ((cspParShape.fY + cspParShape.fCircleYTemp[iLoop2]) - (fY + fCircleYTemp[iLoop]))
            If Abs(fXDif) < iMaxDistTemp And Abs(fYDif) < iMaxDistTemp Then
               fDistTemp = (fXDif * fXDif) + (fYDif * fYDif)
               If fDistTemp < (iMaxDistTemp * iMaxDistTemp) Then
                  fDistTemp = Sqr(fDistTemp)
                  
                  fVarResXVec:+ (fXDif / fDistTemp) * -(iMaxDistTemp - fDistTemp)
                  fVarResYVec:+ (fYDif / fDistTemp) * -(iMaxDistTemp - fDistTemp)
                  
                  fVarColX = fVarColX[..fVarColX.length + 1]
                  fVarColY = fVarColY[..fVarColY.length + 1]
                  fVarColX[fVarColX.length - 1] = fCircleXTemp[iLoop] + (fXDif / fDistTemp) * (Float(iCircleRadius[iType][iLoop]) - ((iMaxDistTemp - fDistTemp) / 2.0))
                  fVarColY[fVarColY.length - 1] = fCircleYTemp[iLoop] + (fYDif / fDistTemp) * (Float(iCircleRadius[iType][iLoop]) - ((iMaxDistTemp - fDistTemp) / 2.0))
                  
                  bCollision = True
               End If
            End If
         Next
      Next
      
      Return bCollision
   End Method
   
   
   Function Create:ColShape(iParType:Int)
      Local cspTemp:ColShape = New ColShape
      
      cspTemp.iType = iParType
      cspTemp.fCircleXTemp = cspTemp.fCircleXTemp[..iCircleNum[iParType]]
      cspTemp.fCircleYTemp = cspTemp.fCircleYTemp[..iCircleNum[iParType]]
      
      Return cspTemp
   End Function
   
   'Setzt die Anzahl der CollisionShapes auf den angegebenen Wert. Bei einer Erhöhung bleiben die vorherigen erhalten, wenn bParClear = False
   Function RedefineTypes:Byte(iParNewTypeNum:Int, bParClear:Byte = False)
      If bParClear = True Then
         RedefineTypes(0)
      End If
      
      iCount = iParNewTypeNum
      sID = sID[..iParNewTypeNum]
      iCircleNum = iCircleNum[..iParNewTypeNum]
      iCircleX = iCircleX[..iParNewTypeNum]
      iCircleY = iCircleY[..iParNewTypeNum]
      iCircleRadius = iCircleRadius[..iParNewTypeNum]
      
      Return True
   End Function
   
   Function RedefineCircleTypes:Byte(iParType:Int, iParNewNum:Int)
      Local iLoop:Int
      Local iLoop2:Int
      Local iOldNum:Int = iCircleX[iParType].length
      
      iCircleX[iParType] = iCircleX[iParType][..iParNewNum]
      iCircleY[iParType] = iCircleY[iParType][..iParNewNum]
      iCircleRadius[iParType] = iCircleRadius[iParType][..iParNewNum]
      
      For iLoop = iOldNum To iParNewNum - 1
         'Hier eventuelle Standartwerte festlegen
      Next
      
      Return True
   End Function
   
   Function ID2Type:Int(sParID:String)
      If iCount = 0 Then Return 0
      Local iLoop:Int
      For iLoop = 0 To (iCount - 1)
         If sID[iLoop] = sParID Then Return iLoop
      Next
      Return Int(sParID)
   End Function
   
   Function ValidID:Byte(sParID:String)
      If iCount = 0 Then Return False
      Local iLoop:Int
      For iLoop = 0 To (iCount - 1)
         If sID[iLoop] = sParID Then Return True
      Next
      Return False
   End Function
End Type


'Gibt die Entfernung zwischen den beiden angegebenen Punkten zurück, ohne vorher die Wurzel zu ziehen. Ein bischen schneller, dafür nicht für alles geeignet.
Function DistanceQuad:Float(fParX1:Float, fParY1:Float, fParX2:Float = 0, fParY2:Float = 0)
   Return ((fParX1 - fParX2) * (fParX1 - fParX2) + (fParY1 - fParY2) * (fParY1 - fParY2))
End Function

'Dreht und Skaliert die angegebenen Koordinaten im angegebenen Winkel um eine Mitte.
Function TransformCoord:Byte(fVarX:Float Var, fVarY:Float Var, fAngle:Float, fParCenterX:Float = 0.0, fParCenterY:Float = 0.0, fScale:Float = 1.0)
   Local fTempAngle:Float = Angle(fParCenterX, fParCenterY, fVarX, fVarY) + fAngle
   Local fTempDist:Float = Distance(fVarX, fVarY, fParCenterX, fParCenterY) * fScale
   fVarX = fParCenterX + Sin(fTempAngle) * fTempDist
   fVarY = fParCenterY - Cos(fTempAngle) * fTempDist
   Return True
End Function

'Liefert den Winkel von Punkt 2 zu Punkt 1 zurück.
'Beispiel: Punkt 1 liegt bei 0,0, Punkt 2 bei 10,0
'Dann wird der Winkel 90 zurückgeliefert.
Function Angle:Float(fX1:Float, fY1:Float, fX2:Float, fY2:Float)
   Return (ATan2(fY2 - fY1, fX2 - fX1) + 450.0) Mod 360.0
End Function

'Gibt die Entfernung zwischen den beiden angegebenen Punkten zurück.
Function Distance:Float(fParX1:Float, fParY1:Float, fParX2:Float = 0, fParY2:Float = 0)
   Return Sqr((fParX1 - fParX2) * (fParX1 - fParX2) + (fParY1 - fParY2) * (fParY1 - fParY2))
End Function


Hier mal ein Verwedungsbeispiel:
Code: [AUSKLAPPEN]

'#### ColShap-Typ erstellen: ####
'Gesamte Typanzahl auf 1 erhöhen. Bei Erhöhung bleiben vorherige ColShapes erhalten.
ColShape.RedefineTypes(1)
'Maximalanzahl der Radien für Typ 0 (Typennummerierung beginnt bei 0) auf 2 setzen
ColShape.RedefineCircleTypes(0, 2)
'Werte für Kollisionsform Typ 0 festlegen:
ColShape.sID[0] = "TESTCOLLISION" 'ID des ColShape-Typs 0
ColShape.iCircleNum[0] = 2 'Anzahl der Radien auf 2 setzen.
'RADIUS 0
ColShape.iCircleX[0][0] = -3 'X-Position des Radienmittelpunkts relativ zum Mittelpunkt des ColShapes
ColShape.iCircleY[0][0] = 0 'Y-Position "  "  "
ColShape.iCircleRadius[0][0] = 5 'Radius
'RADIUS 1
ColShape.iCircleX[0][1] = 3 'X-Position des Radienmittelpunkts relativ zum Mittelpunkt des ColShapes
ColShape.iCircleY[0][1] = 0 'Y-Position "  "  "
ColShape.iCircleRadius[0][1] = 7 'Radius

'#### ColShape des Typs 0 erstellen ####
Global cspTemp:ColShape = ColShape.Create(ColShape.ID2Type("TESTCOLLISION")) 'Oder alternativ statt ID2Type direkt die Typnummer eingeben

'#### ColShape benutzen ####
'cspTemp.Update(fXPos, fYPos, fAngle) '<- Setzt Position und Winkel des ColShapes neu.
'cspTemp.Draw(fXCam, fYCam) '<- fXCam und fYCam sind optional. Sie werden beim zeichnen zur Position des ColShapes dazuaddiert.
'cspTemp.CollidedWith(cspAnotherColShape) '<- True oder False. Kollidiert oder nicht.
'cspTemp.CollidedWith2(cspAnotherColShape, fVarColX[], fVarColY[], fVarResVecX, fVarResVecY) '<- Genau wie CollidedWith, liefert aber Kollisionspunkte und resultierenden Vektor zurück.


Hoffe, das hilft vielleicht dem ein oder anderen ^^

Fetze

BeitragSo, März 26, 2006 11:46
Antworten mit Zitat
Benutzer-Profile anzeigen
Hatte eine Function vergessen, ist aber nun hinzugefügt. Sollte also jetzt funktionieren ^^

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group