# Kollision von Objekten



## jbow (24. Dez 2006)

Im Forum steht ja einiges zum Thema Kollision, allerdings bleibt bei mir da eine Frage offen..
Ist es möglich eine ereignisgesteuerte Kollisionserkennung zwischen Objekten bei klassischen 2D Spielen zu implementieren?
Ich bin eher noch ein Anfänger im Bereich Java-Grafik-/Spieleprogrammierung und kenne das aus anderen Programmiersprachen/
Plattformen auf denen ich früher mal programmiert habe (z.B. C64) so, dass z.B. bei der Kollision zwischen Sprite/Sprite oder Sprite/Hintergrund ein Flag gesetzt wird welches ich dann abfrage und irgendwas anstosse. Die meisten Beispiele die ich bei Java gefunden habe beruhen aber auf einem Positionsvergleich, was m.E. umständlicher ist.
Deshalb die Frage, geht das nicht mit der "Eventsteuerung" oder wenn doch wie muss ich das implementieren?
Gerade bei Monstern die teilweise aus transparenten Pixeln bestehen, weil sie halt gezack sind, stösst die Positionsberechnung m.E. an ihre Grenzen?!

Was meint Ihr dazu?


----------



## LoN_Nemesis (24. Dez 2006)

Ich weiss nicht genau was eventbasierte Kollision sein soll, deswegen kann ich deine Frage nicht richtig beantworten. Wie funktioniert das, man setzt ein Flag wenn es irgendwo im Spiel eine Kollision gibt? Ok und dann bekommt man wahrscheinlich noch Zugriff auf die kollidierenden Objekte und kann entsprechend reagieren.
Das ist doch fast das gleiche wie "positionsbasierte Kollision" oder? Ich meine ob man nun ein Objekt bewegt, ein Flag setzt und dann reagiert oder ein Objekt bewegt und dann direkt reagiert ist ja jetzt nicht so der unterschiedliche Ansatz.

Normalerweise macht man Kollisionsabfragen ja mit Bounding Boxes, also irgendwelchen geometrischen Körpern die die kollisionsrelevanten Teile eines Spielobjektes möglichst gut abdecken. Aber man kann doch genauso gut jeden Pixel zweiter Objekte prüfen.

Also wie gesagt ich weiss nicht was eventbasierte Kollisionserkennung sein soll. Aber wenn du es weisst solltest du es auch implementieren können. Ich denke mal die Programmiersprache wird da nicht das Hindernis sein. Und wenn man es auf dem C64 machen konnte, dann kann man es mit Java auch


----------



## jbow (24. Dez 2006)

Also die Funktionsweise beim C64 muss ich wohl nochmal etwas ausführlicher erklären, dann das ist der Weg den ich kenne...
Programmiert wird hierbei in Assembler, was ja bekanntlich hardwarenah ist. Die beteiligten Flags sind Register auf dem Videochip des C64 und werden teilweise von diesem Baustein selbständig gesetzt.
D.H. ich teile dem Chip durch setzen eines Bits in einem bestimmten Register (z.B. Bit = 1) mit, dass bei Kolision von zwei Sprites untereinander ein IRQ (=eine Art Exception, nur hardwarebasiert) ausgelöst werden soll. Der Chip überwacht "seine" fest implementierten 8 Sprites und setzt bei einer Kollision dann die Register der beteiligten Sprites und ruft den IRQ auf. Hier klinkt sich dann meine Routine ein, stellt über die gesetzten Register fest welche Sprites betroffen sind, und löst z.B. eine Explosion dadurch aus, dass eine andere Grafik geladen wird.
Die Sprites selbst sind immer eckig, allerdings reagiert die Kollision des Videochips nur auf gesetzte Bytes. Das bedeutet, ein rundes Sprites reagiert nur mit der "sichtbaren" Fläche auf eine Kollision. 
Das finde ich eigentlich recht komfortabel, auch wenn der "Brotkasten" schon mehr als 20 Jahre alt ist...
Allerdings will ich ja jetzt mal ein altes Spiel in Java neu programmieren und da war eben meine Vorstellung, es von der Architektur her genauso zu machen. Das ganze dann natürlich objektorientiert und nicht mehr hardwarenah, aber eben ereignisgesteuert. Darunter vestehe ich, dass es so eine Art Kollisionregister/Objektvariable gibt, die ich abfragen kann ob eine Kollision stattgefunden hat und die dann meine Routine ausführt. Soll halt so ähnlich sein wie das Abfragen einer Tastatureingabe.
Aber ich habe eben mittlerweise den Eindruck, dass es mit Java anders besser geht.
Eben über den Positionsvergleich (X und Y Koordinate).
Allerdings habe ich hierbei noch nicht ganz verstanden, wie es mit Grafiken funktioniert.
Wie stelle ich bei gezackten Grafiken eine Kollision pixelgenau fest?
Das mit der Position geht m.E. nicht, denn dann müsst ich über eine Grafik deckungsgleich ein Polygon legen und mit einer irrelangen Entfernungsformel hantieren?
Habe ich das so richtig verstanden?

Freue mich über jeden Hinweis!


----------



## Illuvatar (24. Dez 2006)

Also fest implementiert gibt es sowas IMO in Java nicht. Allerdings könntest du das in eine Klasse amchen, und so schwer zu implementieren wäre das jetzt auch nicht unbedingt.
Du könntest eine Klasse Sprite erstellen, die das BufferedImage und ein boolean-Flag enthält, das angibt, ob das Sprite kollidiert ist.
Dann hast du eine Klasse, die für das Zeichnen zuständig ist, ads geht die Sprites durch und zeichnet die BufferedImages. Und dann könnte Sprite eine Methode intersects(Sprite, xOffset, yOffset) haben - und der Trick wäre dann, dass du die Pixelwerte aus den BufferedImages ausliest, an den Stellen, an denen die Sprites übereinander gezeichnet werden (am Besten vorher testen, ob sie überhaupt übereinander gezeichnet werden). Wenn dann beide Pixel nicht transparent sind - boolean-Flag setzen.


----------



## LoN_Nemesis (25. Dez 2006)

Ja wenn du es wirklich pixelgenau machen willst, dann ist das von Illuvatar eine gute Lösung.

Allerdings solltest du dir wirklich überlegen ob du das brauchst. In 90% aller Fälle muss es nämlich wirklich nicht pixelgenau sein. Die Bewegungen/Schüsse etc sind meist so schnell, man sieht überhaupt nicht ob der Treffer jetzt genau richtig oder um 2 Pixel verschoben war. Und eins ist mal klar: Pixelgenaue Kollision kostet eine Menge Rechenzeit.. ich persönlich würde da eher mit Bounding Boxes arbeiten und dafür kann man dann auch mehr als 3 Figuren auf einmal darstellen.


----------



## jbow (25. Dez 2006)

Vielen Dank für Eure Antworten, auch wenn ich die Antwort von Illuvatar nicht vollständig verstanden habe. Vermutlich stecke ich da einfach (noch) nicht tief genug drinnen.
Vielleicht könnte man das Problem ja auch lösen ohne das Rad neu zu erfinden..
Ich muss nicht den Weg des C64 nach Java portieren, es ging mir nur darum den mir bekannten Weg zu beschreiben.
Es gibt ja eine Reihe von Spielen in Java, die ja genau dieselben Fragestellungen hinsichtlich der Kollision haben wie die Klassiker auf dem C64. Mich interessiert in erster Linie wie es dort implementiert wurde.
Insofern habe ich jetzt verstanden, dass man es in Java wohl tatsächlich über die Position und nicht über eine Kollisionserkennung nach meiner Definition macht.
In diesem Zusammenhang wurde die Bounding Box genannt. Ich lege in die BB eine Grafik und überprüfe laufend die Entfernung zu anderen Objekten (Bounding Boxen??). Bei einem bestimmten Abstand löse ich z.B. eine Explosion aus.
Bei runden "Monstern" ignoriere ich die u.U. am Rand fehlenden Pixel, bzw. berechne mir den Radius oder sowas.
Kleine Ungenauigkeiten fallen nicht so ins Gewicht, da die Bewegungen recht schnell sind?
Alles richtig verstanden??

Ach ja.. Frohe Weihnachten....


----------



## LoN_Nemesis (25. Dez 2006)

Ja das hast du richtig verstanden. Im übrigen kommt es auch noch darauf an, ob du eine tile-basierte Welt hast oder eine kontinuierliche. Wenn die ganze Welt in Tiles aufgeteilt ist und sich Spielobjekte auch nur tileweise bewegen können, dann brauchst du nichtmal eine Bounding Box. Dann reicht wirklich ein einfacher Positionsvergleich.

Falls du mal ein Beispiel sehen willst: http://mitglied.lycos.de/destinyjava/

Das war ein Spieleprojekt von mir, wird aber nicht mehr weitergemacht. Jedenfalls arbeite ich da mit Bounding Boxes. Allerdings sind die noch nicht richtig angepasst, du wirst merken, dass man oft deutlich zu früh kollidiert.

Insgesamt funktioniert es also so: Es gibt eine Liste in der alle Spielobjekte eingetragen werden die aktiv in der Welt sind (in diesem Fall der Held, der Hase und die beiden Schleimblobbs). Jedesmal wenn ein Objekt sich bewegt, wird überprüft ob an der neuen Position schon ein anderes Objekt ist. Dazu gehe ich einfach alle Objekte in der Liste durch und überprüfe ihre Bounding Boxes mit .intersect (ist eine Java Methode, funktioniert mit Rectangle, Oval, etc). Falls .intersect ein true liefert, dann wird die Bewegung nicht ausgeführt, wenn false dann ja. Ich hab das mit 500+ aktiven Spielobjekten auf einmal getestet, läuft immer noch flüssig. Allerdings ist auch noch keine KI und so implementiert.

Optimieren kann man das ganze noch, in dem man z.b. die Liste schlau verwaltet. Bei mir gibt es zum Beispiel ein visible flag, wenn das "false" ist, dann wird gar nicht erst auf Kollision geprüft.

Wenn du es pixelgenau machen willst, kannst du genau den gleichen Ansatz benutzen. Nur vergleichst du da eben keine Bounding Boxes, sondern die als BufferedImage gespeicherten Grafiken der Spielobjekte. Die dafür notwendige .intersects Methode musst du wahrscheinlich selbst schreiben, sollte aber nicht zu schwer sein.


Dir auch frohe Weihnachten


----------



## jbow (27. Dez 2006)

Vielen Dank für Deine ausführliche Erklärung. Ich glaube jetzt habe ich zumindest den Positionsvergleich kapiert.
Es gibt hier auch noch ein sehr gutes Tutorial, in welchem es genauso gemacht wird. Es klappt eigentlich recht gut.
http://www.planetalia.com/cursos/Java-Invaders/JAVA-INVADERS-20.tutorial

Kann ich nur jedem empfehlen.

Viele Grüße!


----------

