ODE Physics Setup

I hate to ask and I have looked through the tutorial on setting up ODE physics. I need some clarification because when I tried to integrate the code with my code I got several errors and such.

My Goal:
Add gravity to the actorPanda so the panda falls…that’s it. I just need some help navigating through that ODE physics tutorial because they generate a box and procedurally texture it. I wish they would have just loaded a model instead of generating random cubes :frowning:

Thanks in advance and if someone could point me to a tutorial that maybe has this in there that would be great. (by tutorial I mean an example that uses ODE in the code)

here is my code ( I apologize in advance its really messy and I haven’t had time to clean it up. )

from math import pi, sin, cos
import math, sys
from pandac.PandaModules import Vec3, Vec4

from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from direct.actor.Actor import Actor
from direct.interval.IntervalGlobal import Sequence
from panda3d.core  import Point3
from pandac.PandaModules import OdeWorld, OdeSimpleSpace, OdeJointGroup
from pandac.PandaModules import OdeBody, OdeMass, OdeBoxGeom, OdePlaneGeom
from pandac.PandaModules import CardMaker, Quat
class Panda(ShowBase):
    def __init__(self):
               ShowBase.__init__(self)
               #setup gravity and physics world using ODE
               #gravity is standard earth gravity rounded two decimal places -9.81 units/second
#               self.world = OdeWorld()
#               self.world.setGravity(0,0,-9.81)
#               self.space = OdeSimpleSpace()
#               self.space.setAutoCollideWorld(self.world)
#               self.contactGroup = OdeJointGroup()
#               self.space.setAutoCollideJointGroup(self.contactGroup)
               
               
               self.environ = self.loader.loadModel("models/environment")
               self.environ.reparentTo(self.render)
               self.environ.setScale(0.25,0.25,0.25)
               self.environ.setPos(-8, 42, 0)
               
               self.pandaActor = Actor("models/panda-model", {"walk": "models/panda-walk4"})
               self.pandaActor.setScale(0.005,0.005,0.005)
               self.pandaActor.reparentTo(self.render)
               
               #ode stuff for the pandaActor
#               self.pandaActor.flattenLight()
#               self.pandaActorMass = OdeBody(self.world)
#               self.pandaActorMass.setMass(50,1,1,1)
               #ode physics setup simulation
#               taskMgr.add(self.simulateTask, "simulate physics")
               
               #------------------
               #Movement of character sections
               
               self.accept('w', self.walking_forward)
               self.accept('w-up', self.stop_walking_forward)
               self.accept('s', self.walking_backward)
               self.accept('s-up', self.stop_walking_backward)
               self.accept('a', self.turn, [ -1 ])
               self.accept('a-up', self.stopTurn)
               self.accept('d', self.turn, [ 1 ])
               self.accept('d-up', self.stopTurn)
               self.acceptOnce('escape', sys.exit)
               
               #------------------
#    def simulateTask(self, task):
#        self.space.autoCollide()
#        self.world.quickStep(globalClock.getDt())
#        self.pandaActor.setPosQuat(render, self.pandaActor.getPosition(), Quat(self.pandaActor.getQuaterion()))
#        self.contactGroup.empty()
#        return Task.cont
    def turn(self, direction):
        taskMgr.add(self.turnTask, 'turnTask', extraArgs = [ direction ])
    def turnTask(self, direction):
        self.pandaActor.setH(self.pandaActor.getH()-direction)
        return Task.cont
    def stopTurn(self):
        taskMgr.remove('turnTask')
        
    def walking_forward(self):
        self.pandaActor.loop("walk")
        taskMgr.add(self.walking_forward_task, 'walking_forward_task')
    def walking_forward_task(self, task):
        distance = 0.025
        angle = self.pandaActor.getH()*math.pi/-180
        correction = math.pi/2
        dx = distance * math.cos( correction + angle )  
        dy = distance * -math.sin( correction + angle )
        self.pandaActor.setPos( Vec3( self.pandaActor.getX( ) + dx, self.pandaActor.getY( ) + dy, 0 ) )
        return Task.cont  
    def walking_backward(self):
        self.pandaActor.loop("walk")
        taskMgr.add(self.walking_backward_task, 'walking_backward_task')
    def walking_backward_task(self, task):
        distance = 0.025
        angle = self.pandaActor.getH()*math.pi/-180
        correction = math.pi/2
        dx = distance * math.cos( correction + angle )
        dy = distance * -math.sin( correction + angle )
        self.pandaActor.setPos( Vec3( self.pandaActor.getX() - dx, self.pandaActor.getY() - dy, 0))
        return Task.cont
    def stop_walking_forward(self):
        self.pandaActor.stop()
        taskMgr.remove('walking_forward_task')
    def stop_walking_backward(self):
        self.pandaActor.stop()
        taskMgr.remove('walking_backward_task')
#    def stop_walking(self):
#        self.pandaActor.stop()
#        taskMgr.remove('walking_task')

app = Panda()
app.run()

I tried to fix the code you posted, but I can only do so much. I changed just enough so it doesn’t crash and you can see some effect. It also doesn’t really work. :open_mouth:

But making a character controller in ODE is a complex task I haven’t tackled yet. You need to apply movement to the OdeBody, not the NodePath. The NodePath should be purely a “slave” to the simulation task. It’s hard because physics bodies are meant to be pushed around by forces, not explicitly moved from point to point. And dragging along the ground against friction causes it to jump around a lot as you will see.

from math import pi, sin, cos 
import math, sys 
from pandac.PandaModules import Vec3, Vec4 

from direct.showbase.ShowBase import ShowBase 
from direct.task import Task 
from direct.actor.Actor import Actor
from panda3d.core  import Point3 
from pandac.PandaModules import OdeWorld, OdeSimpleSpace, OdeJointGroup 
from pandac.PandaModules import OdeBody, OdeMass, OdeBoxGeom, OdePlaneGeom
from pandac.PandaModules import CardMaker, Quat 

class Panda(ShowBase): 
    def __init__(self): 
        ShowBase.__init__(self) 
        #setup gravity and physics world using ODE 
        #gravity is standard earth gravity rounded two decimal places -9.81 units/second 
        self.world = OdeWorld()
        self.world.setGravity(0,0,-9.81)
        # you need these next two lines or it will CRASH
        self.world.initSurfaceTable(1)
        self.world.setSurfaceEntry(0, 0, 150, 0.0, 9.1, 0.9, 0.00001, 0.0, 0.002)
        self.space = OdeSimpleSpace()
        self.space.setAutoCollideWorld(self.world)
        self.contactGroup = OdeJointGroup()
        self.space.setAutoCollideJointGroup(self.contactGroup)
        
        self.environ = self.loader.loadModel("models/environment")
        self.environ.reparentTo(self.render)
        self.environ.setScale(0.25,0.25,0.25)
        
        # you need something to collide with as the ground or you will just fall through
        self.groundGeom = OdePlaneGeom(self.space, Vec4(0, 0, 1, 0))
        
        self.pandaActor = Actor("models/panda-model", {"walk": "models/panda-walk4"}) 
        self.pandaActor.setScale(0.005,0.005,0.005) 
        self.pandaActor.reparentTo(self.render) 
        
        # ODE STUFF
        pandaMass = OdeMass()      # <-- no need to store on self, the OdeBody will hold it
        pandaMass.setBox(50,1,1,1) # <-- this should match the shape of your OdeGeom
        self.pandaBody = OdeBody(self.world)
        self.pandaBody.setMass(pandaMass) # <-- THIS is what you pass to setMass
        pandaGeom = OdeBoxGeom(self.space, 1, 1, 1) # <-- doesn't really fit the panda, but whatever
        pandaGeom.setBody(self.pandaBody) # <-- again the OdeBody will hold the ref
        
        #ode physics setup simulation
        taskMgr.add(self.simulateTask, "simulate physics")
        
        #Movement of character sections 
        
        self.accept('w', self.walking_forward) 
        self.accept('w-up', self.stop_walking_forward) 
        self.accept('s', self.walking_backward) 
        self.accept('s-up', self.stop_walking_backward) 
        self.accept('a', self.turn, [ -1 ]) 
        self.accept('a-up', self.stopTurn) 
        self.accept('d', self.turn, [ 1 ]) 
        self.accept('d-up', self.stopTurn) 
        self.acceptOnce('escape', sys.exit) 
        
    def simulateTask(self, task): 
        self.space.autoCollide() 
        self.world.quickStep(globalClock.getDt()) 
        self.pandaActor.setPosQuat(render, self.pandaBody.getPosition(), Quat(self.pandaBody.getQuaternion()))
        self.contactGroup.empty()
        return task.cont
    def turn(self, direction): 
        taskMgr.add(self.turnTask, 'turnTask', extraArgs = [ direction ]) 
    def turnTask(self, direction): 
        self.pandaActor.setH(self.pandaActor.getH()-direction) 
        return Task.cont 
    def stopTurn(self): 
        taskMgr.remove('turnTask') 
        
    def walking_forward(self): 
        self.pandaActor.loop("walk") 
        taskMgr.add(self.walking_forward_task, 'walking_forward_task') 
    def walking_forward_task(self, task): 
        distance = 0.025 
        angle = self.pandaActor.getH()*math.pi/-180 
        correction = math.pi/2 
        dx = distance * math.cos( correction + angle )  
        dy = distance * -math.sin( correction + angle ) 
        self.pandaBody.setPosition( Vec3( self.pandaActor.getX( ) + dx, self.pandaActor.getY( ) + dy, 0 ) ) 
        return Task.cont  
    def walking_backward(self): 
        self.pandaActor.loop("walk") 
        taskMgr.add(self.walking_backward_task, 'walking_backward_task') 
    def walking_backward_task(self, task): 
        distance = 0.025 
        angle = self.pandaActor.getH()*math.pi/-180 
        correction = math.pi/2 
        dx = distance * math.cos( correction + angle ) 
        dy = distance * -math.sin( correction + angle ) 
        self.pandaBody.setPosition( Vec3( self.pandaActor.getX() - dx, self.pandaActor.getY() - dy, 0)) 
        return Task.cont 
    def stop_walking_forward(self): 
        self.pandaActor.stop() 
        taskMgr.remove('walking_forward_task') 
    def stop_walking_backward(self): 
        self.pandaActor.stop() 
        taskMgr.remove('walking_backward_task') 
#    def stop_walking(self): 
#        self.pandaActor.stop() 
#        taskMgr.remove('walking_task') 

app = Panda() 
app.run()

Thanks for the reply. Looking back on the my code I was like wow…did I code this? lol :slight_smile: in any case I’ve decided to use Bullet in order to complete my physics needs.