Thanks for the response.
I did have an “again” event pointing to the same method, and I tried adding a normalized copy of the collision depth multiplied by .01 to the collision depth to deal with imprecision, but still had the same problem. I’ve tried using a CollisionHandlerPusher, but for some reason it collides in the opposite direction of the stage mesh’s normals, which isn’t what I want of course.
So I got sick of dealing with events and decided to use a queue instead. It solved the problem of the player pushing through walls, at least at high framerates (they easily phase through the wall at 5 fps for instance, which is also a problem), but the player still bounces too far out of the wall. Here’s my entire update method for my character object, most of the relevant code is towards the end, starting with the comment “#Handle collision…”.
def update(self):
#Get time passed since last frame to calculate movement.
self.dt = self.clock.getDt()
movement = Vec3(0, 0, 0)
#Act based on the current state and choose the next state as necessary.
#RotatingLeft and RotatingRight are functionally identical to Standing, except for the spinning part.
#They just exist to activate different animations.
if self.state == "Standing":
self._chooseDirection()
if self.direction != 0:
self.request("Walking")
elif self.input.rotL and not self.input.rotR:
self.request("RotatingLeft")
elif self.input.rotR and not self.input.rotL:
self.request("RotatingRight")
elif self._isFalling():
self.request("Falling")
elif not self._isFalling():
movement += Vec3(0, 0, self.stagePoint.getZ() - self.facingObj.getPos().getZ())
self.actor.setHpr(0, 0, 0)
if self.state == "RotatingLeft":
self._chooseDirection()
if self.direction != 0:
self.request("Walking")
elif (not self.input.rotL and not self.input.rotR) or (self.input.rotL and self.input.rotR):
self.request("Standing")
elif self.input.rotR and not self.input.rotL:
self.request("RotatingRight")
elif self._isFalling():
self.request("Falling")
elif not self._isFalling():
movement += Vec3(0, 0, self.stagePoint.getZ() - self.facingObj.getPos().getZ())
self.facingObj.setHpr(self.facingObj, self.turnSpeed * self.dt, 0, 0)
self.actor.setHpr(0, 0, 0)
if self.state == "RotatingRight":
self._chooseDirection()
if self.direction != 0:
self.request("Walking")
elif (not self.input.rotL and not self.input.rotR) or (self.input.rotL and self.input.rotR):
self.request("Standing")
elif self.input.rotL and not self.input.rotR:
self.request("RotatingLeft")
elif self._isFalling():
self.request("Falling")
elif not self._isFalling():
movement += Vec3(0, 0, self.stagePoint.getZ() - self.facingObj.getPos().getZ())
self.facingObj.setHpr(self.facingObj, -self.turnSpeed * self.dt, 0, 0)
self.actor.setHpr(0, 0, 0)
#Walking and Backpedaling are functionally identical save for their animation and direction.
elif self.state == "Walking":
self._chooseDirection()
if self.direction == 0:
self.request("Standing")
elif self.direction >= 4 and self.direction <= 6:
self.request("Backpedaling")
elif self._isFalling():
self.request("Falling")
elif not self._isFalling():
movement += Vec3(0, 0, self.stagePoint.getZ() - self.facingObj.getPos().getZ())
#Based on which direction was chosen, set movement speed and direction
#as well as the actor's facing relative to the facing object.
if self.direction == 1:
movement += Vec3(0, -self.moveSpeed * self.dt, 0)
self.actor.setHpr(self.facingObj, 0, 0, 0)
if self.direction == 2:
movement += Vec3(-self.moveSpeed * .7071 * self.dt, -self.moveSpeed * .7071 * self.dt, 0)
self.actor.setHpr(self.facingObj, -45, 0, 0)
if self.direction == 8:
movement += Vec3(self.moveSpeed * .7071 * self.dt, -self.moveSpeed * .7071 * self.dt, 0)
self.actor.setHpr(self.facingObj, 45, 0, 0)
if self.direction == 3:
movement += Vec3(-self.moveSpeed * self.dt, 0, 0)
self.actor.setHpr(self.facingObj, -90, 0, 0)
if self.direction == 7:
movement += Vec3(self.moveSpeed * self.dt, 0, 0)
self.actor.setHpr(self.facingObj, 90, 0, 0)
#Rotate the character and view if the rotate button is held.
if self.input.rotL and not self.input.rotR:
self.facingObj.setHpr(self.facingObj, self.turnSpeed * self.dt, 0, 0)
if self.input.rotR and not self.input.rotL:
self.facingObj.setHpr(self.facingObj, -self.turnSpeed * self.dt, 0, 0)
elif self.state == "Backpedaling":
self._chooseDirection()
if self.direction == 0:
self.request("Standing")
elif self.direction < 4 or self.direction > 6:
self.request("Walking")
elif self._isFalling():
self.request("Falling")
elif not self._isFalling():
movement += Vec3(0, 0, self.stagePoint.getZ() - self.facingObj.getPos().getZ())
#Based on which direction was chosen, set movement speed and direction
#as well as the actor's facing relative to the facing object.
if self.direction == 5:
movement += Vec3(0, self.moveSpeed * self.dt, 0)
self.actor.setHpr(self.facingObj, 0, 0, 0)
if self.direction == 4:
movement += Vec3(-self.moveSpeed * .7071 * self.dt, self.moveSpeed * .7071 * self.dt, 0)
self.actor.setHpr(self.facingObj, 45, 0, 0)
if self.direction == 6:
movement += Vec3(self.moveSpeed * .7071 * self.dt, self.moveSpeed * .7071 * self.dt, 0)
self.actor.setHpr(self.facingObj, -45, 0, 0)
#Rotate the character and view if the rotate button is held.
if self.input.rotL and not self.input.rotR:
self.facingObj.setHpr(self.facingObj, self.turnSpeed * self.dt, 0, 0)
if self.input.rotR and not self.input.rotL:
self.facingObj.setHpr(self.facingObj, -self.turnSpeed * self.dt, 0, 0)
elif self.state == "Falling":
if not self._isFalling():
self.request("LandFreeze")
self._chooseDirection()
#Based on which direction was chosen, set movement speed and direction.
if self.direction == 1:
movement += Vec3(0, -self.airSpeed * self.dt, 0)
if self.direction == 2:
movement += Vec3(-self.airSpeed * .7071 * self.dt, -self.airSpeed * .7071 * self.dt, 0)
if self.direction == 8:
movement += Vec3(self.airSpeed * .7071 * self.dt, -self.airSpeed * .7071 * self.dt, 0)
if self.direction == 3:
movement += Vec3(-self.airSpeed * self.dt, 0, 0)
if self.direction == 7:
movement += Vec3(self.airSpeed * self.dt, 0, 0)
if self.direction == 5:
movement += Vec3(0, self.airSpeed * self.dt, 0)
if self.direction == 4:
movement += Vec3(-self.airSpeed * .7071 * self.dt, self.airSpeed * .7071 * self.dt, 0)
if self.direction == 6:
movement += Vec3(self.airSpeed * .7071 * self.dt, self.airSpeed * .7071 * self.dt, 0)
#Rotate the character and view if the rotate button is held.
if self.input.rotL and not self.input.rotR:
self.facingObj.setHpr(self.facingObj, self.turnSpeed * self.dt, 0, 0)
if self.input.rotR and not self.input.rotL:
self.facingObj.setHpr(self.facingObj, -self.turnSpeed * self.dt, 0, 0)
#Drop the bass.
movement += Vec3(0, 0, -self.fallSpeed * self.dt)
#Face the character forward relative to the camera.
self.actor.setHpr(self.facingObj, 0, 0, 0)
elif self.state == "LandFreeze":
movement += Vec3(0, 0, self.stagePoint.getZ() - self.facingObj.getPos().getZ())
self.timer -= self.dt
if self.timer <= 0:
self.request("Standing")
#Actually move the character based on its set movement.
self.facingObj.setPos(self.facingObj, movement)
#Handle collision...
self.collisionDepth = Vec3(0, 0, 0)
for i in range(self.collisionHandler.getNumEntries()):
entry = self.collisionHandler.getEntry(i)
#...with the stage.
if entry.getFromNodePath() == self.stageCollideSphere:
# Calculate collision depth.
fromNodePath = entry.getFromNodePath()
colSurfacePt = entry.getSurfacePoint(fromNodePath)
colInteriorPt = entry.getInteriorPoint(fromNodePath)
self.collisionDepth += colSurfacePt - colInteriorPt
if entry.getFromNodePath() == self.stageCollideLine:
self.stagePoint = entry.getSurfacePoint(render)
#Take the player out of walls, regardless of state.
self.facingObj.setPos(self.facingObj, self.collisionDepth)