How to smooth CollisionHandlerPusher?

One collision node collides to another, and CollisionHandlerPusher() pushes it back. But - it pushes it to its previous position. So, the moving collision node bounces forward and back like crazy, instead of slowly sliding along the surface of the second node. How to smooth it?
(Imagine, I have camera parented to the moving node; it goes mad!)
Here is the test code and the egg.
Code:

import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.showbase.DirectObject import DirectObject
from direct.task.Task import Task
import sys

base.cTrav = CollisionTraverser()
pusher = CollisionHandlerPusher()

class Into():
    def __init__(self):
        self.collisionBox = loader.loadModel("collisionBox")
        self.collisionBox.reparentTo(render)
        self.collisionBox.setPos(0, 5, 0)
        self.collisionBox.setH(60)
        self.collisionBox.setScale(1.5)
        self.collisionBox.setCollideMask(BitMask32.bit(1))

class From(DirectObject):
    def __init__(self):
        self.fromNode = render.attachNewNode("fromNode")
        self.fromNode.setPos(0, 0, 0)
        self.fromColNode = CollisionNode("fromColNode")
        self.fromColNode.addSolid(CollisionSphere(0, 0, 0, 0.5))
        self.fromColNP = self.fromNode.attachNewNode(self.fromColNode)
        self.fromColNP.show()

        self.fromColNode.setCollideMask(BitMask32.bit(1))

        base.cTrav.addCollider(self.fromColNP, pusher)
        pusher.addCollider(self.fromColNP, self.fromNode)

        self.defineMovements()

    def defineMovements(self):
        self.accept("w", self.forward)
        self.accept("w-repeat", self.forward)
        self.accept("s", self.backward)
        self.accept("s-repeat", self.backward)

        self.accept("escape", sys.exit)

    def forward(self):
        self.fromNode.setPos(self.fromNode, 0, 0.1, 0)
        print "Forward"
    def backward(self):
        self.fromNode.setPos(self.fromNode, 0, -0.1, 0)
        print "Backward"

base.cam.setPos(0, 0, 20)
base.cam.lookAt(0, 0, 0)

intoO = Into()
fromO = From()

run()

The egg. Name is “collisionBox.egg”, and put to the same directory:

<CoordinateSystem> { Z-up }

<Comment> { "Egg laid by Chicken for Blender vR44" }

<Group> car-col {
  <Collide> { Polyset keep descent }
  <Transform> {
    <Matrix4> {
      1.000000 0.000000 0.000000 0.000000
      0.000000 0.000000 1.000000 0.000000
      0.000000 -1.000000 0.000000 0.000000
      0.000000 0.000000 0.000000 1.000000
    }
  }
  <VertexPool> car-col {
    <Vertex> 0 {
      2.31999993324 4.78000068665 3.27196502686
    }
    <Vertex> 1 {
      2.31999993324 4.78000020981 3.33753487212e-005
    }
    <Vertex> 2 {
      -2.32000041008 4.78000020981 3.36137673003e-005
    }
    <Vertex> 3 {
      -2.31999993324 4.78000068665 3.27196550369
    }
    <Vertex> 4 {
      2.3200006485 -4.77999973297 3.27196598053
    }
    <Vertex> 5 {
      -2.31999969482 -4.77999973297 3.27196645737
    }
    <Vertex> 6 {
      -2.32000017166 -4.78000020981 3.45739463228e-005
    }
    <Vertex> 7 {
      2.31999921799 -4.78000020981 3.38586905855e-005
    }
    <Vertex> 8 {
      2.31999993324 4.78000068665 3.27196502686
    }
    <Vertex> 9 {
      2.3200006485 -4.77999973297 3.27196598053
    }
    <Vertex> 10 {
      2.31999921799 -4.78000020981 3.38586905855e-005
    }
    <Vertex> 11 {
      2.31999993324 4.78000020981 3.33753487212e-005
    }
    <Vertex> 12 {
      2.31999993324 4.78000020981 3.33753487212e-005
    }
    <Vertex> 13 {
      2.31999921799 -4.78000020981 3.38586905855e-005
    }
    <Vertex> 14 {
      -2.32000017166 -4.78000020981 3.45739463228e-005
    }
    <Vertex> 15 {
      -2.32000041008 4.78000020981 3.36137673003e-005
    }
    <Vertex> 16 {
      -2.32000041008 4.78000020981 3.36137673003e-005
    }
    <Vertex> 17 {
      -2.32000017166 -4.78000020981 3.45739463228e-005
    }
    <Vertex> 18 {
      -2.31999969482 -4.77999973297 3.27196645737
    }
    <Vertex> 19 {
      -2.31999993324 4.78000068665 3.27196550369
    }
    <Vertex> 20 {
      2.3200006485 -4.77999973297 3.27196598053
    }
    <Vertex> 21 {
      2.31999993324 4.78000068665 3.27196502686
    }
    <Vertex> 22 {
      -2.31999993324 4.78000068665 3.27196550369
    }
    <Vertex> 23 {
      -2.31999969482 -4.77999973297 3.27196645737
    }
  }
  <Polygon> {
    <Normal> { -0.000000 1.000000 -0.000000 }
    <VertexRef> { 0 1 2 3 <Ref> { car-col } }
  }
  <Polygon> {
    <Normal> { 0.000000 -1.000000 0.000000 }
    <VertexRef> { 4 5 6 7 <Ref> { car-col } }
  }
  <Polygon> {
    <Normal> { 1.000000 -0.000000 -0.000000 }
    <VertexRef> { 8 9 10 11 <Ref> { car-col } }
  }
  <Polygon> {
    <Normal> { -0.000000 -0.000000 -1.000000 }
    <VertexRef> { 12 13 14 15 <Ref> { car-col } }
  }
  <Polygon> {
    <Normal> { -1.000000 -0.000000 0.000000 }
    <VertexRef> { 16 17 18 19 <Ref> { car-col } }
  }
  <Polygon> {
    <Normal> { 0.000000 0.000000 1.000000 }
    <VertexRef> { 20 21 22 23 <Ref> { car-col } }
  }
}

You’ve found a weakness in Panda’s collision system. It’s usually best to avoid situations like this, if you can. For instance, don’t put two collision walls facing to each other in close proximity. Wall off tight corners so your players can’t work themselves in tight spaces like that.

David

Well, it seams, my learning finally becomes hard :slight_smile:
Then I could try following:

  1. Replace CollisionHandlerPusher() with CollisionHandlerQueue().
  2. Find the direction of normal at the point of collision.
  3. Manually re-calculate the new position of a moving object using trigonometry functions, so that it slides along the surface.
    What do you think about it, David?
    If you think it’s good idea, then, please, could you be so kind as give few hints: how to find normal orientation at the point of collision? How to find radius of CollisionSphere attached to the moving object?
    Sorry that I ask so many questions before trying to implement it myself. Since I am just learning, implementing it would take a lot of time, and I want to be sure that I go in right direction.

EDIT: No need to help at the moment; I think I have figured this out :slight_smile:

Note that the CollisionHandlerPusher already does (2) and (3). It doesn’t push an object back to its previous position; it pushes it just enough to get it free of the current collision. When there is just one wall pushing on the object, this results in a nice, smooth, slide along the object’s surface.

But it gets complicated when you have multiple different walls all pushing on the same object at the same time. The CollisionHandlerPusher makes an attempt to do the “right” thing most of the time, but there are a few degenerate cases when it gets its knickers in a knot.

But, taking a closer look at your code, this isn’t what you’ve run into at all. You’ve run into a completely different limitation on the collision system: it doesn’t deal well with scales. For this reason, it’s best to avoid scales on your collision surfaces. You can use flattenLight() to apply scales to the vertices.

Try replacing your init function with this:

    def __init__(self):
        self.collisionBox = loader.loadModel("collisionBox")
        self.collisionBox.setScale(1.5)
        self.collisionBox.flattenLight()
        self.collisionBox.reparentTo(render)
        self.collisionBox.setPos(0, 5, 0)
        self.collisionBox.setH(60)
        self.collisionBox.setCollideMask(BitMask32.bit(1)) 

David

In my case it doesn’t make smooth movement. It pushes the object back to the previous position…

Have you tried flattening out the scale, as I suggested in the above post?

David

Flattened, still bounces…

I have removed scaling, it still bounces.

I have found: the from object collides into the the edge of the self.collisionBox. But anyway, even if it collides into the edge, why does it bounce?

Ah, yes, so that’s your problem: both the side and the bottom of the box are pushing back on your object, and so the object gets pushed twice. As long as you don’t collide right on the edge, it should be better. In your example, for instance, change your collisionBox position to:

        self.collisionBox.setPos(0, 5, -2)

This is one of those cases that the CollisionHandlerPusher tries to handle correctly, but doesn’t get right all the time. The problem is that sometimes when two walls are both pushing on an object, you want them both to apply (for instance, when you’re walking into a concave corner), and sometimes you want only one of them to apply (as in this example). It’s surprisingly difficult to get all the cases right.

The current CollisionHandlerPusher tries to compromise in favor of keeping things from getting stuck or from falling through walls, but it doesn’t always guarantee smooth behavior. Over the years, we’ve played with difficult variations on this algorithm, and this is the one that has made the most people happy most of the time.

I’m not saying it’s perfect–no doubt better algorithms are possible–but this is the one we’ve settled on so far.

David