We're going to add two kinds of animation to our cycle. We'll make the discs at the front and rear of the cycle rotate in accordance with the throttle setting, and we'll make the cycle lean left and right when it turns. Because we don't want the CollisionRays
attached to the cycle to lean as well, we'll have to make accommodations for that.
CycleClass_00.py
in the Chapter09
folder. import
statements to give us access to Actors:
from direct.actor.Actor import Actor
setupVarsNPs()
method and look for the section where we use if
statements to position self.root
and load the correct model. That section looks like the following code:if(startPos == 1): self.root.setPos(5,0,0) self.cycle = loader.loadModel("../Models/RedCycle.bam") elif(startPos == 2): self.root.setPos(-5,-5,0) self.cycle = loader.loadModel("../Models/BlueCycle.bam") elif(startPos == 3): self.root.setPos(5,-10,0) self.cycle = loader.loadModel("../Models/GreenCycle.bam") elif(startPos == 4): self.root.setPos(-5,-15,0) self.cycle = loader.loadModel("../Models/YellowCycle.bam")
self.cycle = self.root.attachNewNode("Cycle") if(startPos == 1): self.root.setPos(5,0,0) self.model = loader.loadModel("../Models/RedCycle.bam") self.turret = loader.loadModel("../Models/RedTurr.bam") elif(startPos == 2): self.root.setPos(-5,-5,0) self.model = loader.loadModel("../Models/BlueCycle.bam") self.turret = loader.loadModel("../Models/BlueTurr.bam") elif(startPos == 3): self.root.setPos(5,-10,0) self.model = loader.loadModel("../Models/GreenCycle.bam") self.turret = loader.loadModel("../Models/GreenTurr.bam") elif(startPos == 4): self.root.setPos(-5,-15,0) self.model = loader.loadModel("../Models/YellowCycle.bam") self.turret = loader.loadModel("../Models/YellowTurr.bam") self.mounts = Actor("../Models/Mounts.egg") self.model.reparentTo(self.cycle) self.mounts.reparentTo(self.model) turretMount = self.mounts.exposeJoint(None, "modelRoot", "Turret") fdMount = self.mounts.exposeJoint(None, "modelRoot", "FrontDisc") rdMount = self.mounts.exposeJoint(None, "modelRoot", "RearDisc") self.fd = loader.loadModel("../Models/Disc.bam") self.rd = loader.loadModel("../Models/Disc.bam") self.turret.reparentTo(turretMount) self.fd.reparentTo(fdMount) self.rd.reparentTo(rdMount)
self.cycle
to self.root
. Delete that line and put the following two lines in its place:self.turning = None self.lean = 0
setupCollisions
. Look for the following line:self.shieldCNP = self.cycle.attachNewNode(self.shieldCN)
self.cycle
to self.model
so it looks like this:self.shieldCNP = self.model.attachNewNode(self.shieldCN)
cycleControl()
method and find the short block of code that turns the cycle according to user input. It looks like the following code:if(self.inputManager.keyMap["right"] == True): self.turn("r", dt) elif(self.inputManager.keyMap["left"] == True): self.turn("l", dt)
if(self.inputManager.keyMap["right"] == True): self.turn("r", dt) self.turning = "r" elif(self.inputManager.keyMap["left"] == True): self.turn("l", dt) self.turning = "l" else: self.turning = None
move()
method. Add the following code to the bottom of the method, right above the return
statement:currentLean = self.model.getR() if(self.turning == "r"): self.lean += 2.5 if(self.lean > 25): self.lean = 25 self.model.setR(self.model, (self.lean - currentLean) * dt * 5) elif(self.turning == "l"): self.lean -= 2.5 if(self.lean < -25): self.lean = -25 self.model.setR(self.model, (self.lean - currentLean) * dt * 5) else: self.lean = 0 self.model.setR(self.model, (self.lean - currentLean) * dt * 5) self.fd.setH(self.fd, 5 + (20 * self.throttle)) self.rd.setH(self.rd, -5 + (-20 * self.throttle))
destroy()
method and add these five lines right underneath the call to self.cycle.removeNode():
self.mounts.delete() self.model.removeNode() self.turret.removeNode() self.fd.removeNode() self.rd.removeNode()
CycleClass_01.py
and run WorldClass_00.py
from the command prompt. The other files for this chapter have already been updated to look for CycleClass_01.py
so we don't need to edit any of them.That brings some new life to our cycle! There's one thing we should talk about in this example that we haven't really discussed yet: the reason why we made self.cycle
an empty NodePath
and changed the model to be self.model
. Remember the CollisionRays
we made back in Chapter 6, The World in Action: Handling Collisions and how they are children self.cycle?
Well, when we lean the cycle during a turn, we don't want those CollisionRays
to lean with it, but the CollisionRays
still have to turn with the cycle so that the front ray stays in front and the back ray stays at the back. For all that to work out, we need to separate the turning from the leaning, and that's why we are using two NodePaths
now. Since we want the CollisionSpheres
for the shield to lean with the cycle, we made them children of self.model
instead of self.cycle
.