Mini DoomLike and CollisionHandlerPusher problems

Hi everybody,
i’ve some problems with the CollisionHandlerPusher.

Here is the code :

from direct.showbase.ShowBase import ShowBase
from direct.gui.OnscreenText import OnscreenText
from panda3d.core import *
import sys

CAMERA_MOVEMENT_SPEED = 2
CAMERA_MOUSE_ROTATION_SPEED = 80
CAMERA_ROTATION_UPDOWN = 50
CAMERA_HEIGHT = 6

COLLIDE_PLAYER_MASK = 2 
COLLIDE_PLAYER_GROUND_MASK = 4 
COLLIDE_PLAYER_INTERACTIVE_MASK = 8 

class MyApp(ShowBase):
	def __init__(self):
		ShowBase.__init__(self)
		render.setShaderAuto()
		base.setFrameRateMeter(True) 
		
		self.textObject = OnscreenText(text = 'Loading, please wait...', pos = (0.8, -0.8), fg = (1,1,1,1))	
		
		# World / Physics
		base.cTrav = CollisionTraverser() 
		base.cTrav.setRespectPrevTransform(True) #modif word
		base.pusher = CollisionHandlerPusher()
		#base.cTrav.showCollisions(render)
		
		self.cameraMoveX = 0
		self.cameraMoveY = 0
		
	def startGame (self, task):	
		
		# Load the environment model.
		self.map = self.loader.loadModel("models/map")
		#self.map.setTwoSided(True)
		
		self.map.reparentTo(render)
		self.map.setCollideMask(BitMask32(COLLIDE_PLAYER_MASK|COLLIDE_PLAYER_GROUND_MASK)) # modif word
		
		#player
		height = 1.75
		radius = 0.4
		self.player = render.attachNewNode("player")  #modif word
 		self.player.setPos(base.camera.getPos())
		
		# Set Light attached to player
		dlight = DirectionalLight('dlight')
		dlight.setColor(VBase4(0.1, 0.1, 0.1, 1)) 
		self.playerLight = render.attachNewNode(dlight)
		self.map.setLight(self.playerLight)
		self.playerLight.reparentTo(base.camera)
		
		# and an ambient light too
		alight = AmbientLight('alight')
		alight.setColor(VBase4(0.85, 0.85, 0.85, 1))
		alnp = render.attachNewNode(alight)
		render.setLight(alnp) 		
		
		#---physics
		#Walls
		cn = self.player.attachNewNode(CollisionNode('player_collision')) #modif word
		cn.node().addSolid(CollisionSphere(0, 0, 0, 1.8)) #modif word
		cn.node().setFromCollideMask(BitMask32(COLLIDE_PLAYER_MASK))
		cn.node().setIntoCollideMask(BitMask32.allOff())
		self.pusher = CollisionHandlerPusher()
		self.pusher.setHorizontal(True)
		base.cTrav.addCollider(cn, self.pusher) #modif word
		self.pusher.addCollider(cn, self.player, base.drive.node()) #modif word
		
		#Ground
		ground_cn = self.player.attachNewNode(CollisionNode('player_ground_collision'))
		ground_cn.node().addSolid(CollisionRay(0, 0, 1, 0, 0, -1))
		ground_cn.node().setFromCollideMask(BitMask32(COLLIDE_PLAYER_GROUND_MASK))
		ground_cn.node().setIntoCollideMask(BitMask32.allOff())
		self.groundLifter = CollisionHandlerFloor()
		self.groundLifter.setOffset(height*3)
		self.groundLifter.addCollider(ground_cn, self.player)
		base.cTrav.addCollider(ground_cn, self.groundLifter) #modif word
		
		base.camLens.setFov(60)
		base.camLens.setNear(0.9)
		base.camera.reparentTo(self.player)		
	
		self.accept("q", self.mouvement, ['left'])
		self.accept("q-up", self.mouvement, ['left_stop'])
		self.accept("d", self.mouvement, ['right'])
		self.accept("d-up", self.mouvement, ['right_stop'])
		self.accept('z', self.mouvement, ['forward'])
		self.accept('z-up', self.mouvement, ['forward_stop'])
		self.accept('s', self.mouvement, ['backward'])
		self.accept('s-up', self.mouvement, ['backward_stop'])
		self.accept('+', self.screencpy)
		self.accept("escape", sys.exit)   		
		
		self.textObject.destroy()
		base.disableMouse()
		self.updateTask = taskMgr.add(self.update, "update_world")
	
	def screencpy(self):
		base.screenshot('screenshot')
	
	def mouvement(self, dirs):
		if dirs == 'left':
			self.cameraMoveX = -1
		elif dirs == "left_stop" and self.cameraMoveX == -1:
			self.cameraMoveX = 0
		elif dirs == "right":
			self.cameraMoveX = 1
		elif dirs == "right_stop" and self.cameraMoveX == 1:
			self.cameraMoveX = 0
		elif dirs == 'forward':
			self.cameraMoveY = 1
		elif dirs == 'forward_stop' and self.cameraMoveY == 1:
			self.cameraMoveY = 0
		elif dirs == "backward":
			self.cameraMoveY = -1
		elif dirs == "backward_stop" and self.cameraMoveY == -1:
			self.cameraMoveY = 0
		
	def update (self, task):
		if not hasattr(task, "last_time"):
			task.last_time = 0	
		delta = task.time - task.last_time
		task.last_time = task.time
		
		if base.mouseWatcherNode.hasMouse():
			wp = base.win.getProperties()
			cameraRotZ = -base.mouseWatcherNode.getMouseX() * CAMERA_MOUSE_ROTATION_SPEED
			cameraRotUp = base.mouseWatcherNode.getMouseY()* CAMERA_ROTATION_UPDOWN
			base.win.movePointer(0, wp.getXSize() / 2, wp.getYSize() / 2)   
			self.player.setHpr(self.player, cameraRotZ, 0, 0)  

			base.camera.setHpr(base.camera, 0, cameraRotUp, 0)
			if base.camera.getP() > 50:
				base.camera.setP(50)
			if base.camera.getP() < -50:
				base.camera.setP(-50)

		self.player.setFluidX(self.player,float(self.cameraMoveX * CAMERA_MOVEMENT_SPEED))
		self.player.setFluidY(self.player, float(self.cameraMoveY * CAMERA_MOVEMENT_SPEED))
		#self.player.setX(self.player,float(self.cameraMoveX * CAMERA_MOVEMENT_SPEED))
		#self.player.setY(self.player,float(self.cameraMoveY * CAMERA_MOVEMENT_SPEED))
			
		return task.cont

app = MyApp()
taskMgr.doMethodLater(0.1, app.startGame, "start_game")
app.run()

and the egg file is here :
http://www.benicourt.com/bullet/models.rar
got an idea ? i’ve written a similar code for bullet, and it functions well… i don’t understand. It’s probably the egg file…

Salut,

My first idea was that the normals were all wrong. So I opened the blend file and… saw that they were good. Okay, good job :slight_smile:.

Then I saw that you enable the fluid motion on the traverser, that you use setFluidPos on the player, but you don’t use the CollisionHandlerFluidPusher. I tried with that, and yep, it worked a little bit better.

It’s hard to tell what’s going on because the world is 1 kilometer wide, the player is 1,8 m high but the camera is at his feet, and we run at a good 200 m/s on my machine (indeed, the speed doesn’t adapt to the framerate).

So I think that your problem is mostly a problem of scale. Once I placed the camera in the head, put the collision sphere in the middle of the body, and multiplied the speed by globalClock.getDt(), then I collide normally again. Of course I move super slowly because the map is enormous, and the texture is stretched to death so it feels funny, but it works. We don’t miss collisions anymore. I didn’t try ALL the walls, just a few, because it’s big!

I tried making the player 10 meters high, with a 5-meter-radius collision sphere, it would work too at 100 m/s.

Still, it’s not perfect. I keep having problems when squeezing between the floor and a very low ceiling.

I had problems with your mouselook by the way, doesn’t work for me when the game isn’t centered/maximized: the scene rotates on its own. I’ve got one that works if you want.

oh yes ! Thank you very much, it was that, use globalClock.getDt()with the speed. I don’t understand why, but it’s functional. Thank you.

This line

self.player.setFluidX(self.player,float(self.cameraMoveX * CAMERA_MOVEMENT_SPEED))

means that at each frame, you move the player by CAMERA_MOVEMENT_SPEED, which in your case equals 2.

Therefore, if the game runs at 100 fps, then the player moves at 2x100 = 200 meters/seconds. And if the game runs at 10 fps, then the player moves at 20 meters/seconds. That is NOT what we want. We want the player to move at the same speed on every computer.

This thing:

    globalClock.getDt()

is pretty much what you had done yourself by attaching a last_time on your task and computing the elapsed time since last frame. You don’t have to do it yourself, that’s what the globalClock is here for. But yeah, you were on the right track.

Now, why do we use it ? Because if the game runs at 100 FPS then dt = 0.01, one hundredth of a second. If the player walks at two meters per second, then it moves by 2 centimeters in a hundredth of a second which is the duration of that frame. That’s why we multiply CAMERA_MOVEMENT_SPEED by that dt.

I understand that, about framespeed. But, i don’t understand why the collision handler don’t function without. I’ve tested with a very slow speed (but without time clock) and the result was the same. With time clock, it functions well !

Oh ! Well, no clue, I never did without :p.