NoUserOrg

Reto Spoerri : Game Design : Zürich

ProgrammingPanda3dTutorialKollisionen

Filed in: Resources.ProgrammingPanda3dTutorialKollisionen · Modified on : Fri, 31 Jul 09

====== Kollisionen ======

Kollisionen sind ein wichtiges Element für die Steuerung eines Spiels. Sie werden nicht nur verwendet um den Kontakt zwischen zwei Szenenobjekten festzustellen, sondern werden auf zum detektieren von Mausklicks auf Objekte benötigt. Es gibt mehrere Möglichkeiten Objekte kollidierbar zu machen.

  * Das verwenden des Modelles als Kollisionsobjekt.
  * Das verwenden einer speziellen Modelles als Kollisionsobjekt.
  * Das verwenden von speziellen Kollisionsformen als Kollisionsobjekt.

Die Objektgeometrie ist die genaueste Methode zur Kollisionsüberprüfung. Sie macht jedoch nur Sinn wenn sehr genaue abfragen notwendig sind, da diese Methode äusserst rechenintensiv ist.

Das verwenden eines speziellen Modelles (low-poly) zur Kollisionsüberprüfung wird verwendet wenn genaue Informationen benötigt oder komplexe Modelle überprüft werden.

Kollisionsformen werden eingesetzt wenn keine genauen Kollsionen benötigt werden. Es gibt verschiedene solche Formen: http://www.panda3d.org/wiki/index.php/Collision_Solids



Panda3d kann nicht jede Form gegen eine beliebige andere Form kollidieren lassen. So existieren zBsp keine Kollisionstests von 3d Modellen gegen andere 3d Modelle. Dies erscheint auf den ersten Blick absurd, jedoch wird ein solcher Kollisionstest in einem Spiel kaum benötigt. Ein Kollisionstest von 2 Objekten mit je 100 Polygonen benötigt bereits 10'000 Kollisionsüberprüfungen (100*100).



===== Kollisionsevents ===== Panda3d kann auf 2 verschiedene Arten auf Kollisionen reagieren, zum einen mit dem erstellen eines Events, zum anderen als Liste die abgefragt werden kann.



===== Kollisionbitmasks ===== Damit Panda3d Objekte gegeneinander kollidieren lässt müssen zum einen Objekte als "from" definiert werden, zum anderen müssen alle Objekte müssen alle Objekte die entsprechende bitmask haben. Als "from" Objekte werden grundsätzlich die beweglichen Objekte definiert, je mehr "from" Objekte definiert sind desto mehr muss berechnet werden.

http://www.panda3d.org/wiki/index.php/Collision_Bitmasks

auszug aus Tut-Roaming-Ralph.py <code type="Python">

        # ein collisiontraverser überprüft die Szene auf kollisionen
        self.cTrav = CollisionTraverser()

        # ein collisionray ist ein strahl, (eine linie von einem punkt ausgehend in das unendliche)
        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,1000)
        self.ralphGroundRay.setDirection(0,0,-1)
        # ein CollisionNode enthält einen oder mehrere collisionsobjekte
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        # die collisionsmask definiert mit welchen objekten kollidiert werden soll
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        # der collider wird an den charakter angehaengt und fährt somit mit ihm mit
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        # eine collisonhandlerqueue ermöglicht das abfragen von kollisionen 
        # die durch die assoziierten colliders erstellt werden
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

</code>

im egg file kann die collisionbitmask ebenfalls defniert werden: <code type="Python">

  <Collide> { Polyset keep descend }
  <Scalar> collide-mask { 0b001 }

</code>



===== Kollsion und Klassen ===== Wenn Objekte in Panda3d kollidieren bekommen wir Informationen über die Kollisionsobjekte. Diese beinhalten den Kollisionspunkt, die Normalen sowie die beiden NodePath's. Wenn im Code jedoch weitere Informationen über diese Objekte gespeichert sind, müssen wir diese zuordnen können.

<code type="Python"> class PandaClass:

  def __init__( self, name ):
    self.np = loader.loadModel( 'panda' )
    self.name = name
    self.np.setTag('myObjectTag', name)

panda1 = PandaClass( 'hans' ) panda2 = PandaClass( 'bruno' )

nodeNames = { 'hans': panda1

            , 'bruno': panda2 }

...

nodeTag = panda1.np.getTag('myObjectTag') nodeNames[nodeTag] → gibt panda1 </code>

Die Funktion setTag ermöglicht es dem NodePath einen String zuzuordnen. Anschliessend kann mit den Funktionen getTag, getNetTag, findNetTag der entsprechende Tag abgefragt werden. (die ...Net... funktionen suchen auch in den ParentNodes nach dem entsprechenden Tag) http://www.panda3d.org/wiki/index.php/Clicking_on_3D_Objects



===== Kollisionsabfragen ===== <code type="Python"> queue = CollisionHandlerQueue() traverser.addCollider(fromObject, queue) traverser.traverse(render) queue.sortEntries() for i in range(queue.getNumEntries()):

  entry = queue.getEntry(i)
  print entry
  obj = entry.getIntoNodePath()
  obj.findNetTag( 'myObjectTag' )

</code>