Seite 1 von 3

Kollisionen [ehem. "Spiegeln?"]

Verfasst: 16.12.2006 13:45
von Janiboy
Hallo zusammen,
kann sein, dass es das Thema schon gibt, aber ich konnte nichts Brauchbares finden. Ich habe mit einem Code eine Figur erstellt, die nach rechts läuft, nun soll sie auch nach links laufen, dazu muss sie sich ja aber "umdrehen", wie kann ich die 4 sprites der animation "spiegeln", damit er auch in die richtige richtung läuft?

Gruß,
Janiboy

Verfasst: 16.12.2006 14:54
von Kaeru Gaman
normalerweise macht man das vor der programmausführung,
und lädt eben eine extra-animation für jede laufrichtung.

sogar PAINT hat eine funktion "Horizontal spiegeln"

Verfasst: 16.12.2006 15:00
von Janiboy
Tatsächlich, nie gesehen diese Funktion :) .
Hätte aber noch ne Frage zur Kollision, auch wenns jetzt net unter die Überschrift passt: Ich will, dass ein Felsen, wenn die Figur ihn berührt, losrollt, kann jemand mal einen Beispielausschnitt für eine Kollisionsabfrage posten, alles bisher gefundene is mir zu undurchsichtig :) .

Gruß,
Janiboy

Verfasst: 16.12.2006 15:06
von Kaeru Gaman
http://www.purebasic.fr/german/viewtopic.php?t=9093

verschiedene koordinaten-basierte kollisionsroutinen.
so schwierig ist das garnicht, ist recht einfache mathematik.
lass dich von der kreis-kollision nicht gleich abschrecken,
dafür braucht man halt nen pythagoras....
du kannst auch dort nochmal nachfragen, ich erklärs gerne noch etwas ausführlicher.

man kann auch den PB-Befehl SpriteCollision() verwenden.
der überprüft auch, ob die rechteckigen bereiche von zwei sprites sich überlappen.
aber da der recht unflexibel ist und nicht der schnellste,
schreibe ich die abfragen lieber selbst....

Verfasst: 16.12.2006 15:22
von Janiboy
Holla... sieht komplex aus :) . aber meiner compiled das irgendwie nicht, hmm... Wie sähe das ganze denn mit spritecollision() aus, ich glaube is doch etwas kürzer oder? Ich möchte nämlich nichts in meinen code kopieren, von dem ich im endeffekt nix versteh`:D .

Irgendjemand hatte mir auch mal sowas gesagt:

Code: Alles auswählen

If SpritePixelCollision(12, 10, 5,14, 10, 5) 
    maxrange=12
    minrange=8
    move=1 
    EndIf
Aber das macht das Programm unglaublich langsam und es reagiert kaum noch.

Gruß,
Janiboy

Verfasst: 16.12.2006 15:32
von Kaeru Gaman
> aber meiner compiled das irgendwie nicht, hmm...

öh... das sind auch reine prozeduren, ohne hauptprogramm...

> Wie sähe das ganze denn mit spritecollision() aus, ich glaube is doch etwas kürzer oder?
nur der befehl selber. natürlich kannst du das verwenden, aber später könnte sich das als unpraktisch erweisen.

> Ich möchte nämlich nichts in meinen code kopieren, von dem ich im endeffekt nix versteh`
sehr löblich :allright:

aber wie gesagt, ich erklärs gerne nochmal ausführlich.

können wir auch gerne in diesem thread machen, da bisher keiner an ihm interesse gezeigt hat.


für einen kollisionscheck, der einem SpriteCollision() entspricht, brauchst du nur die routine für die einfache box-kollision:
StdColl(x1,y1,a1,b1,x2,y2,a2,b2)
die Standard-Collision, funktioniert genauso wie SpriteCollision(), nur dass hier keine SpriteNummer angegeben wird, sondern Höhe und Breite des Objekts.
dadurch spart sie funktionsaufrufe, und ist außerdem auch für mittels DirectDraw gezeichnete Objekte verwendbar (z.b. Box() )
ich nenn die Proc mal anders...

Code: Alles auswählen

Procedure KG_SpriteCollision(x1,y1,a1,b1,x2,y2,a2,b2) 
  Coll = #False 
  
  If x1 < x2 
    dx = x2 - (x1 + a1) 
  Else 
    dx = x1 - (x2 + a2) 
  EndIf 
  If y1 < y2 
    dy = y2 - (y1 + b1) 
  Else 
    dy = y1 - (y2 + b2) 
  EndIf 
  
  If dx < 0 And dy < 0 
    Coll = #True 
  EndIf 
  
  ProcedureReturn Coll 

EndProcedure 
das kannst du (fast) genauso verwenden, wie den Befehl SpriteCollision.

PS:
...du hast editiert...

ja, von SpritePixelCollision rate ich grundsätzlich ab,
weil es für die meisten problemstellung absolut unnötiger aufwand ist,
jedes einzelne pixel von beiden sprites zu überprüfen.

man kann durch variation der koordinaten-überprüfung für
jede problemstellung den passenden check erstellen.

Verfasst: 16.12.2006 15:55
von Janiboy
ok, jetzt muss ich nurnoch versuchen, die ganzen variablen zu verstehen :) , naja, wird schon klappen. Aber wo kommt dann eigentlich der befehl für das "ergebnis" der kollision hin, also z.B. dass etwas animiert wird oder ein sprite sich ändert?

Gruß,
Janiboy

Verfasst: 16.12.2006 16:23
von Kaeru Gaman
ich hab dir mal ne kleine demo geschrieben.

die kollisionsabfrage steht hier nur deshalb innerhalb eines Drawing-Blocks,
weil ich mit einer draw-ausgabe reagiere...

da du ja oft aufgrund einer kollision einen vorgang starten willst,
sähe das ganze dann noch ein bissel anders aus...

aber hier erst mal soweit der beispielcode:

Code: Alles auswählen

InitSprite()
InitKeyboard()
OpenScreen(800,600,32,"Coll-Demo")

Procedure KG_SpriteCollision(x1,y1,a1,b1,x2,y2,a2,b2) 
  Coll = #False 
  
  If x1 < x2 
    dx = x2 - (x1 + a1) 
  Else 
    dx = x1 - (x2 + a2) 
  EndIf 
  If y1 < y2 
    dy = y2 - (y1 + b1) 
  Else 
    dy = y1 - (y2 + b2) 
  EndIf 
  
  If dx < 0 And dy < 0 
    Coll = #True 
  EndIf 
  
  ProcedureReturn Coll 

EndProcedure 

; Starting Positions
Box1_XPos = 100
Box1_YPos = 100
Box1_Width = 60
Box1_Height = 40

Box2_XPos = 600
Box2_YPos = 400
Box2_Width = 80
Box2_Height = 30

; optional
SetFrameRate(60)

;*** MainLoop***
Repeat
  ExamineKeyboard()
  ClearScreen($402010)

  ; Keyboard Box1: W-A-S-D ; Box2: Cursor
  If KeyboardPushed(#PB_Key_A)
    Box1_XPos -2
  EndIf
  If KeyboardPushed(#PB_Key_D)
    Box1_XPos +2
  EndIf
  If KeyboardPushed(#PB_Key_W)
    Box1_YPos -2
  EndIf
  If KeyboardPushed(#PB_Key_S)
    Box1_YPos +2
  EndIf
  If KeyboardPushed(#PB_Key_Left)
    Box2_XPos -2
  EndIf
  If KeyboardPushed(#PB_Key_Right)
    Box2_XPos +2
  EndIf
  If KeyboardPushed(#PB_Key_Up)
    Box2_YPos -2
  EndIf
  If KeyboardPushed(#PB_Key_Down)
    Box2_YPos +2
  EndIf

  StartDrawing(ScreenOutput())
    ;** Box1
    Box(Box1_XPos, Box1_YPos, Box1_Width, Box1_Height,$8040FF)
    ;** Box2
    Box(Box2_XPos, Box2_YPos, Box2_Width, Box2_Height,$FF8040)
  
    ;****** Collision ******
    If KG_SpriteCollision( Box1_XPos, Box1_YPos, Box1_Width, Box1_Height, Box2_XPos, Box2_YPos, Box2_Width, Box2_Height )
      DrawText(370,0," KOLLISION ",$00FFFF,$FF0000)
    EndIf
  StopDrawing()

  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)

Verfasst: 16.12.2006 16:40
von Janiboy
Den Drawing-Effekt kann ich mir ja mit hineingeladenen Sprites sparen, aber da ich ja Sprites hab, müssen ja bei

Code: Alles auswählen

If KG_SpriteCollision( Box1_XPos, Box1_YPos, Box1_Width, Box1_Height, Box2_XPos, Box2_YPos, Box2_Width, Box2_Height ) 
      DrawText(370,0," KOLLISION ",$00FFFF,$FF0000) 
    EndIf 
in die spritecollisionsklammer andere Werte, nicht? Was genau sind das für Werte?

Gruß,
Janiboy

P.S.: Sorry, wenn ich manchmal wenig versteh`, ich hoffe das nervt nicht zu sehr :) .

Verfasst: 16.12.2006 16:56
von Kaeru Gaman
nunja... eben die position und die höhe und breite von deinem sprite...

ich dachte, das würde anhand der verwendeten namen deutlich,
deswegen hab ich extra ne Box genommen, damit man auch was sieht...

änder das mal für sprites:

Code: Alles auswählen

LoadSprite(1,"....") ; <- dein erstes sprite
LoadSprite(2,"....") ; <- dein zweites sprite

Sprite1_XPos = 100
Sprite1_YPos = 100
Sprite1_Width = SpriteWidth(1)
Sprite1_Height = SpriteHeight(1)

Sprite2_XPos = 600
Sprite2_YPos = 400
Sprite2_Width = SpriteWidth(1)
Sprite2_Height = SpriteHeight(1)
also, deine sprites laden, und die startwerte einstellen.
die position wird wieder willkürlich gesetzt, höhe und breite wird ermittelt.

dann änderst du in der tastaturabfrage die variablennamen von Box... auf Sprite...
das ist nnur kosmetisch, damit es besser aussieht.
es sind nur variablennamen, man könnte das auch auch Box lassen oder Hinz und Kunz nennen....
aber die namen müssen halt übereinstimmen.

im draw-bereich ersetzt du eben die Box-Befehle durch

Code: Alles auswählen

DisplaySprite( 1, Sprite1_XPos, Sprite1_YPos )
(auch fürs zweite)

und in die kollisionsabfrage kommen eben auch die neuen variablennamen...