[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] PyODE



I attached my little test from a year ago (I forgot to attach it to my first reply).  It's been a while since I looked at it, but I think your last value of the planes are wrong.  In my example they are:

frontwall = ode.GeomPlane(sp,normal=(0,0,1),dist=-1)
backwall = ode.GeomPlane(sp,normal=(0,0,-1),dist=-1)

Both are -1.  I forget the math, but the distance is basically moving the plane against the normal that amount.  So for the normal pointing into the screen, you want to move it OUT of the screen by 1, which is against the normal, hence the minus.  For the normal pointing out of the screen you want to move it IN - again against the normal, again -1.  This way you have two planes that are pointing toward each other keeping anything between them locked in.

What you had I think with the +1 and -1 was two planes with opposite normals located at the same z value.
import pygame
import ode

class colmesh:
    def __init__(self):
        self.mesh = None
        self.body = None
    def add_to_space(self,space):
        space.add(self.mesh)
    def addbody(self,body):
        if not self.body:
            self.body = body
        if self.mesh:
            self.mesh.setBody(body.body)
        if not self.body.mesh:
            self.body.addmesh(self)

class raymesh(colmesh):
    def __init__(self,pos,dir,length=1000):
        colmesh.__init__(self)
        self.pos = pos
        self.dir = dir
        self.length = length
        self.mesh = ode.GeomRay(None,self.length)
        self.mesh.set(self.pos,self.dir)

class TriMesh(colmesh):    
    def __init__(self,file):
        colmesh.__init__(self)
        f = open(file)
        verts,faces = eval(f.read())
        f.close()
        self.data = ode.TriMeshData()
        self.data.build(verts,faces)
        self.mesh = ode.GeomTriMesh(self.data,space)
        
class BoxMesh(colmesh):
    def __init__(self,dimensions=[1.0,1.0,1.0]):
        self.dimensions = dimensions
        colmesh.__init__(self)
        self.mesh = ode.GeomBox(None,dimensions)
        
class body(object):
    def __init__(self,colworld,pos=[0.0,0.0,0.0],mass=1.0,density=2500.0,sphere=None,box=None):
        self.body = ode.Body(colworld.wo)
        self.pos = pos
        self.mass = ode.Mass()
        if box:
            self.mass.setBox(density,*box)
        if sphere:
            self.mass.setSphere(density,sphere)
        self.mass.mass = mass
    def __setattr__(self,attr,val):
        object.__setattr__(self,attr,val)
        if attr == "pos":
            self.body.setPosition(val)
    def addmesh(self,mesh):
        self.mesh = mesh
        if not self.mesh.body:
            self.mesh.addbody(self)
        
class CollisionWorld:
    def __init__(self):
        self.sp = ode.Space()
        self.wo = ode.World()
        self.joints = ode.JointGroup()
    def addStatic(self,mesh):
        mesh.add_to_space(self.sp)
    def raytest(self,pos,dir):
        ray = raymesh(pos,dir)
        cols = []
        for geom in self.sp:
            cols.extend(ode.collide(ray.mesh,geom))
        highestz = None
        for c in [c.getContactGeomParams()[0] for c in cols]:
            if not highestz or c>highestz:
                highestz = c[2]
        if highestz:
            return highestz
    def step(self):
        def near_callback(args,geom1,geom2):
            contacts = ode.collide(geom1,geom2)
            for c in contacts:
                c.setBounce(0.2)
                c.setMu(5000)
                j = ode.ContactJoint(self.wo,self.joints,c)
                j.attach(geom1.getBody(),geom2.getBody())
        self.sp.collide(None,near_callback)

def step(sp,wo,joints):
    def near_callback(args,geom1,geom2):
        contacts = ode.collide(geom1,geom2)
        for c in contacts:
            param = c.getContactGeomParams()
##            if hasattr(geom1,"only_normal"):
##                if param[1] != geom1.only_normal:
##                    continue
            if hasattr(geom2,"only_normal"):
                if param[1] != geom2.only_normal:
                    continue
            c.setBounce(0.2)
            c.setMu(2000)
            j = ode.ContactJoint(args[0],args[1],c)
            j.attach(geom1.getBody(),geom2.getBody())
    for n in range(1):
        sp.collide((wo,joints),near_callback)
    wo.step(.005)
    joints.empty()
        
wo = ode.World()
wo.setGravity( (0,-9.81,0) )
wo.setERP(0.8)
wo.setCFM(1E-5)
sp = ode.Space()
joints = ode.JointGroup()
m1 = ode.Mass()
m1.setBox(2500.0,1.0,1.0,1.0)
box1body = ode.Body(wo)
box1body.setPosition([1,1,0])
box1body.setMass(m1)
box1mesh = ode.GeomBox(sp,lengths=[1,1,1])
box1mesh.setBody(box1body)
box2body = ode.Body(wo)
box2body.setPosition([1,3,0])
box2body.setMass(m1)
box2mesh = ode.GeomBox(sp,lengths=[1,1,1])
box2mesh.setBody(box2body)
floor = ode.GeomPlane(sp,normal=(0,1,0),dist=0)
frontwall = ode.GeomPlane(sp,normal=(0,0,1),dist=-1)
backwall = ode.GeomPlane(sp,normal=(0,0,-1),dist=-1)
ledge = ode.GeomBox(sp,lengths=[1,1,1])
ledge.setPosition([3,1,0])
ledge.only_normal = [0,1.0,0]

disp = pygame.display.set_mode([320,240],0,32)
square = pygame.Surface([32,32])
square.fill([255,0,0])
play = 1
while play:
    disp.fill([0,0,0])
    pos1 = [int(32*box1body.getPosition()[0]),-int(32*box1body.getPosition()[1])+200]
    pos2 = [int(32*box2body.getPosition()[0]),-int(32*box2body.getPosition()[1])+200]
    pos3 = [int(32*ledge.getPosition()[0]),-int(32*ledge.getPosition()[1])+200]
    #print pos1,box1body.getPosition()
    pygame.draw.rect(disp,[255,255,255],[pos1[0]-16,pos1[1]-16,32,32])
    pygame.draw.rect(disp,[255,0,255],[pos2[0]-16,pos2[1]-16,32,32])
    pygame.draw.rect(disp,[0,0,255],[pos3[0]-16,pos3[1]-16,32,32])
    pygame.draw.line(disp,[255,255,255],[0,200],[320,200])
    pygame.display.update()
    step(sp,wo,joints)
    pygame.event.pump()
    for evt in pygame.event.get([pygame.KEYDOWN,pygame.KEYUP]):
        if evt.key == pygame.K_ESCAPE:
            play = None
        if evt.type == pygame.KEYDOWN and evt.key == pygame.K_UP:
            box2body.addForce([0,3000000,0])
    k = pygame.key.get_pressed()
    force = 10000
    if k[pygame.K_RIGHT]:
        box2body.addForce([force,0,0])
    if k[pygame.K_LEFT]:
        box2body.addForce([-force,0,0])
    
pygame.quit()