Seite 1 von 2

Kugelkolision

Verfasst: 14.12.2006 17:16
von sen-me
Hi, ich habe ein Kugelkolisionserkennung im Code-Archiv schon gefunden, aber die hat nur was mit Maus und Bildschirmrand zu tun, was ist wenn aber wo ein Hinderniss ist?
Und wie frag ich ab welches Hinderniss er berührt hat (Wie bei Pinball z.B. es ja verschiedene Sachen gibt die verschiedene Punkte bringen)

Verfasst: 14.12.2006 18:42
von #NULL
kreis-kreis-kollision ist einfach. ich habs mal in eine procedure aufgetrieselt damit man es besser lesen kann.
hab mich auch grad an kreis-rechteck versucht. komme aber nicht auf simple lösungen.

Code: Alles auswählen

InitSprite()
hWin=OpenWindow(0, 50,50,600,600, "")
OpenWindowedScreen( hWin, 0,0,600,600, 0,0,0)




Structure circleS
  x.l
  y.l
  r.l
EndStructure
NewList c.circleS()

AddElement( c() )
c()\x=Random(500)+50
c()\y=Random(500)+50
c()\r=Random(20)+20

AddElement( c() )
c()\x=Random(500)+50
c()\y=Random(500)+50
c()\r=Random(20)+20

AddElement( c() )
c()\x=Random(500)+50
c()\y=Random(500)+50
c()\r=Random(20)+20



Procedure collCircCirc( x1,y1,r1, x2,y2,r2 )
  dx= x1-x2
  dy= y1-y2
  distance= Sqr( dx*dx + dy*dy )
  If distance < r1+r2
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure



;MOUSE
m.circleS
m\r=50

Repeat
  m\x=WindowMouseX(0)
  m\y=WindowMouseY(0)
  m\r+Random(2)-1

  StartDrawing( ScreenOutput() )
    coll=0
    ForEach c()
      If collCircCirc( m\x, m\y, m\r,  c()\x, c()\y, c()\r ) 
        DrawingMode(#PB_2DDrawing_Outlined)
        coll=1
      Else
        DrawingMode(#PB_2DDrawing_Default)
      EndIf
      Circle( c()\x, c()\y, c()\r )
    Next

    If coll
      DrawingMode(#PB_2DDrawing_Outlined)
    Else
      DrawingMode(#PB_2DDrawing_Default)
    EndIf
    Circle( m\x, m\y, m\r)
    
  StopDrawing()

  
  event=WindowEvent()
  Select event
    Case #PB_Event_CloseWindow
      quit=1
  EndSelect
  FlipBuffers()
  ClearScreen($333333)
Until quit

Verfasst: 14.12.2006 18:58
von Kaeru Gaman
bei kreis-rechteck würde ich zu beginn eine fallunterscheidung machen,
in welchem der 9 möglichen quadranten der kreismittelpunkt liegt,
dann weiß ich, mit welchen eckpunkten ich wie vergleichen muss.

@sen-me

meintest du denn überhaupt kreis-kollisionen?
...weil du kugel-kollision geschrieben hattest...

Verfasst: 14.12.2006 19:43
von sen-me
Ich hab ne Kugel(die als quadrat fungiert), die fliegt rum, und trift nur auf rechtecke/quadrate

Verfasst: 14.12.2006 19:58
von Kaeru Gaman
also dochn kreis... kugel is 3D...

mit den segmenten meinte ich das so:

Code: Alles auswählen

     |     |     
  1  |  2  |  3  
     |     |     
-----+-----+-----
     |     |     
  4  |  5  |  6  
     |     |     
-----+-----+-----
     |     |     
  7  |  8  |  9  
     |     |     
segment 5 entspricht der position des rechtecks.

je nachdem, in welchem segment sich der mittelpunkt des kreises befindet,
muss man nun unterschiedliche koordinaten-checks vornehmen.

Kx,Ky seien die koordinaten des kreismittelpunktes und R der radius.

in segment 1 z.b. macht man einen kreis-punkt-kollisionscheck für den Punkt x1,y1

Code: Alles auswählen

dx = Kx -x1
dy = Ky -y1
distq = dx*dx+dy*dy
If distq < R*R
   Collsision()
für segment 2 überprüft man lediglich, ob der kreismittelpunkt weit genug oben liegt

Code: Alles auswählen

If Ky > y1 - R
  Collision()
für die anderen segmente funktioniert es analog.


in welchem segment sich der kreis befindet, ist auch einfach zu ermitteln:

Code: Alles auswählen

Segment = 5
If Kx < x1
  Segment -1
ElseIf Kx > x2
  Segment +1
EndIf
If Ky < y1
  Segment -3
ElseIf Ky > y2
  Segment +3
EndIf
und danach die fälle per Select/Case trennen...

Verfasst: 14.12.2006 20:21
von sen-me
Öhm oookayy? ^^
Nix verstanden aber aufwenig erklärt ^^

Was sind segmente?

Nochmal:

Code: Alles auswählen

     |     |
  A  |  B  |  C
     |     |
-----+-----+-----
     |     |
  D  |  E  |  F
     |     |
-----+-----+-----
     |     |
  G  |  H  |  I
     |     |
Sagen wir in E ist der Kreis (er wird als Quadrat(10*10) gerechnet)
in A und C sind jedweils ein Quadrat (16*16)
In H befindet sich ein Rechteck (75*16)
Wir nehmen an, der Kreis würde sich auf A zubewegen, und dann nach C abprallen und wiederum nach H und dort abprallen.

Ich will nun wissen

1. Wie sich die Kugeln bewegen soll (Bewegung+Abprallen)
2. Ob er A, C, den Bildschirmrand oder sonst was berührt hat (also weiß auf was er kollidiert ist und dann zurückgibt z.B. A)
3. Wie er weiß (selbsständig) ob dort etwas zum abprallen ist (weil manche sachen bewegen sich wie z.B. H)

Dies hab ich aus dem Code-Archiv: (nur etwas umgeändert damit es auf PB4 geht)

Code: Alles auswählen

Global Dim diff_Kollision.w(3)
Global BallX.w : BallX = 10
Global BallY.w : BallY = 10
Global BallRateY.w : BallRateY = 4  ; Ball-Geschwindigkeit in Y-Richtung
Global BallRateX.w : BallRateX = 6  ; Ball-Geschwindigkeit in X-Richtung
Global BallDirY.w : BallDirY = -1   ; Y-Richtung
Global BallDirX.w : BallDirX = 1    ; X-Richtung
Global BallRadius.w : BallRadius = 10 ; Ball-Radius   ist in Wirklichkeit ein Rechteck ;)
Global BlockXL.w  ; Linke X-Kante des Blocks
Global BlockXR.w  ; Rechte X-Kante des Blocks
Global BlockYT.w  ; Obere Y-Kante des Blocks
Global BlockYB.w  ; Untere Y-Kante des Blocks
Procedure Ball_Block_Kollision()
  Shared BlockXL , BlockXR , BlockYT , BlockYB
  Shared BallX , BallY , BallDirX , BallDirY
  If BallX >= BlockXL-BallRadius And BallX <= BlockXR+BallRadius And BallY >= BlockYT-BallRadius And BallY <= BlockYB+BallRadius
    diff_XL=BallX-BlockXL : diff_XR=BlockXR-BallX : diff_YT=BallY-BlockYT : diff_YB=BlockYB-BallY
    diff_Kollision(0)=diff_XL : diff_Kollision(1)=diff_XR : diff_Kollision(2)=diff_YT : diff_Kollision(3)=diff_YB
    SortArray(diff_Kollision(),0)
    If diff_XL = diff_Kollision(0)
      BallDirX = -1
    ElseIf diff_XR = diff_Kollision(0)
      BallDirX = 1
    ElseIf diff_YT = diff_Kollision(0)
      BallDirY = -1
    ElseIf diff_YB = diff_Kollision(0)
      BallDirY = 1
    EndIf
  EndIf
EndProcedure
InitSprite() : InitKeyboard() : InitMouse() : OpenScreen(640,480,16,"Ball") : SetFrameRate(60)
CreateSprite(1,20,20,#PB_Sprite_Texture) : TransparentSpriteColor(1,$000000)
StartDrawing(SpriteOutput(1))
Box(0,0,20,20,RGB(0,0,0))
Circle(10,10,10,RGB(255,0,0))
StopDrawing()
CreateSprite(2,40,40,0)
StartDrawing(SpriteOutput(2))
Box(0,0,40,40,RGB(0,0,0))
StopDrawing()
MouseLocate(300,300)
Repeat
  ExamineKeyboard()
  ExamineMouse()
  ; Block positionieren
  BlockXL = MouseX()-20
  BlockXR = MouseX()+20
  BlockYT = MouseY()-20
  BlockYB = MouseY()+20
  ; Ball-Bewegung
  BallX = Int(BallX + BallRateX * BallDirX)
  BallY = Int(BallY + BallRateY * BallDirY)
  ; Ball-Screen Kollision
  If BallY <= 0
    BallDirY = 1
  EndIf
  If BallY >= 480
    BallDirY = -1
  EndIf
  If BallX <= 0
    BallDirX = 1
  EndIf
  If BallX >= 640
    BallDirX = -1
  EndIf
  ; Ball-Block Kollision
  Ball_Block_Kollision()
  
  ClearScreen(RGB(100,100,100))
  DisplayTransparentSprite(1,BallX-BallRadius,BallY-BallRadius)
  DisplaySprite(2,BlockXL,BlockYT)
  FlipBuffers()
Until KeyboardPushed(1)
CloseScreen()

Verfasst: 14.12.2006 20:29
von Kaeru Gaman
nein. das mittlere segment ist das rechteck.

so eine proc gibt NUR zurück, ob eine kollision stattgefunden hat oder nicht.

ich hab sie so wie bisher angedacht mal ausgeführt:
http://www.purebasic.fr/german/viewtopi ... 234#129234


die ermittlung, in welche richtung wie abgeprallt werden müsste, bedarf weiterer überlegungen.

> Wie er weiß (selbsständig) ob dort etwas zum abprallen ist (weil manche sachen bewegen sich wie z.B. H)
selbständig weiß ein computer nix... ;)

das musst du alles einzeln programmieren...


> Dies hab ich aus dem Code-Archiv:
ähm.. im Code-Archiv ist aber zumindest nen kommentar dabei, was der code eigentlich tut...

Verfasst: 14.12.2006 23:10
von sen-me
Schon klar was es tut.. aber ist nur Maus+Bildschirmrand, würde er von Objekten noch irgendwo abprallen und wissen an welchen Objekten er abgeprallt ist wäre das echt n1

Verfasst: 14.12.2006 23:44
von #NULL
hier noch eine etwas andere version. die 9 fälle werden zusammengefaßt/verallgemeinert. kann sein dass es lansgamer ist, weiß ich aber nicht.

Code: Alles auswählen

Procedure collCircRect(cx,cy,cr, x1,y1,x2,y2)

  If x1>x2
    Swap x1,x2
  EndIf
  If y1>y2
    Swap y1,y2
  EndIf
  
  mx= (x1+x2)/2
  my= (y1+y2)/2
  
  dx= cx-mx
  If dx<0 :: dx*-1 :: EndIf
  dy= cy-my
  If dy<0 :: dy*-1 :: EndIf

  If mx+dx-cr > x2
    ProcedureReturn #False
  ElseIf my+dy-cr > y2
    ProcedureReturn #False
  Else
    dx- (mx-x1)
    dy- (my-y1)
    If dx>0 And dy>0 And dx*dx+dy*dy > cr*cr
      ProcedureReturn #False
    EndIf
  EndIf
  
  ProcedureReturn #True
EndProcedure

Verfasst: 15.12.2006 00:18
von Kaeru Gaman
sen-me hat geschrieben:Schon klar was es tut..
yo, mir aber nicht.... ;)


das abprallen von objekten wäre im endeffekt das einzige, was du brauchst...

auch deine maus wird im endeffekt ein objekt steuern,
und auch den bildrand könntest du als objekte definieren.

also bräuchtest du ein-e objekt-liste/-array,
und die kannst du mit einer schleife durchgehen, und auf kollisionen checken,
(irgendwie optimieren, dass nicht immer sämtliche objekte gecheckt werden müssen...)
bei jedem objekt wird dann entschieden, ob es auf circle-box oder auf circle-circle kollision geprüft wird.
und die kollisionsroutine könnte auch gleich den abprallwinkel zurückliefern,
dafür müsste sie dann dementsprechend etwas komplexer gestaltet werden...

aber das wäre dann schon das grundgerüst für einen flipper....