questions about ode and somthing else(solved)

Hi
I have spent several weeks working on Panda3D hoping to build a small game at last. And inevitablly I got some problems. Here are some them.

the code is listed below those problem, it looks a little bit long but the part where i got the problem is highlighted.

when I attaching a odebody to an actor, it seemed impossible to control the actor’s hpr by method setHpr(). I only can use the odebody method setRotation() to do the rotation but still can get the angle by actor method getH().Is it a rule or something?

When I dragging the window, charactor with an odebody shaked like a tumbler, make everything a little naughty. Is there a way to tackle this?

and about ode collision detection, thanks pro-rsoft for uploading a new ode sample in the forum. now I can use self.accept(“ode-collision”, self.onCollision) to accept collision. but is there a more particular way I mean in which I can specify more details like “from object” and “into boject” etc.

and in the code below, I got a very weird problem. In this program, I wanted to control a charactor to do some performence like running, jumping, and some animation. others looked fine, but the “running part"did not. In the “running part” I intended to control the charactor to run in several velocities and whin max and min range by using “arrow_up” and " arrow_down”. I used some global virables to act like constants, and give it to the keyMap dictionary. unexpectedly those “constants” changed when I give it to variables. I know it’s stupid, but I can’t find where I reset those “constants”.

by the way, is there a genuine constant expression in python?

still, one last question: Is there a place I can got more “free-downloadable” eggs other than the art gallery. I tried and failed to learn 3DS max, since my time is limited. I only want a animal charactor(a sheep) with several animation. but I can’t find any existed models with enough animations(2~3 beside “walking”)in the art gallery. now I use “the boxing robert” which is in the tutorial instead.

At last, thanks for all hard working for the new release of V1.6.0 and especially the downloadable manual since I am a newbie and it’s not easy to get access to Internet 24*7 in my country~

#sheep Ver. 0.9
#an overall test about all the sheep can do
#from jumping, performence, landing to sending point
#use ODE physics engine
#use a exited model to fake sheep, since the sheep haven't been modeled yet

#run stably :)
#jump and run look fine :)
#can do some performence:)
#can spin :)

#Problems:
#can't control the velocity of running correctly
#MAX_vel changed when I set self.keyMap["runVel"]

#press space to jump
#arrow-up to accelerate
#arrow-down to decelrate

#April 9th 2009
from direct.directbase import DirectStart
from pandac.PandaModules import AmbientLight,DirectionalLight
from pandac.PandaModules import LightAttrib
from pandac.PandaModules import OdeWorld, OdeSimpleSpace, OdeJointGroup
from pandac.PandaModules import OdeBody, OdeMass, OdeBoxGeom, OdePlaneGeom
from pandac.PandaModules import BitMask32, CardMaker, Vec3, Vec4, Quat,Mat3
from direct.actor import Actor
from direct.showbase.DirectObject import DirectObject
from direct.interval.MetaInterval import Sequence

#create game states global viriables
gameStates = {"jumping": False,
              "running": False,
              "inTheAir": False}

#Constants that will control the behavior of the game.
SHEEP_INIT_VEL = Vec3(0,0,0)#-0.5)
SHEEP_MAX_VEL = Vec3(40.0,40.0,0.0)#-0.5)
SHEEP_MIN_VEL = Vec3(-40.0,-40.0,0.0)#-0.5)
SHEEP_ACCEL = Vec3(20,20,0)
SHEEP_DECEL = Vec3(-20,-20,0)
SHEEP_FORCE_DURATION = 0.5

class Environment:
    def __init__(self):
        # Load the first environment model
        Environment._environ = loader.loadModel( "models/environment" )
        Environment._environ.reparentTo( render )
        Environment._environ.setScale( 0.25, 0.25, 0.25 )
        Environment._environ.setPos( -8, 42, 0 )

        # Setup our physics world
        Environment.world = OdeWorld()
        Environment.world.setGravity(0, 0, -9.81)

        # Create a space and add a contactgroup to it to add the contact joints
        Environment.space = OdeSimpleSpace()
        Environment.space.setAutoCollideWorld(Environment.world)
        Environment.contactgroup = OdeJointGroup()
        Environment.space.setAutoCollideJointGroup(Environment.contactgroup)

        # The surface table is needed for autoCollide
        Environment.world.initSurfaceTable(1)
        Environment.world.setSurfaceEntry(0, 0, 
                              mu = 0.001, 
                              bounce = 0.0, 
                              bounce_vel = 9.1, 
                              soft_erp = 0.9, 
                              soft_cfm = 0.00001, 
                              slip = 0.0, 
                              dampen = 0.9)

        # Add a plane to collide with
        Environment._groundGeom = OdePlaneGeom(Environment.space, Vec4(0, 0, 1, 0))
        Environment._groundGeom.setCollideBits(BitMask32(0x00000001))
        Environment._groundGeom.setCategoryBits(BitMask32(0x00000002))
        
        #set collision event ???
        Environment.space.setCollisionEvent("ode-collision") 
    
        # Set the camera position
        base.disableMouse()
        base.camera.setPos(80, -20, 40)
        base.camera.lookAt(0, 0, 10)
        
        #setup Lights
        self.setupLights()
    ##end __init__
        
    #This function sets up the lighting
    def setupLights(self):
        lAttrib = LightAttrib.makeAllOff()
        ambientLight = AmbientLight( "ambientLight" )
        ambientLight.setColor( Vec4(.8, .8, .75, 1) )
        lAttrib = lAttrib.addLight( ambientLight )
        directionalLight = DirectionalLight( "directionalLight" )
        directionalLight.setDirection( Vec3( 0, 0, -2.5 ) )
        directionalLight.setColor( Vec4( 0.9, 0.8, 0.9, 1 ) )
        lAttrib = lAttrib.addLight( directionalLight )
        render.attachNewNode( directionalLight.upcastToPandaNode() ) 
        render.attachNewNode( ambientLight.upcastToPandaNode() ) 
        render.node().setAttrib( lAttrib )
##end  Environment

class sheep(DirectObject):
    def __init__(self):
        self._sheep = Actor.Actor('samples/Boxing-Robots/models/robot',
          {'leftPunch' : 'samples/Boxing-Robots/models/robot_left_punch', 
           'rightPunch' : 'samples/Boxing-Robots/models/robot_right_punch', 
           'headUp' : 'samples/Boxing-Robots/models/robot_head_up', 
           'headDown' : 'samples/Boxing-Robots/models/robot_head_down'})
        
        #wrap animation into Sequence
        self.performence1 = Sequence(self._sheep.actorInterval('leftPunch'))
        self.performence2 = Sequence(self._sheep.actorInterval('rightPunch'))
        self.performence3 = Sequence(self._sheep.actorInterval('headUp'),self._sheep.actorInterval('headDown'))
                                                 

        #Actors need to be positioned and parented like normal objects
        self._sheep.setPosHprScale(0,0,2,45,0,0,1,1,1)
        self._sheep.reparentTo(render)

        #setup sheep body
        self._sheepBody = OdeBody(Environment.world)
        self._sheepMass = OdeMass()
        self._sheepMass.setBox(100, 1, 1, 1)
        self._sheepBody.setMass(self._sheepMass)
        self._sheepBody.setPosition(self._sheep.getPos(render))
        self._sheepBody.setQuaternion(self._sheep.getQuat(render))

        # Create collision geometry
        self._sheepGeom = OdeBoxGeom(Environment.space, 2,2,2)
        self._sheepGeom.setCollideBits(BitMask32(0x00000002))
        self._sheepGeom.setCategoryBits(BitMask32(0x00000001))
        self._sheepGeom.setBody(self._sheepBody)
        
        #create a control keys' dictionary
        self.keyMap = {"jump":          False,
                       "runVel":        SHEEP_INIT_VEL,
                       "per1":          False,
                       "per2":          False,
                       "spinLeft":      False,
                       "spinRight":     False}
        
        # Accept the control keys for movement
        self.accept("space", self.setJumpKey, [True])
        self.accept("space-up", self.setJumpKey, [False])
        self.accept("arrow_up", self.setRunKey, [SHEEP_ACCEL])
        ##self.accept("arrow_up-up", self.setKey, ["runVel", vec3(0,0,0)])
        self.accept("arrow_down", self.setRunKey, [SHEEP_DECEL])
        ##self.accept("arrow_down-up", self.setKey, ["runVel", vec3(0,0,0)])
        self.accept("q", self.setPerformanceKey, ["per1", True])
        self.accept("q-up", self.setPerformanceKey, ["per1", False])
        self.accept("w", self.setPerformanceKey, ["per2", True])
        self.accept("w-up", self.setPerformanceKey, ["per2", False])
        self.accept("a", self.setPerformanceKey, ["spinLeft", True])
        self.accept("a-up", self.setPerformanceKey, ["spinLeft", False])
        self.accept("s", self.setPerformanceKey, ["spinRight", True])
        self.accept("s-up", self.setPerformanceKey, ["spinRight", False])
        
        self.accept("ode-collision", self.onCollision) 
        
        #add perform task
        performTask = taskMgr.add(self.perform, "perform")
        performTask.last = 0    #last task.time
        performTask.jumpDtAccum = 0 #delta time accumulator for jumping
        performTask.perDtAccum = 0 #delta time accumulator for performence
        #run sheepDetection once per second
        ##taskMgr.doMethodLater(1,self.sheepDetection,"sheepDetection")
     ##end __init__
     
    #these are a set of setKey method to set keyMap dictionary and change the gameStates dictionary   
    def setPerformanceKey(self, key, value):
        self.keyMap[key] = value
        
    def setJumpKey(self,value):
        self.keyMap["jump"] = value
        gameStates["jumping"] = True
        gameStates["running"] = False
        gameStates["inTheAir"] = True
##--------------------------------------------------------------------------##    
    #here I got problems 
    def setRunKey(self, value):
        gameStates["running"] = True
        if self.keyMap["runVel"] > SHEEP_MAX_VEL:
            print self.keyMap["runVel"],">", SHEEP_MAX_VEL
            self.keyMap["runVel"] = SHEEP_MAX_VEL
            print "setmax", self.keyMap["runVel"]
            print "MAX_VEL is:",SHEEP_MAX_VEL
            
        elif self.keyMap["runVel"] < SHEEP_MIN_VEL:
            print self.keyMap["runVel"],"<", SHEEP_MIN_VEL
            self.keyMap["runVel"] = SHEEP_MIN_VEL
            print "min", self.keyMap["runVel"]
            print "MIN_VEL is:",SHEEP_MIN_VEL
            
        else: 
            self.keyMap["runVel"] += value        
            print "setkey",self.keyMap["runVel"]
            print "MAX_VEL is:",SHEEP_MAX_VEL
            print "MIN_VEL is:",SHEEP_MIN_VEL
    ##end setKey
##--------------------------------------------------------------------------##     
    #create a perform task
    def perform(self,task): 
        
        dt = task.time - task.last
        task.last = task.time
        #when sheep is jumping give it a static force in duration of SHEEP_FORCE_DURATION
        if gameStates["jumping"]:
            task.jumpDtAccum += dt
            if task.jumpDtAccum < SHEEP_FORCE_DURATION:
                self._sheepBody.setForce(Vec3(0,0,4000))
            else:
                print "force duration is:",task.jumpDtAccum
                task.jumpDtAccum = 0
                gameStates["jumping"] = False                 
        ##end if
        
        #when sheep is running update it's running velocity
        if gameStates["running"]:
            self._sheepBody.setLinearVel(self.keyMap["runVel"])
        ##end if
        
        if self.keyMap["spinLeft"]:
            task.perDtAccum += dt
            rotation =self._sheepBody.getRotation()
            rotation.setRotateMat(task.perDtAccum*300)
            #print "after:",rotation
            self._sheepBody.setRotation(rotation)
            
        if self.keyMap["spinRight"]:
            task.perDtAccum -= dt
            rotation =self._sheepBody.getRotation()
            rotation.setRotateMat(task.perDtAccum*300)
            #print "after:",rotation
            self._sheepBody.setRotation(rotation)       
        if gameStates["inTheAir"]:
            if self.keyMap["per1"] and not self.performence1.isPlaying() and not self.performence2.isPlaying():
                self.performence1.start()
            if self.keyMap["per2"] and not self.performence1.isPlaying() and not self.performence2.isPlaying():
                self.performence2.start()

        ##end if    
                       
        return task.cont
    ##end jump
    
    #when collision is detected chang gameState["jumping"] to False
    #it seems it's been called everyframe since sheep lands ground
    def onCollision(self, entry):
        gameStates["inTheAir"] = False
        ##print "jumping = ",gameStates["jumping"]
    ##end onCollision
    
    def sheepDetection(self, task):
        print "vel is:",self._sheepBody.getLinearVel()
        print "heading is:",self._sheep.getH()
        for name in gameStates:
            print name, ":", gameStates[name]
        return task.again
##end sheep


class World:
    def __init__(self):
        Environment()
        self.sheep00 = sheep()
        self.gameTask = taskMgr.doMethodLater(0.5, self.simulationTask, "simulationTask", extraArgs = [self.sheep00], appendTask=True)

    ##end init
    
    def simulationTask(self, sheepObj, task):
        Environment.space.autoCollide() # Setup the contact joints
        Environment.world.quickStep(globalClock.getDt())            
        sheepObj._sheep.setPosQuat(render, sheepObj._sheepBody.getPosition(), Quat(sheepObj._sheepBody.getQuaternion()))
        Environment.contactgroup.empty() # Clear the contact joints
        return task.cont
    ##end simulationTask
    
#main loop    
World()
run()

thanks again

[
when I attaching a odebody to an actor, it seemed impossible to control the actor’s hpr by method setHpr(). I only can use the odebody method setRotation() to do the rotation but still can get the angle by actor method getH().Is it a rule or something?
]

If you decide to use Ode, it means you shall give most of the control of your objects to Ode and let Ode to do all the position updates for you. In your Ode simulation task:
sheepObj._sheep.setPosQuat(render, sheepObj._sheepBody.getPosition(), Quat(sheepObj._sheepBody.getQuaternion()))

You actually synchronize your Ode result to your Panda object in each time step.

Usually you can influence your object by:

  • setForce on it,
  • or calling corresponding Ode API,
  • or you set the position of your Panda object, then synchronize this to Ode before the simulation task quickstep.

[When I dragging the window, charactor with an odebody shaked like a tumbler, make everything a little naughty. Is there a way to tackle this? ]
You run your simulation task as:
Environment.world.quickStep(globalClock.getDt())
When you drag the Panda window, your task loop will be stopped. After you finish the dragging, the globalClock.getDt() shall be quite large. The Ode simulation task will catch up this time difference so you see an abnormal effect.
The quickest and dirty way for you to fix this problem is to set a max for the Environment.world.quickStep call.

[
and in the code below, I got a very weird problem. In this program, I wanted to control a charactor to do some performence like running, jumping, and some animation. others looked fine, but the “running part"did not. In the “running part” I intended to control the charactor to run in several velocities and whin max and min range by using “arrow_up” and " arrow_down”. I used some global virables to act like constants, and give it to the keyMap dictionary. unexpectedly those “constants” changed when I give it to variables. I know it’s stupid, but I can’t find where I reset those “constants”.
]

A variable that you have not touched will not modified itself. But I am at 1.5.4 and have no 1.6.0 installed, so can’t help at this moment.

But if you think the SHEEP* constants are changed, why don’t you remove them all together and directly put the constants in your program ?

clcheung

thanks for your answers

the 2ed question I rewrite it like this, every thing looks normal again

Environment.world.quickStep(min(globalClock.getDt(),FRAME_DELTA_TIME))

the 3rd question

I just want it be a little more project oriented, since I am a newbie I have to make it more easy to understand and do things according to textbook.~~

anyway, I did what you said, everything goes fine now, thank you

Yes, usually it is better not to hard code. I just suggest you a quick and dirty fix.