After posting all these screenshots and videos, we thought it would be nice to go a little bit deeper and share some code. What you see below is how we are making the camera follow the ball (don’t worry, some explanation will follow!):
camvec = self.ball.getPos() - base.camera.getPos()
camheight = camvec.getZ()
camvec.setZ(0)
camdist = camvec.length()
camvec.normalize()
if (camdist > 20.0):
base.camera.setPos(base.camera.getPos() + camvec * (camdist - 20))
elif (camdist < 15.0):
base.camera.setPos(base.camera.getPos() - camvec * (15 - camdist))
if (camheight > 0):
base.camera.setPos(base.camera.getPos() + Vec3(0, 0, camheight - 0))
elif (camheight < -3):
base.camera.setPos(base.camera.getPos() + Vec3(0, 0, camheight + 3))
self.ballPosHprDummy.setPos(self.ball.getPos())
self.ballPosHprDummy.setH(self.ball.getH())
dirVec = self.desiredCamPosDummy.getPos(render) - base.camera.getPos()
dirVec.setZ(0)
turnRate = 0.1
base.camera.setPos(base.camera.getPos() + dirVec * turnRate)
base.camera.lookAt(self.ball)
So what’s this mumbo-jumbo all about?
Let’s have a look at it step by step:
- First we get the vector pointing from the camera to the ball and store the difference in height between those two in camheight and camdist.
- The next part of the posted code is responsible for the camera following the player with a distance of at least 15 and 20 units at max (first if…elif statement). The second part makes the camera follow the ball on the z axis (which is up and down in Panda3D). What’s important here is that the camera is not directly set to the player’s height, which would give it an unnatural feeling – instead it starts matching the height when the given threshholds are surpassed.
- In the last part, we are using the ballPosHprDummy and desiredCamPosDummy NodePath objects to adjust the camera rotation with a slight delay. The desiredCamPosDummy is parented to ballPosHprDummy and (in our case) always 15 units behind ballPosHprDummy (the code to setup this hierarchy is not shown here). This can be used to get a vector from the camera’s current position to its desired position, which is then used to bump it a small part along this vector (influenced by turnRate) to get closer to the desired position. You may need to tweak the turnRate variable to adjust it to the turning speed of your game character!
Closing thoughts and notes:
This way to handle the camera may be a little hacky and will most definitely see some changes (just think of problems like the camera intersecting / getting occluded by objects) on our journey to the final version of the game, but as a drop-in solution for quickly testing our basic gameplay, it worked like a charm!
Also note that there may no need for something like the ballPosHprDummy in other kinds of games. We just were not able to parent desiredCamPosDummy directly to the ball, because it is spinning most of the time (Well, there was a short moment where we didn’t mind this that got us a little dizzy when starting the game…).