- Panda3d 1.7 Game Developer's Cookbook
- Christoph Lang
- 743字
- 2021-04-09 21:21:48
Making the camera smoothly follow an object
In this recipe you will learn how to program a simple camera system that follows an object smoothly, without giving the impression of being glued to the back of the target.
Getting ready
See the recipe Setting up the game structure to create the basic application framework for the following steps.
How to do it...
Let's build a third person camera system:
- Add this code to
Application.py
:from direct.showbase.ShowBase import ShowBase from direct.actor.Actor import Actor from panda3d.core import Vec3 from direct.interval.IntervalGlobal import * from FollowCam import FollowCam class Application(ShowBase): def __init__(self): ShowBase.__init__(self) self.world = loader.loadModel("environment") self.world.reparentTo(render) self.world.setScale(0.5) self.world.setPos(-8, 80, 0) self.panda = Actor("panda", {"walk": "panda-walk"}) self.panda.reparentTo(render) self.panda.setHpr(270, 0, 0) self.panda.loop("walk") self.walkIval1 = self.panda.posInterval(2, Vec3(-8, -8, 0), startPos = Vec3(8, -8, 0)) self.walkIval2 = self.panda.posInterval(2, Vec3(-8, 8, 0), startPos = Vec3(-8, -8, 0)) self.walkIval3 = self.panda.posInterval(2, Vec3(8, 8, 0), startPos = Vec3(-8, 8, 0)) self.walkIval4 = self.panda.posInterval(2, Vec3(8, -8, 0), startPos = Vec3(8, 8, 0)) self.turnIval1 = self.panda.hprInterval(0.5, Vec3(180, 0, 0), startHpr = Vec3(270, 0, 0)) self.turnIval2 = self.panda.hprInterval(0.5, Vec3(90, 0, 0), startHpr = Vec3(180, 0, 0)) self.turnIval3 = self.panda.hprInterval(0.5, Vec3(0, 0, 0), startHpr = Vec3(90, 0, 0)) self.turnIval4 = self.panda.hprInterval(0.5, Vec3(-90, 0, 0), startHpr = Vec3(0, 0, 0)) self.pandaWalk = Sequence(self.walkIval1, self.turnIval1, self.walkIval2, self.turnIval2, self.walkIval3, self.turnIval3, self.walkIval4, self.turnIval4) self.pandaWalk.loop() self.followCam = FollowCam(self.cam, self.panda)
- Add a new file to the project. Call it
FollowCam.py
. - Copy the following code to the file you just created:
from direct.showbase.ShowBase import ShowBase from panda3d.core import Vec3 class FollowCam(): def __init__(self, camera, target): self.dummy = render.attachNewNode("cam" + target.getName()) self.turnRate = 2.2 self.camera = camera self.target = target taskMgr.add(self.updateCamera, "updateCamera" + target.getName()) def updateCamera(self, task): self.dummy.setPos(self.target.getPos()) heading = self.clampAngle(self.dummy.getH()) turnDiff = self.target.getH() - heading turnDiff = self.clampAngle(turnDiff) dt = globalClock.getDt() turn = turnDiff * dt self.dummy.setH(heading + turn * self.turnRate) self.camera.setPos(self.dummy.getPos()) self.camera.setY(self.dummy, 40) self.camera.setZ(self.dummy, 10) self.camera.lookAt(self.target.getPos() + Vec3(0, 0, 7)) return task.cont def clampAngle(self, angle): while angle < -180: angle = angle + 360 while angle > 180: angle = angle - 360 return angle
- Press F6 to start the application. You should be able to see a panda walking in circles while the camera follows it:
How it works...
We use the constructor of our Application
class to set up the scene containing the walking panda and the background scenery. In the last line we create a new instance of our FollowCam
, which contains the camera tracking code that is the core of this recipe.
To make the FollowCam
work correctly and to be able to have multiple cameras follow different objects, we have to pass the camera we want to be updated and its target to the constructor, where we set up a few things we need for updating the camera. For example, we add a task that will call the updateCamera()
method each frame. Additionally, the target's name is appended to both the dummy object's and the task's names to avoid name clashes in the case where we need to use more than one FollowCam
instance. The dummy object is an invisible helper object that will help us to position the camera, as you will see in the following paragraphs.
The updateCamera()
method is where all the work is happening: We move the dummy to our target's current position and get its current heading. The heading angle (in degrees) is clamped to the range of values from 180 to 180. We do this to avoid the camera getting stuck or continuing to turn because of the ambiguous nature of angles.
In the next steps, we calculate the difference between the target's heading and that of our dummy object, which is also clamped to avoid the undesired results described in the previous paragraph. In the following lines we can find the explanation for the camera's smooth turning—every frame, the dummy object's heading converges towards the heading of the camera target just a little bit. This is intentional; as it is multiplied by the time it took to complete the last frame. Additionally, we can also influence how fast the camera turns by adjusting turnRate
.
In the final steps, the camera is first moved to the position of the dummy and then pushed away again along the dummy's local axis to its final position. After setting the camera's lookAt()
target, we are done!
There's more...
In this version, the camera only supports smooth turning for objects that only change their heading. Other rotation axes can be added rather easily, as they work exactly the same as the one presented in this recipe!
- 剪映短視頻剪輯零基礎一本通
- Photoshop 2022從入門到精通
- UG NX 12.0實例寶典
- Drools JBoss Rules 5.0 Developer's Guide
- Photoshop CC從入門到精通(全彩超值版)
- NHibernate 3.0 Cookbook
- BackTrack 5 Wireless Penetration Testing Beginner's Guide
- Midjourney商業設計完全教程
- 原片蛻變:Photoshop CC商業修圖必修課
- MATLAB在日常計算中的應用
- 企業微信公眾平臺開發實戰:再小的個體也有自己的品牌
- LaTeX論文寫作教程
- JBoss AS 5 Performance Tuning
- CorelDRAW 2018平面設計基礎教程(第3版)
- UG NX 12.0完全自學手冊(第4版)