[SOLVED] Bullet - Push player out of walls

Hi all,
Sorry that this is the second stupid beginner question I have to ask, but I just don’t get this right. I attempt to implement a player controller and don’t want to use the standard one (for various reasons, of which my ego may be a not unimportant one). My code insofar is as follows:

def moveWithCollision(self, target, n=0):
	if n == 10:
		#give up, don't move at all
		return
	oldPos = self.node.getPos()
	r = base.physicsWorld.rayTestClosest(oldPos, target)
	if not r.hasHit(): 
		self.node.setPos(target)
	else:
		oldMove = target - oldPos
		#move to a point outside the wall instead
		newTarget = r.getHitPos() + r.getHitNormal() 
		newMove = newTarget - oldPos
		if newMove.length() > oldMove.length():
			#don't move faster than desired
			newMove /= (newMove.length() / oldMove.length())
			newTarget = oldPos + newMove
		#check whether there are new collisions on the way to the target
		self.moveWithCollision(newTarget, n + 1)

However, there are various issues with this approch. First, the proximity the player can have to the wall is framerate dependent. Second, if the player approaches the wall in a steep angle, he can go as near to the wall as he wants, as the code only checks for collisions in front of him.

Both problems could as far as I understand be remedied by putting a BulletGhostNode around the player and then checking whether the ghost collides with some object, and if it does, push it away from the object. However, I don’t know how this can be implemented as I don’t find any way of determining in what direction of the player a collision occured. If I was using Panda’s vanilla collision system, I could just call entry.getSurfacePoint() and then move the player in the opposite direction of the surface point. How can I obtain similar information using Bullet? Or should I use a totally different approach?

Just an idea (not sure if this is the most elegant way, or even if it is sufficient): You could use the “sweep” test API (e.g. world.sweepTestClosest). This “moves” a shape from an original transform to a new transform, and checks for collisions on the way. The result returned by a sweep test has hit pos and normal.

Thank you enn0x, that definitely gave me the right direction. I first tried to only change the ray test to a sweep test, but that didn’t work for the reason I tried to draw here:

The first picture shows how it worked using rays, and the second picture shows how it not works using moving spheres. The problem is that when the sphere/capsule is already touching the wall, it can’t move into the wall’s direction at all and therefore even in the case of the moving direction being 99% along the wall, no movement at all would occur.

I realized I couldn’t solve this without resorting to maths (yuck!). The working code does now use vector projection to find the part of the movement that I do not want to do because it would push me into the wall, subtracts that from the overall movement and therefore calculates the correct movement (along the wall).

def moveWithCollision(self, targetPos, n=0):
	if n == 10:
		#give up, don't move at all
		return
	oldPos = self.node.getPos()
	r = base.physicsWorld.sweepTestClosest(
		self.shape,
		TransformState.makePos(oldPos),
		TransformState.makePos(targetPos),
		1)
	if not r.hasHit(): 
		self.node.setPos(targetPos)
	else:
		moveVector = targetPos - oldPos
		#project move onto normal
		normal = r.getHitNormal()
		normalUnit = normal / normal.length()
		projected = normal * (moveVector.dot(normalUnit))
		#subtract projected vector from move
		newMove = moveVector - projected
		#move along newly calculated vector
		self.moveWithCollision(oldPos + newMove, n + 1)

Bullet developers made a beautiful engine and a good abstraction model for it. ennox made a big work , integrating it in to Panda3D. We must value and respect this work.
I don’t see any reasons to ignore their work, invent a wheel again and move objects by yourself. Just create rigid body, reparent character to in and use forces to control your rigid - it’s much easier and logical in my opinion.

For slow object moving use bulletPhysics in manual. And for moving fast objects use Ccd option. (see examples)

If you want explicitly move objects in position you want, I think you can just reduce speed to 0, add force to rigid body equal to (deltaPos * mass ) for one frame. Using Ccd option of course. And then, if you want reduce speed again to 0.

P.s. Sorry for my English

It seems so, but it’s not. A walking human is a different case than an inert rigid body. It needs to behave in a conscious way, which requires putting a lot of artificial constrains on the rigid body. Sometimes you need infinite friction, other times you may need no friction. You don’t want your humans to bounce off of walls or floors, and you don’t want them to rocket into the sky when approaching stairs too fast.

There’s a reason why the only successful Dynamic Character Controller is the one in Havok, and why PhysX uses a Kinematic one. The dynamic approach just creates more problems than it solves, even if that seems a bit counter intuitive. You would think that keeping a capsule upright and pushing it around is all you need, but, again, a human is not a ball or a crate.

Makeing a dynamic character controller is indeed very tricky. I don’t want to say that kinematic character controllers are easy - just much easier than dynamic ones.

However, PhysX ships with the source code of their character controllers, even though they rest of their code is closed-source (unless you pay much money). The reason is that especially for character controllers there is no such things a “one size fits all”. It’s good to have a working start point, but being able to modify it comes handy in most games.

So I don’t see a problem with attempting to implement additional character controllers for Bullet. The one provided by the Panda3D Bullet module just wraps the default one provided by Bullet, which is incomplete and quite new to the Bullet codebase. For example interaction between the controller and dynamic objects is not implemented so far in the Bullet CC. Something I consider VERY important.

I even appreciate this attempt to roll your own CC. Even more if you can contribute the leassons you leard, and thus help us improving the CC in the Panda3D Bullet module.