A weapon that can't hit anything isn't much good to us. In order to hit things, we need to use collision detection. Let's go ahead and add collision detection to our MachineGun
class so we can shoot some things in the scene.
ExplosionClasses_01.py
.from direct.interval.IntervalGlobal import * import random
__init__
method as follows:class Pop: def __init__(self, pos): rand = random.randint(1,3) self.pop = loader.loadModel( "../Models/Explosions/Laserburst" + str(rand) + ".bam") self.pop.reparentTo(render) self.pop.setPos(pos) self.pop.find('**/+SequenceNode').node().play(0, 15) self.self = self self.seq = Sequence( Wait(.5), Func(self.destroy))
destroy()
method to clean up after the explosion is finished:def destroy(self): self.pop.removeNode() self.self = None return
GunClasses_01.py
.from ExplosionClasses_01 import *
__init__
method, right underneath our declaration of reloadTime:
self.damage = 10
self.firePar
so that it looks like the following code:self.firePar = Parallel( Func(self.checkForHit), Func(self.setEffects), self.flashLerp)
fire()
method. Remove the line that repositions self.refNP
; we won't need it anymore. clearEffects()
method. It will employ a CollisionRay
we're going to add to the Cycle
class to check if the laser hit anything.def checkForHit(self): self.cycle.trgtrCTrav.traverse(render) if(self.cycle.trgtrCHan.getNumEntries() > 0): self.cycle.trgtrCHan.sortEntries() entry = self.cycle.trgtrCHan.getEntry(0) colPoint = entry.getSurfacePoint(render) self.refNP.setPos(render, colPoint) pop = Pop(colPoint) thingHit = entry.getIntoNodePath() if(thingHit.hasPythonTag("owner")): thingHit.getPythonTag("owner").hit(self.damage) else: self.refNP.setPos(self.cycle.trgtrCNP, 0, 300, 0) pop = Pop(self.cycle.refNP.getPos(render))
GunClasses_02.py
. CycleClass_02.py
and update the imports to use the new file for our gun class. setupCollisions()
method:self.trgtrCN = CollisionNode(self.name + "_TargeterCN") self.trgtrRay = CollisionRay(0,0,0,0,1,0) self.trgtrCN.addSolid(self.trgtrRay) self.trgtrCN.setFromCollideMask(BitMask32.bit(3)) self.trgtrCN.setIntoCollideMask(BitMask32.allOff()) self.trgtrCNP = self.trgtrMount.attachNewNode(self.trgtrCN) self.trgtrCTrav = CollisionTraverser() self.trgtrCHan = CollisionHandlerQueue() self.trgtrCTrav.addCollider(self.trgtrCNP, self.trgtrCHan)
bump()
method since it's a similar sort of method to bump:def hit(self, damage): print(self.name + " has taken " + str(damage) + " damage!") return
destroy()
method and add the following line right under the line that removes gRayCNP
to clean up the new CollisionRay
we've created:self.trgtrCNP.removeNode()
CycleClass_03.py
. RaceClass_01.py
to use CycleClass_03.py
, and then resave it as RaceClass_02.py
. WorldClass_01.py
to use RaceClass_02.py
, and then resave it as WorldClass_02.py
. WorldClass_02.py
from the command prompt. Try and shoot the AI cycles as they drive past, and try shooting the ground as well.When we point our lasers at a cycle or the ground and fire them, we see a little explosion at the point of impact. If we hit a cycle, we also get a printout to the command prompt telling us the name of the cycle that got hit, and how much damage it was dealt.
We didn't really have to do anything new to make this work, except for one line in the Pop
class we made:
self.pop.find('**/+SequenceNode').node().play(0, 15)
The model that we're loading and referencing with self.pop
is a flipbook-style animation created with the Panda3D utility egg-texture-cards. This line of code is used to tell the animation to play from frame 0
to frame 15
, which is the last frame in the animation. We need this line because without it, the animation may not play as intended. It might be at frame 8
when the explosion appears, and loop around to frame 7
by the time it finishes.