Wall Collision Help

Hi everyone I have some questions about the wall collision. I read that I can use the pusher collision but I don’t understand how to do it properly and the examples are not very helpful on this point. My project (a game based on the roaming-ralph example) uses the ray collision for now but it only worked on the z axis (for the height). In fact I can see the ray and the surface point on the wall in panda3D when i launch the code, but I can still go through the wall.
That’s the code (I’m French sorry ^^’) :

Collisions

    self.cTrav = CollisionTraverser()

    self.FreddyGroundRay = CollisionRay()
    self.FreddyGroundRay.setOrigin(0, 0, 0.5)
    self.FreddyGroundRay.setDirection(0, -1, 0)
    self.FreddyGroundCol = CollisionNode('freddyRay')
    self.FreddyGroundCol.addSolid(self.FreddyGroundRay)
    self.FreddyGroundCol.setFromCollideMask(CollideMask.bit(0))
    self.FreddyGroundCol.setIntoCollideMask(CollideMask.allOff())
    self.FreddyGroundColNp = self.Freddy.attachNewNode(self.FreddyGroundCol)
    self.FreddyGroundHandler = CollisionHandlerQueue()
    self.cTrav.addCollider(self.FreddyGroundColNp, self.FreddyGroundHandler)

    self.FreddyGroundColNp.show()
    self.cTrav.showCollisions(render)

and

    self.cTrav.traverse(render)
    entries = list(self.FreddyGroundHandler.getEntries())
    entries.sort(key=lambda y: y.getSurfacePoint(render).getY())

    if len(entries) > 0 and entries[0].getIntoNode().getName() == "Coli":
        self.Freddy.setY(entries[0].getSurfacePoint(render).getY())
    else:
        self.Freddy.setPos(startpos)

Any help please ?

Here a pic if you want :


And I can give you the entire code if you want

First of all, the pusher is usually the right choice for handling player collisions with a wall. It will handle many difficult cases for you correctly, such as wall sliding. We’re happy to help out with whatever issues you might be running into with the CollisionHandlerPusher.

Furthermore, a ray is probably not the right choice for what you’re trying to do. A ray will only go in one direction, but will do so infinitely (it will register a collision with a wall very far away). A CollisionSphere might be a better choice.

But anyway, what your code is doing is first sorting all the collision hits by their Y position, and taking the one that comes first in the Y coordinates. I just want to point out that this also only works in a single direction; if you were moving in any of the 3 other directions, then it would be sorting it incorrectly.

What your handling code is actually doing is that if the ray finds any collision (with a node named “Coli”) at all (even if it is still far away), it is repositioning the player right “inside” that nearest wall. And if there is no such collision, it is positioning the player back to the starting position.

So I would even suggest that, if your player is not actually eratically teleporting as the code seems to be doing, that second bit of code might not be running at all. Try adding a print statement to see if this code is being run.

What you probably want to do (if you really don’t want to use the pusher) is to use a collision sphere, store the previous position in a variable, and if there is a collision, position the player back to this previous position.

If you really wanted to do a ray, the way to set this up would be to check that the distance between the player and the wall is less than a certain amount, and if so, prevent your player from moving in this direction (deactivating the control that does so).

1 Like

Thank you for your quick and instructive answer ! I admit that this part of the code was quite difficult for me to clearly understand… So i think i will try both CollisionSphere and the difference with the surface point (this is for an exam, so it will shows that i search different ways to solve my problems). I have still a question : what I have to put inside the CollisionSphere parameters exactly ?

The CollisionSphere takes a centre point and a radius.

The centre will probably just be (0, 0, 0) since you are going to parent it to your player, but you can offset it relative to your player; if you need it to be a unit higher than your player origin then it would be (0, 0, 1).

The radius will affect how close the player can get to the wall before the collision is triggered, basically. You want this to be large enough to avoid the possibility of “slipping” through cracks in the collision geometry, but small enough for the player to be able to get as close as desired to the walls.

So I suceed in applying the Sphere around the character but I didn’t manage how to edit his coordinates when the Sphere touches the wall.
For now I have this :


And my code :

self.cTrav = CollisionTraverser()
self.FreddyGroundHandler = CollisionHandlerQueue()
self.cTrav.showCollisions(render)
self.FreddyGroundSphere = CollisionSphere(0, 0, 0.5, 0.5)
self.FreddyGroundCol = CollisionNode(‘freddySphere’)
self.FreddyGroundCol.addSolid(self.FreddyGroundSphere)
self.FreddyGroundCol.setFromCollideMask(BitMask32.bit(0))
self.FreddyGroundCol.setIntoCollideMask(BitMask32.allOff())
self.FreddyGroundColNp = self.Freddy.attachNewNode(self.FreddyGroundCol)
self.cTrav.addCollider(self.FreddyGroundColNp, self.FreddyGroundHandler)
self.FreddyGroundColNp.show()

Hmm, by that code alone I can’t tell what you’re doing wrong.

What you probably want to do is store the previous coordinates of the player somewhere in your move task, before the movement occurs. Then, if you detect a collision, you can move the player back to those previous coordinates.

What you probably want to do is store the previous coordinates of the player somewhere in your move task, before the movement occurs

I did it, it’s called “startpos”.

Then, if you detect a collision, you can move the player back to those previous coordinates.

So I have to do something like :
startpos = player.getPos
if Collision detected between player and wall :
player.setPos(startpos)
Right ? Because I don’t know how panda3D will recognize the wall in my code

Yes, more or less: something like

self.startpos = player.getPos()

This should be done before the player is moved by the task (or whatever mechanims you have for moving the player), so that when a collision is detected, you can move the player back to the previous position.

If you are still having trouble with this, please show your entire code.

I DIT IT !!! YEAHHHH ! XD After 1 month of intensive research i suceed. Thank you very much !

2 Likes