moving the collision follow a card?(panda intergrate ode)

Hello, I fallow the sample in “Collision Detection with ODE”.
And I want to move the floor, so when the ball fall on the floor as i moving, the ball should roll to the edge of the floor, then fall again.
In order to let the floor to be movable, I made some change like this:

cm = CardMaker("ground")
cm.setFrame(-20, 20, -20, 20)
cm.setColor(0.1, 0.5, 0, 1)
ground = render.attachNewNode(cm.generate())
ground.setPos(0, 0, -1)
ground.lookAt(0, 0, -2)
groundGeom = OdeBoxGeom(space, 20, 20, 1)
groundGeom.setCollideBits(BitMask32(0x00000001))
groundGeom.setCategoryBits(BitMask32(0x00000002))
groundBody = OdeBody(world)
groundBody.setPosition(ground.getPos(render))
groundBody.setQuaternion(ground.getQuat(render))
groundGeom.setBody(groundBody)

I want make the collision solid follow the floor,but the balls fall through the floor. I can move the green floor, but it seem not the collision solid. Did I miss something?
Could someone tell me why? Thanks.

Hmm, don’t make the ground a very-thin box. That gives problems.
All you need to do to make the ground movable is to change the lines where the ground is created with this:

# Add a plane to collide with
cm = CardMaker("ground")
cm.setFrame(-20, 20, -20, 20)
ground = render.attachNewNode(cm.generate())
ground.setPos(0, 0, -1); ground.lookAt(0, 0, -2)
groundBody = OdeBody(world)
groundBody.setPosition(ground.getPos())
groundBody.setQuaternion(Quat(ground.getPos()))
groundGeom = OdePlaneGeom(space, Vec4(0, 0, 1, 0))
groundGeom.setCollideBits(BitMask32(0x00000001))
groundGeom.setCategoryBits(BitMask32(0x00000002))
groundGeom.setBody(groundBody)
boxes.append((ground, groundBody))

Yeah, it gets added to “boxes”, that might sound weird, but all that does is keep the position updated.
You can now move “ground” around. I didn’t test it, but it should work.

As you can see now the plane is affected by gravity as well, I think you can fix that by creating a joint that attaches it to the environment. (explained on the Joints page)

But I could be terribly wrong, I’m not an expert on ODE.

The floor doesn’t need to have an associated OdeBody since it’s not going to be physically simulated, an OdeBoxGeom should be enough. The problem of the ball falling through your BoxGeom might be related to the step resolution you’re using for the simulation, the delta time might be too fast so that the ball moves past the BoxGeom instead of colliding with your floor.

Here is my code, it’s kind of messy:

# -*- coding: utf-8 -*-
from direct.directbase import DirectStart
from pandac.PandaModules import OdeWorld, OdeSimpleSpace, OdeJointGroup
from pandac.PandaModules import OdeBody, OdeMass, OdeSphereGeom, OdePlaneGeom, OdeBoxGeom
from pandac.PandaModules import BitMask32, CardMaker, Vec4, Quat
from random import randint, random
from direct.task.Task import Task
from direct.showbase.DirectObject import DirectObject
import sys, os, math


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

# The surface table is needed for autoCollide
world.initSurfaceTable(1)
#odeWorld.setSurfaceEntry(surfaceID1, surfaceID2, mu, bounce, bounce_vel, soft_erp, soft_cfm, slip, dampen)
world.setSurfaceEntry(0, 0, 15, 0.5, 9.1, 0.9, 0.00001, 0.0, 0.002)

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

# Load the sphere
sphere = loader.loadModel("ping_ball")
#sphere.setTextureOff()

# Add a random amount of spherees
spherees = []
for i in range(randint(15, 30)):
  # Setup the geometry
  sphereNP = sphere.copyTo(render)
  sphereNP.setPos(randint(-10, 10), randint(-10, 10), 10 + random())
  sphereNP.setHpr(randint(-45, 45), randint(-45, 45), randint(-45, 45))
  # Create the body and set the mass
  sphereBody = OdeBody(world)
  M = OdeMass()
  M.setSphere(8, 1)
  
  sphereBody.setMass(M)
  sphereBody.setPosition(sphereNP.getPos(render))
  sphereBody.setQuaternion(sphereNP.getQuat(render))
  # Create a sphereGeom
  sphereGeom = OdeSphereGeom(space, 1)
  sphereGeom.setCollideBits(BitMask32(0x00000002))
  sphereGeom.setCategoryBits(BitMask32(0x00000001))
  #this will automatically reposition the geometry (collision solid) with regard to the position 
  #of the position of the related body in the OdeWorld.
  sphereGeom.setBody(sphereBody)
  spherees.append((sphereNP, sphereBody))

# Add a plane to collide with
cm = CardMaker("ground")
cm.setFrame(-20, 20, -20, 20)
cm.setColor(0.1, 0.5, 0, 1)
ground = render.attachNewNode(cm.generate())
ground.setPos(0, 0, -1)
ground.lookAt(0, 0, -2)
groundBody = OdeBody(world)
groundBody.setPosition(ground.getPos())
groundBody.setQuaternion(ground.getQuat())
groundGeom = OdeBoxGeom(space, 20, 20, 1)
groundGeom.setCollideBits(BitMask32(0x00000001))
groundGeom.setCategoryBits(BitMask32(0x00000002))
groundGeom.setBody(groundBody)

# Set the camera position
base.disableMouse()
base.camera.setPos(40, 40, 20)
base.camera.lookAt(0, 0, 0)


#move the floor
class World(DirectObject):
    
    def __init__(self):
        self.keyMap = {"forward":0}
        self.accept("escape", sys.exit)
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        taskMgr.add(self.move,"moveTask")

        # Game state variables
        self.prevtime = 0
        
    def setKey(self, key, value):
        self.keyMap[key] = value
        
    def move(self, task):
        elapsed = task.time - self.prevtime
            
        if (self.keyMap["forward"]!=0):
             
                
            ground.setX(ground, -elapsed*50)
            print "move"
                
            # Store the task time and continue.
        self.prevtime = task.time
        return Task.cont
w = World()




# The task for our simulation
def simulationTask(task):
  space.autoCollide() # Setup the contact joints
  # Step the simulation and set the new positions
  world.quickStep(globalClock.getDt())
  for np, body in spherees:
    np.setPosQuat(render, body.getPosition(), Quat(body.getQuaternion()))
  contactgroup.empty() # Clear the contact joints
  return task.cont
  
taskMgr.doMethodLater(0.5, simulationTask, "Physics Simulation")

run()

I don’t quite understand what “step resolution” is, Is the

world.quickStep(globalClock.getDt())

If so, I change it to

world.quickStep(globalClock.getDt() - 0.015)

but it didn’t work.
I am trying the “joint” way.

No, ZeroByte is probably right. He means you should simulate as explained on the page “Simulating the Physics Scene”.

@ZeroByte, without a body, how do you plan to move the geom around?

OdeGeom’s have their own setPosition functions so you can just move it around the world with that.

Yes, it works now :smiley: , don’t need to use “groundBody”, just set

groundGeom.setPosition( ground.getX(), ground.getY(), ground.getZ())

Thanks.
but when i move the floor, the ball on the floor didn’t spin, I am working on it. And I found out that boxes in the sample of Collision Detection with ODE looks like didn’t actually ‘touch’ the floor?