more trouble exposing joints

so I played a dummy animation on my entire scene so I could expose joints where I want to place objects. It works great with both my rock class and my spike class, but when I try it with my Pit class, it doesn’t work.

Basically, i had my modeler place joints at the corners of the pit so I could create a collision polygon between those points. Exposing the joints seems to work, because when I print the joint I get a different NodePath. But all the positions are always at (0,0,0).

here’s my code:


 def exposeJoints(self, task):

        # for each rock, we need to expose the joint, and create a collision sphere at the pos of the joint
        for i in range (1,744):
            rockName = "Rocks1:r" + str(i)
            self.rockJoint = self.tube.exposeJoint(None,"modelRoot",rockName ) 
            self.rockModel = Actor.Actor("models/Ice2.egg", {'shatter' : "models/Ice2-Shatter"} )

            self.rock = Rock(self.rockJoint, self.rockModel, i, self)
            self.rocks[i] = self.rock

for i in range (1,13,4):

            self.pitCorner1 = self.tube.exposeJoint(None, "modelRoot", 'hole'+str(i))
            i = i+1

            self.pitCorner2 = self.tube.exposeJoint(None, "modelRoot", 'hole'+str(i))
            i = i+1

            self.pitCorner3 = self.tube.exposeJoint(None, "modelRoot", 'hole'+str(i))
            i = i+1

            self.pitCorner4 = self.tube.exposeJoint(None, "modelRoot", 'hole'+str(i))

        self.pit = Pit(self.pitCorner1, self.pitCorner2, self.pitCorner3, self.pitCorner4, self)
        self.pits[i] = self.pit

And here’s my rock class:


class Rock(DirectObject):

    def __init__(self, joint, model, num, w):

        self.model = model
        self.num = num
        self.joint = joint

        self.model.reparentTo(self.joint)

        self.rockSphere = CollisionSphere(0, 0, 0, 1.7) 
        self.rockSphereNodePath = self.model.attachNewNode(CollisionNode('rock'+str(self.num) ) )
        
        self.rockSphereNodePath.node().addSolid(self.rockSphere)
        #self.rockSphereNodePath.show()

and finally my pit class:


class Pit(DirectObject):

    def __init__(self, p1, p2, p3, p4, w):

        pos1 = render.attachNewNode('pos1')
        pos1.reparentTo(p1)

        pos2 = render.attachNewNode('pos2')
        pos2.reparentTo(p2)

        pos3 = render.attachNewNode('pos3')
        pos3.reparentTo(p3)

        pos4 = render.attachNewNode('pos4')
        pos4.reparentTo(p4)
        
        print pos1
        print pos2
        print pos3
        print pos4
        
        self.collisionPoly = CollisionPolygon(pos1.getPos(), pos2.getPos(), pos3.getPos(), pos4.getPos())
        self.collisionNodePath = render.attachNewNode(CollisionNode('pit')) 
        self.collisionNodePath.node().addSolid(self.collisionPoly)

        self.collisionNodePath.show()

Any suggestions for saving the positions of the pit corner nodes? I think the reason the rocks and spikes work is that I have a concrete model to reparent to the exposed spike node, and in the pit example I do not. But I make a dummy node for each corner in the pit class, so I thought I covered this case.

Any help?

Thanks in advance,

Adam

When you get a NodePath’s position via, e.g. pos1.getPos(), you are returning the local position of that NodePath relative to its parent. In this case, it’s always (0, 0, 0) because you created those NodePaths, pos1, pos2, pos3, and pos4, and did not set their local positions to anything in particular.

What you really want to be querying is the object’s net position, which is its position relative to render, or in other words its position in world space. Try pos1.getNetTransform().getPos() for this.

I tried that, but I’m still getting (0,0,0) for the point. I even tried to print self.pitCorner1.getNetTransform.getPos() right after I created the nodePath to see what the position was, but I got (0,0,0) and I know for a fact that these joints are not at (0,0,0).

Not sure what to do here…I don’t understand why this worked for the rocks and spikes, and not for pits.

edit: typo, i meant pitCorner1.getNetTransform().getPos()

still getting (0,0,0)

It may also be that at the time you construct the object, it has not yet played the default animation yet, so all of the joints you expose are still at the origin (they will move when the animation plays the first time, which will occur when it is rendered). This would be why your rocks work, since you are parenting them to the joints, and they will move when the joints move.

You can call self.tube.update() to force the actor to update immediately. But there is a sequencing issue: you should create the Actor, bind the animation, expose all of the joints, then call self.tube.update() once, and then extract the positions of the joints.

I realize this seems like a lot of hard work to do something that should be simple, and I agree–but part of the problem is that you are exporting your scene as an animated character and using the Actor interface to expose key locations in your scene, which is not the way that animated characters were intended to be used. Are you sure that this is the way you want to do it? It only makes sense if you will be animating these positions at runtime, and even then it might not be the best way to do it.

David

I would change the way it’s done, but the mini game is due tomorrow morning, so as long as it works, I’m happy =)

I appreciate your help immensely though, and I will definitely used the sceneGraph searching feature next time instead of exposing the joints on the world

ok i used self.tube.update() and i got the pits to draw, but I think they are overwriting eachother. I only see a collision polygon where the first pit should be. It’s probably a stupid mistake, but I can’t seem to find it.

Here’s my code:


        for i in range (1,36,4):

            self.pitJoint1 = self.tube.exposeJoint(None, "modelRoot", 'hole'+str(i))
            self.pitJoint2 = self.tube.exposeJoint(None, "modelRoot", 'hole'+str(i+1))
            self.pitJoint3 = self.tube.exposeJoint(None, "modelRoot", 'hole'+str(i+2))
            self.pitJoint4 = self.tube.exposeJoint(None, "modelRoot", 'hole'+str(i+3))

            self.tube.update()

            pos1 = self.pitJoint1.getPos()
            pos2 = self.pitJoint2.getPos()
            pos3 = self.pitJoint3.getPos()
            pos4 = self.pitJoint4.getPos()

            pit = Pit(pos1, pos2, pos3, pos4, self, i)
            self.pits[i] = pit


class Pit(DirectObject):

    def __init__(self, p1, p2, p3, p4, w, num):

        self.collisionPoly = CollisionPolygon(p1, p2, p3, p4)
        self.collisionNodePath = render.attachNewNode(CollisionNode('pit'+str(num) ) ) 
        self.collisionNodePath.node().addSolid(self.collisionPoly)

        self.collisionNodePath.show()

I appreciate your help a lot =)

Thanks in advance,

-Adam

edit:

I inserted print statements to check out the positions of self.pitJoint1, 2, 3, and 4 and I’m getting the right coordinates for the first pit, but for all other pits I’m getting (0,0,0) for the coords for each corner.

Maybe this will help. I’m not sure why this would happen.

Are you exposing all the joints before the first call to update()? The problem is that update() is smart, and it won’t do anything the second time you call it if the animation hasn’t changed. So if you expose a joint and call update(), it works on that joint. But then if you expose another joint and call update(), it figures nothing has changed, and it doesn’t work on the second joint.

You have to expose all of the joints first, and then call update() exactly once.

David

ahhh I see. Yeah I have update in a loop, so that explains why it works for the first one and not for any other ones. So would you suggest I store the joints in each instance of the pit class, then once I get all the instances done, call update, and then place all the collision polys in another loop?

Yep, that’s what I’d suggest. :slight_smile:

David