Max2D Kollision Teil 2
Max2D Kollision Teil 2
(c) Assari 2006
Ins Deutsche übersetzt von simi
Wir haben im vorherigen Tutorial gesehen, wie man mit unseren Funktionen RectOverlaps und CircRectOverlaps Kollisionen erkennen kann. Wir haben weiter die Pixel-Kollisionsbefehle ImagsCollide und ImagesCollide2 kennen gelernt.
In diesem Tutorial werden wir 2 weiter Max2D-Kollisionfunktionen anschauen, die eine andere Technik als die vorherigen verwenden.
CollideImage
Lass uns anhand dem Skalierungsproblem, das wir schon früher gesehen haben, die neuen Funktionen kennen lernen und sehen, wie man die neue Technik benutzt. Die Syntax von CollideImage kann Verwirrung stiften. Unten siehst du sie, aber ignoriere sie für eine Minute und schau dir die Änderungen an, die wir gemacht haben, um die Kollision mit der CollideImage-Funktion hinzukriegen.
Function CollideImage:Object[](image:TImage,x,y,frame,collidemask%,writemask%,id:Object=Null) |
Beachte die hervorgehobenen Änderungen (wie immer ist der graue Text unverändert vom vorherigen Tutorial übernommen)
Graphics 640,480 Local URL:String="http::www.hanfgebiet.de/" Local Player:TImage=LoadImage(LoadBank(URL+"blobship_1-1.png")) Local Alien:TImage=LoadAnimImage(LoadBank(URL+"exp1.png"),64,64,0,16) Local Frame:Int=0 Local AnimDelay:int=10 Local PlayerSize:Int=1 Local AlienSize:Int=2 While Not KeyHit(key_escape) Or AppTerminate() Cls ResetCollisions() SetScale AlienSize,AlienSize DrawImage Alien,150,100,Frame CollideImage(Alien,150,100,Frame,0,2) SetScale PlayerSize,PlayerSize DrawImage Player,MouseX(),MouseY() If CollideImage(Player,MouseX(),MouseY(),0,2,0) SetClsColor 255,0,0 Else SetClsColor 0,0,0 EndIf Flip If AnimDelay<0 Then Frame :+ 1 If Frame>15 Then Frame=0 AnimDelay=10 EndIf AnimDelay :- 1 Wend End |
Wenn du den obigen Code ausführst, wirst du sehen, dass die Kollision genau gleich wie im vorherigen Tutorial erkennt wird.
Dieses neue BlitzMax-Kollisionssystem führt das Konzept von Kollisionlayer ein. Die Schritte, um die Kollisionsabfrage zu verwenden, wären wie folgt:
- zuerst muss man sich versichern, dass der Kollisionslayer leer ist
- füge dem Kollisionslayer das Bild hinzu, das du auf Kollision überprüfen willst
- vergleiche das Bild, mit welchem du die Kollision mit dem in den Kollisionlayer geschriebenen Bild, überprüfen willst
Es gibt 32 Kollisionslayer, die wir benutzen können. Im obigen Beispiel benutzen wir den Kollisionslayer #1.
Im obigen Programm werden die 3 Schritte wie folgt abgearbeitet:
ResetCollisions() löscht alle Kollisionslayer. Wir hätten auch ResetCollisions(2) benutzen können, um nur Layer #2 zu löschen.
ResetCollisions() |
Der erste CollideImage-Aufruf schreibt das Alien-Bild in den Kollisionslayer 2.
CollideImage(Alien,150,100,Frame,0,2) |
Dieser CollideImage-Aufruf liest vom Kollisionslayer 2 und überprüft die Kollision zwischen dem Player- und dem Alien-Image.
If CollideImage(Player,MouseX(),MouseY(),0,2,0) |
Folgendes hat Mark Sibly, der Ersteller von BlitzMax, über Layer gesagt (natürlich in Englisch, aber ich habs übersetzt ):
Die Grundidee ist, dass der CollideMask- und WriteMask-Parameter Bitmasken sind (z.B.: 1,2,3,8,16 etc). Das ergibt 32 "Layers" um darauf zu schreiben oder damit zu kollidieren. Zum Beispiel könntest du folgende Layers benutzen: Hintergrund=0, Monster=1, Pickups=2, Spieler=3. Die Bitmasken dazu wären dann 1,2,4 und 8 (Bitmaske = 1 Shl Layer). Das Benutzen von Bitmasken anstelle von Layernummern erlaubt es, mehrere Layer zu benutzen, z.B. Bitmaske 3 bedeutet Layer 0 und 1. CollideImage schreibt ein Bild zu 0-32 Layers (abhängig von der WriteMask) und überprüft die Kollision mit 0-32 Layers (abhängig von der CollideMask). Beim "schreiben eines Bildes" wird intern das Bild, und jetzige Rotation und Skalierung gespeichert. |
Mark hat über die CollideMask- und WriteMask-Parameter gesprochen:
Function CollideImage:Object[](image:TImage,x,y,frame,collidemask%,writemask%,id:Object=Null) |
Um ein Bild auf den Kollisionslayer 1 zu schreiben, müssen wir den writemask-Parameter wie folgt benutzen:
CollideImage(Alien,150,100,Frame,0,1) |
Wir können auch auf beide Kollisionslayer 1 und 2 wie folgt schreiben:
CollideImage(Alien,150,100,Frame,0,3) |
Um auf eine Kollision zu überprüfen, müssen wir den CollideMask-Paramter benutzen:
If CollideImage(Player,MouseX(),MouseY(),0,1,0) |
Wenn wir Kollision auf 2 Layern überprüfen wollen, benutzen wir:
If CollideImage(Player,MouseX(),MouseY(),0,3,0) |
Das gute an den Kollisionslayern ist, dass man die Kollision nur gegen die Layer, die etwas ausmachen, überprüfen kann. Bevor wir ein einfaches Beispiel anschauen, lass uns ein anderes Konzept anschauen:
Bis jetzt haben wir überprüft ob CollideImage true zurückliefert. Wenn dies der Fall ist, hat eine Kollision stattgefunden.
Aber die CollideImage-Funktion hat einen viel mächtigeren Weg um die Kollisionsprüfung anzuwenden. Wir werden und jetzt das Geheimnis vom Object[] und id:Object Teil der CollideImage-Syntax anschauen.
Function CollideImage:Object[](image:TImage,x,y,frame,collidemask%,writemask%,id:Object=Null) |
Beachte dass wir in der Einführung oben erfahren haben, dass es zwei Versionen von CollideImage gibt:
- Die Schreibfunktion mit writemask
- Die Lesefunktion mit collidemask
Wenn wir etwas auf den Kollisionslayer schreiben, erlaubt uns der id:Object-Parameter das Bild, das wir auf den Kollisionlayer geschrieben haben, zu identifizieren.
Wenn wir einmal die Identitäten geschrieben haben, werden die involvierten Objekte bei der Kollisionsabfrage in einem Object-Array zurückgeliefert.
Lass uns das mit einem sehr simplen Beispiel zeigen:
Strict Graphics 640,480 AutoMidHandle True Local URL:String="http::www.hanfgebiet.de/" Local SpaceShip:TImage=LoadImage(LoadBank(URL+"blobship_1-1.png")) Local AlienShip1:TImage=LoadImage(LoadBank(URL+"cartoonufo_1-1.png")) Local AlienShip2:TImage=LoadImage(LoadBank(URL+"cartoonufo_1-1.png")) Repeat Cls Local R:Int=0 Local G:Int=0 Local B:Int=255 ResetCollisions() SetColor 255,255,255 DrawImage AlienShip1, 250,100 CollideImage(AlienShip1,250,100,0,0,1,AlienShip1) DrawImage AlienShip2, 400,100 CollideImage(AlienShip2,400,100,0,0,1,AlienShip2) Local p:Object[]=CollideImage(Spaceship,MouseX(),MouseY(),0,1,0) For Local i:TImage=EachIn p Select i Case AlienShip1 R=255 Case AlienShip2 G=255 End Select Next SetColor R,G,B DrawImage SpaceShip,MouseX(),MouseY() Flip Until KeyDown(KEY_ESCAPE) Or AppTerminate() |
Beachte, dass die Farbe abhängig von dem Kollisionszustand geändert wird. Wir können also Kollisionen mit beiden Aliens mit nur einem CollideImage-Aufruf erkennen, da alle kollidierende Objekte im Object-Array zurückgegeben werden.
Falls du das AlienShip1-Objekt nicht zum letzten CollideImage-Parameter schreibst, kannst du keine Kollision anhand des Objektnamen erkennen. Probier es aus!
DrawImage AlienShip1, 250,100 CollideImage(AlienShip1,250,100,0,0,1,Null) |
Beachte, dass wenn du das SpaceShip auch zum Kollisionslayer hinzuschreibst, das SpaceShip-Objekt auch im Object-Array zurückgegeben wird. Wenn du also Kollisionsprüfungen machst, muss du auf das aufpassen, da du sonst denkst, dass eine Kollision stattfand, obwohl du nur mit dir selbst kollidierst. In meinen Beispielen habe ich das SpaceShip-Bild nicht in den Kollisionslayer geschrieben, also ist das kein Problem.
Unten (hervorgehoben) ist ein Beispiel, dass Kollisionen auf mehreren Layern detektiert:
Strict Graphics 640,480 AutoMidHandle True Local URL:String="http::www.hanfgebiet.de/" Local SpaceShip:TImage=LoadImage(LoadBank(URL+"blobship_1-1.png")) Local AlienShip1:TImage=LoadImage(LoadBank(URL+"cartoonufo_1-1.png")) Local AlienShip2:TImage=LoadImage(LoadBank(URL+"cartoonufo_1-1.png")) Repeat Cls Local R:Int=0 Local G:Int=0 Local B:Int=255 ResetCollisions(3) SetColor 255,255,255 DrawImage AlienShip1, 250,100 CollideImage(AlienShip1,250,100,0,0,1,AlienShip1) DrawImage AlienShip2, 400,100 CollideImage(AlienShip2,400,100,0,0,2,AlienShip2) Local Collision_Layer:int=2 Local p:Object[]=CollideImage(Spaceship,MouseX(),MouseY(),0,Collision_Layer,0) For Local i:TImage=EachIn p Select i Case AlienShip1 R=255 Case AlienShip2 G=255 End Select Next SetColor R,G,B DrawImage SpaceShip,MouseX(),MouseY() Flip Until KeyDown(KEY_ESCAPE) Or AppTerminate() |
Wenn du den obigen Code ausführst, wirst du sehen, dass unser SpaceShip nur dann kollidiert, wenn vom gleichen Kollisionslayer gelesen wird. Um mit dem Schiff 1 zu kollidieren, verwende Collision_Layer:int=1. Um mit beiden Schiffen zu kollidieren, ändere den Collision_Layer-Wert auf 3.
Das Ziel von diesem zweiten Teil war, dir zu zeigen wie du die mächtigere CollideImage-Funktion anstelle der traditionelleren Bild-zu-Bild-Kollision, die wir im ersten Teil behandelt haben, nutzen kannst.
Zum Mitnehmen ist, dass die Kollisionsprüfung nicht auf der Zeichnungsfläche, sondern auf einem separaten Kollisionslayer gemacht wird. Dies erlaubt eine selektivere (und schnellere) Kollisionsprüfung. BlitzMax hat 32 Kollisionslayer die wir benutzen können.
Zum Widerhohlen:
- Zuerst den Kollisionslayer mit ResetCollisions(layer#) löschen.
- Die Bilder, die wir auf Kollision überprüfen wollen, auf den/die Kollisionlayer schreiben.
- Von dem/den Kollisionslayer lesen, um die Kollisionsprüfung durchzuführen.
** Vergiss nicht, dass die Layer Maskierbar sind!