NoUserOrg

Reto Spoerri : Game Design : Zürich

ProgrammingPanda3dTutorialInteraktiveManipulation

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

====== Interaktive manipulation ======

<code type="Python"> import direct.directbase.DirectStart from pandac.PandaModules import * from direct.showbase.DirectObject import DirectObject

import string

  1. liste von events die wir abfangen

POLLKEYS = list(string.ascii_lowercase+string.digits) POLLKEYS.extend(

  [ '_del', 'alt', 'asciiKey', 'backspace', 'capsLock', 'control', 'down', 'end', 'enter', 'escape',     'f1', 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8',     'f9', 'help', 'home', 'insert', 'lalt', 'lcontrol', 'left', 'lshift', 'meta', 'numLock',     'pageDown', 'pageUp', 'pause', 'printScreen', 'ralt', 'rcontrol', 'right', 'rshift', 'scrollLock',     'shift', 'shiftLock', 'space', 'tab', 'this', 'this_metatype', 'up',  'arrow_up', 'arrow_down',     'arrow_left', 'arrow_right' ] ) 
  1. diese klasse speichert welche tasten momentan gedrueckt werden

class KeyPollerClass( DirectObject ):

  def __init__( self ): 
    self.data = dict() 
    for key in POLLKEYS: 
      self.accept( key, self.event, [key, True] ) 
      self.accept( key+"-up", self.event, [key, False] ) 
      self.data[ key ] = False 
  def event( self, key, active ): 
    self.data[key] = active 
  def __getitem__( self, key ): 
    return self.data[key] 

keyPoller = KeyPollerClass()

  1. camerasteuerung ausschalten und position setzen

base.disableMouse() camera.setPos( Vec3(0,-30,20) ) camera.lookAt( 0,0,3 )

panda = loader.loadModel('panda') panda.reparentTo(render) panda.setScale(.5)

  1. defintion der tasten und der ausgefuehrten bewegung

MOVEFUNCTIONS = { 'arrow_up' : Vec3(0,-10,0),

                    'arrow_down' : Vec3(0, 10,0) } 

ROTATEFUNCTIONS = { 'arrow_left' : Vec3( 90,0,0),

                    'arrow_right': Vec3(-90,0,0) } 

def moveTask( task ):

  # vergangene zeit seit dem letzten frame 
  dt = globalClock.getDt() 
  # fuer jede gedrueckte taste aus den MOVEFUNCTIONS 
  for key, action in MOVEFUNCTIONS.items(): 
    if keyPoller[ key ]: 
      # bewege den panda relativ zu sich selbst um den Vektor*Zeit 
      panda.setPos( panda, action*dt ) 
  for key, action in ROTATEFUNCTIONS.items(): 
    if keyPoller[ key ]: 
      # rotiere den panda relativ zu sich selbst um den Vektor*Zeit 
      panda.setHpr( panda, action*dt ) 
  # wiederhole diesen task 
  return task.cont 

taskMgr.add( moveTask, 'moveTask' )

run() </code>

In diesem Beispiel werden die Eventbasierten inputs gespeichert und permanent zugänglich gemacht.



<code type="Python"> class keyPollerClass( DirectObject ): </code> Definiert eine Klasse namens keyPollerClass, sie wird von DirectObject abgeleitet. Dies ermöglicht es Events abzufangen. Vorteilhaft gegenüber base.accept ist dass wir die events auch wieder ausschalten können (self.ignoreAll).



<code type="Python">

  1. defintion der tasten und der ausgefuehrten bewegung

MOVEFUNCTIONS = { 'arrow_up' : Vec3(0,-10,0),

                    'arrow_down' : Vec3(0, 10,0) } 

ROTATEFUNCTIONS = { 'arrow_left' : Vec3( 90,0,0),

                    'arrow_right': Vec3(-90,0,0) }

</code> Definiert ein dictionary mit den tasten und deren auswirkungen. Ein dictionary hat immer einen Key und einen Value, der Key muss hashable sein (String, Zahl oder Tuple; keine Dictionary's oder Listen). Die Werte eines Dictionary's können ähnlich wie bei einer Liste abgefragt werden: <code type="Python"> MOVEFUNCTIONS['arrow_up'] </code>



<code type="Python"> taskMgr.add( moveTask, 'moveTask' ) </code> der Taskmanager verwaltet funktionen die zBsp bei jedem Frame ausführt werden, als Parameter wird die auszuführende Funktion sowie ein Name dafür angegeben.



<code type="Python"> def moveTask( task ): </code> Dies ist nun ein solcher Task, er wird bei jedem Frame ausgeführt und benötigt mindestens task als Parameter.



<code type="Python">

  1. vergangene zeit seit dem letzten frame dt = globalClock.getDt()

</code> globalClock ist der Zeitgeber von Panda3d, es können diverse Zeitinformationen abgefragt werden. Hier zBsp. die vergangene Zeit seit dem letzten Frame.

<code type="Python">

  1. fuer jede gedrueckte taste aus den MOVEFUNCTIONS for key, action in MOVEFUNCTIONS.items():
    if keyPoller[ key ]: 
      # bewege den panda relativ zu sich selbst um den Vektor*Zeit 
      panda.setPos( panda, action*dt ) 
for key, action in ROTATEFUNCTIONS.items():
    if keyPoller[ key ]: 
      # rotiere den panda relativ zu sich selbst um den Vektor*Zeit 
      panda.setHpr( panda, action*dt ) 
  # wiederhole diesen task

</code> In diesem teil werden die beiden Dictionary's welche vorhin erstellt wurden durchlaufen und geprüft ob die gewünschten Tasten gedrückt sind.



<code type="Python"> return task.cont </code> Am ende eines Task's muss festgelegt werden ob diese weiterhin laufen soll (über task.cont), es gibt andere Rückgabewerte wie task.done (task wird beendet) oder task.again (wiederholt den task mit der festgelegten verzögerung), wird kein Parameter zurückgegeben bricht der task ab (task.done).



weiterführende erkärung der Interaktiven Manipulation?



Wie eben kurz angetönt können Tasks auch verzögert aufgerufen werden: <code type="Python"> taskMgr.doMethodLater( delayTime, function, 'task name' ) </code>



===== Weitere Informationen zu Task's unter ===== http://www.panda3d.org/wiki/index.php/Tasks