Collision rubber band effect

Newbie with a problem again…

All I’m trying to do is make it so that my free-flying camera has collision with the loaded egg file.

Collision IS working, however whenever I bump into the model, it doesn’t just stop me. It bounces me back. I can’t just slide along a wall. And if I have my camera solid (sphere) set to a radius like 1, I can even force myself through the wall.

I set up my App like this:

import direct.directbase.DirectStart
from pandac.PandaModules import *

from pandac.PandaModules import PandaNode,NodePath,Camera,TextNode
from pandac.PandaModules import Vec3,Vec4,BitMask32
from direct.gui.OnscreenText import OnscreenText
from direct.actor.Actor import Actor
from direct.task.Task import Task
from direct.showbase.DirectObject import DirectObject
import random, sys, os, math

def addInstructions(pos, msg):
	# Function to put instructions on the screen.
	return OnscreenText(text=msg, style=1, fg=(1,1,1,1),
			pos=(-1.3, pos), align=TextNode.ALeft, scale = .05, mayChange=True)

def addTitle(text):
	# Function to put title on the screen.
	return OnscreenText(text=text, style=1, fg=(1,1,1,1),
					pos=(1.3,-0.95), align=TextNode.ARight, scale = .07)
					
class App(DirectObject):
	def __init__(self):
		self.loadLevel()
		self.loadInstructions()
		self.initCamera()
		self.initControls()
		self.initCollision()
		
		taskMgr.add(self.mouseUpdate, 'mouse-task')
		taskMgr.add(self.move,"moveTask")
		self.prevtime = 0
		
	def loadLevel(self):
		#Load the first environment model
		self.environ = loader.loadModel("hl2c.egg")
		self.environ.reparentTo(render)
		self.environ.setScale(0.25,0.25,0.25)
		self.environ.setPos(-8,42,0)

		base.win.setClearColor(Vec4(0.5,0.8,0.8,1)) # black bg

		dlight = DirectionalLight('dlight')
		dlight.setColor(VBase4(0.9, 0.9, 0.9, 1))
		dlnp = render.attachNewNode(dlight)
		dlnp.setHpr(90, -30, 0)
		render.setLight(dlnp)

		colour = (0.6,0.8,0.8)
		expfog = Fog("Scene-wide exponential Fog object")
		expfog.setColor(*colour)
		expfog.setExpDensity(0.005)
		render.setFog(expfog)
		base.setBackgroundColor(*colour)
		
	def loadInstructions(self):
		# Post the instructions
		self.title = addTitle("Testing Stuff with Panda3D Engine")
		self.inst1 = addInstructions(0.95, "[ESC]: Quit")
		self.inst3 = addInstructions(0.90, "[W]: Run Camera Forward")
		self.inst4 = addInstructions(0.85, "[A]: Turn Camera Left")
		self.inst6 = addInstructions(0.80, "[S]: Step Camera Backward")
		self.inst7 = addInstructions(0.75, "[D]: Turn Camera Right")
		self.inst8 = addInstructions(0.65, "")
		
	def initCamera(self):
		camera = base.camera
		camera.setPos(-20,55,40)
		camera.setHpr(30.0, -30.0, 0.0)
		base.camLens.setFar(2000)
		
	def initControls(self):
		self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0, "cam-forward":0, "cam-back":0}
		self.accept( "escape" , sys.exit)	# Sets ESC key to close app
		self.accept("arrow_left", self.setKey, ["left",1])
		self.accept("arrow_right", self.setKey, ["right",1])
		self.accept("arrow_up", self.setKey, ["forward",1])
		self.accept("w", self.setKey, ["cam-forward",1])
		self.accept("a", self.setKey, ["cam-left",1])
		self.accept("d", self.setKey, ["cam-right",1])
		self.accept("s", self.setKey, ["cam-back",1])
		self.accept("arrow_left-up", self.setKey, ["left",0])
		self.accept("arrow_right-up", self.setKey, ["right",0])
		self.accept("arrow_up-up", self.setKey, ["forward",0])
		self.accept("w-up", self.setKey, ["cam-forward",0])
		self.accept("a-up", self.setKey, ["cam-left",0])
		self.accept("d-up", self.setKey, ["cam-right",0])
		self.accept("s-up", self.setKey, ["cam-back",0])
		base.disableMouse()	# Disable mouse controlled camera
		
	def initCollision(self):
		base.cTrav = CollisionTraverser()
		base.pusher = CollisionHandlerPusher()	
		
		cs = CollisionSphere(0, 0, 0, 3)
		cnodePath = camera.attachNewNode(CollisionNode('cnode'))
		cnodePath.node().addSolid(cs)
		base.pusher.addCollider(cnodePath,self.environ)
		base.cTrav.addCollider(cnodePath,base.pusher)
		
	def setKey(self, key, value):
		#Records the state of the arrow keys
		self.keyMap[key] = value

	def move(self, task):
		elapsed = task.time - self.prevtime
		feedback = str(camera.getPos())
		if (self.keyMap["cam-left"]!=0):
			strafe = camera.getNetTransform().getMat().getRow3(0)
			strafe.setZ(0)
			strafe.normalize()
			camera.setPos(camera.getPos() - strafe*(elapsed*35))
		if (self.keyMap["cam-right"]!=0):
			strafe = camera.getNetTransform().getMat().getRow3(0)
			strafe.setZ(0)
			strafe.normalize()
			camera.setPos(camera.getPos() + strafe*(elapsed*35))
		if (self.keyMap["cam-forward"]!=0):
			strafe = camera.getNetTransform().getMat().getRow3(1)
			#strafe.setZ(0) 	#comment this out for free fly camera 
			strafe.normalize()
			camera.setPos(camera.getPos() + strafe*(elapsed*55))
		if (self.keyMap["cam-back"]!=0):
			strafe = camera.getNetTransform().getMat().getRow3(1)
			#strafe.setZ(0)	#comment this out for free fly camera 
			strafe.normalize()
			camera.setPos(camera.getPos() - strafe*(elapsed*55))
		self.inst8.setText(feedback)
		# Store the task time and continue.
		self.prevtime = task.time
		return Task.cont
		
	def mouseUpdate(self,task):
		md = base.win.getPointer(0)
		x = md.getX()
		y = md.getY()
		if base.win.movePointer(0, base.win.getXSize()/2, base.win.getYSize()/2):
			camera.setH(camera.getH() -  (x - base.win.getXSize()/2)*0.1)
			camera.setP(camera.getP() - (y - base.win.getYSize()/2)*0.1)
		return Task.cont

	

#Run program
App()
run()

Thanks for your time and guidance!

There have been problems in the past with scales applied to collision solids having unfortunate effects on the collision itself.

Try flattening the scale onto the vertices by calling self.environ.flattenLight() after you call self.environ.setScale().

David

It didn’t help. I even commented out the scale and it’s still rubberbanding on me.

Maybe you can clarify something for me. How exactly does the pusher work? Does it allow the solid to move to the intersected point, detect collision, and then move you back to the last known unintersected point? Or does it look ahead to determine if the point will collide and reacting accordingly?

Neither, precisely. The object moves inside the collision (the pusher has no control over this). Then the collision traverser runs, and the pusher gets a chance to react, and it does so by pushing the object out to the nearest free point, which is not precisely the same as the last known good position.

Since this all happens during the space of a single frame, though, you never perceive the object within the collision, and the net effect is that of a smooth sliding over the surface. If you’re getting a rubber-band effect, something is wrong.

When the pusher operates on the camera, the timing of the tasks is important. It’s important that the sequence within a frame is: (a) update camera position, (b) perform collision tests, © render frame. If you get this wrong, for instance (a) perform collision tests, (b) update camera position, © render frame, then you will get a rubber-band effect, because you’ll see the camera within the wall for one frame before the collisions gets a chance to fix it.

You can check that you have the tasks in the right order. I think it should be, looking at your code, since Panda creates the collisionLoop task with sort 30, and the igLoop task with sort 50, so both of these should occur in that order after your own tasks, which are sort 0 by default. But you can print taskMgr to prove this.

Also you might want to call pusher.setHorizontal(False), if you don’t want collisions constrained to the XY plane.

Actually, looking at your code, I see that you are attaching self.environ to the pusher, not the camera. This means that you are actually pushing the environment out of the way of the camera. Is this what you had in mind?

David

AHA! I was wondering why the floor wasn’t colliding…

Errr no I intended the camera to move. :slight_smile: Ok I’m fixing that…

This must be what’s happening. Now that I’ve attached the camera to the pusher, it’s flickering. There is a smooth movement along the wall, but it’s like I’m seeing a flickering of two different positions. I’m a little confused about the task timing and how / where to control it. I guess I’ll scour the manual for more info on that.

Nope… that’s not it.

Something I’m noticing is that SOMETIMES it will hit and slide, but most time it warps to the other side of the face. And after hitting the wall enough I can actually get stuck in it and get the flickering effect.

Oh, that sounds like you’ve got two back-to-back collision polygons. Don’t do that, it really confuses the collision system, because it doesn’t know which way to push to get out of the wall. It’s much better to have at least a few feet of crawlspace between any two back-to-back walls.

David

Ahhhh I see. And now it works look at that. :slight_smile: Thanks David!

After looking at this a little deeper… it seems as though the culprit may be the way my egg files are being generated. I can get it to work now with someone else’s egg file, just not my own. I’m converting from SketchUp to .X file format to an EGG file and adding in the collision detection line, but from reading some other posts and noting that my code is working with other egg files but not my own, the culprit is probably somewhere in that file.

EDIT: Yes… that’s it. The extra polys are being exported. I’m not sure if it’s happening from SketchUp to .X or from .X to egg yet but that was definitely the problem. I guess I need to do a little more research. Maybe it’s just a matter of finding a better .X exporter or making modifications to the SketchUp plugin.