def shoot(self, rangeVector): if not self.gag: return rangeNode = NodePath('Shoot Range') rangeNode.reparentTo(self.turret.getCannon()) rangeNode.setScale(render, 1) rangeNode.setPos(rangeVector) rangeNode.setHpr(90, -90, 90) self.gag.setScale(self.gag.getScale(render)) self.gag.setScale(self.gag.getScale(render)) self.gag.setPos(self.gag.getPos(render)) self.gag.reparentTo(render) self.gag.setHpr(rangeNode.getHpr(render)) base.audio3d.attachSoundToObject(self.gagClass.woosh, self.gag) self.gagClass.woosh.play() self.track = ProjectileInterval(self.gag, startPos=self.gag.getPos(render), endPos=rangeNode.getPos(render), gravityMult=self.gravityMult, duration=self.duration, name=self.trackName) self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getDoneEvent(), self.cleanup) self.track.start() fireSfx = base.audio3d.loadSfx('phase_4/audio/sfx/MG_cannon_fire_alt.mp3') base.audio3d.attachSoundToObject(fireSfx, self.turret.getCannon()) fireSfx.play() if self.turret.isLocal(): self.buildCollisions() self.acceptOnce(self.eventName, self.handleCollision)
def __doThrow(self, alreadyThrown): self.weapon.setScale(1) pathNP = NodePath('throwPath') if not alreadyThrown: pathNP.reparentTo(self.suit) else: pathNP.reparentTo(self.weapon) pathNP.setScale(render, 1.0) pathNP.setPos(0, 30, -100) pathNP.setHpr(90, -90, 90) print pathNP.getPos(base.render) if self.throwTrajectory: self.throwTrajectory.pause() self.throwTrajectory = None if alreadyThrown: startPos = self.weapon.getPos(base.render) gravity = 0.7 else: gravity = 0.7 startPos = self.suit.find('**/joint_Rhold').getPos(base.render) self.throwTrajectory = ProjectileInterval(self.weapon, startPos=startPos, endPos=pathNP.getPos(base.render), gravityMult=gravity, duration=3.0) self.throwTrajectory.start() self.weapon.setScale(10) self.weapon.reparentTo(render) self.weapon.setHpr(pathNP.getHpr(render)) self.weapon_state = 'released' self.acceptOnce(self.wsnp.node().getName() + '-into', self.__handleHitFloor) return
def __init__(self, toon, mg): self.mg = mg self.toon = toon self.splat = Actor(GagGlobals.SPLAT_MDL, {'chan': GagGlobals.SPLAT_CHAN}) self.splat.setScale(0.5) self.splat.setColor( VBase4(250.0 / 255.0, 241.0 / 255.0, 24.0 / 255.0, 1.0)) self.splat.setBillboardPointEye() self.gc = WholeCreamPie() self.gc.build() self.gag = self.gc.getGag() self.toon.play('toss', fromFrame=60, toFrame=85) self.gag.reparentTo(self.toon.find('**/def_joint_right_hold')) throwPath = NodePath('ThrowPath') throwPath.reparentTo(self.toon) throwPath.setScale(render, 1) throwPath.setPos(0, 150, -90) throwPath.setHpr(90, -90, 90) self.gag.wrtReparentTo(render) self.gag.setHpr(throwPath.getHpr(render)) self.track = ProjectileInterval( self.gag, startPos=self.toon.find('**/def_joint_right_hold').getPos(render), endPos=throwPath.getPos(render), gravityMult=0.9, duration=3) self.track.start() taskMgr.doMethodLater(3, self.__handleThrowTrackDone, 'handleThrowTrackDoneDGP-' + str(hash(self)))
def gagRelease(self, task): gagRange = NodePath('Gag Range') gagRange.reparentTo(self.localAvatar.find('**/joint_nameTag')) gagRange.setPos(0, 75, 0) gagRange.setHpr(90, -90, 90) if self.gag == None: gagRange.removeNode() base.taskMgr.doMethodLater(0.1, self.enableThrowing, 'Enable Gag Throw') return else: if self.height > 1: grav = 0.7 + self.height / 10 else: grav = 0.7 if self.height > 5.2: base.taskMgr.add(self.enableThrowing, 'Enable Gag Throw') return self.gag.reparentTo(render) self.gag.setHpr(gagRange.getHpr(render)) self.gagMgr.getGagByName(self.currentGag).addCollision(self.gag) handJoint = self.localAvatar.find('**/def_joint_right_hold') startPos = Vec3(handJoint.getPos(render).getX(), handJoint.getPos(render).getY(), handJoint.getPos(render).getZ() + 0.8) self.projectile = ProjectileInterval(self.gag, startPos=startPos, endPos=gagRange.getPos(render), duration=1, gravityMult=grav) self.projectile.start() SoundBank.getSound('pie_throw').play() base.taskMgr.doMethodLater(0.8, self.enableThrowing, 'Enable Gag Throw') base.taskMgr.doMethodLater(2, self.destroyGag, 'Destroy Gag', extraArgs = [self.gag, self.projectile], appendTask = True) base.accept('delete-up', self.null) base.accept('p-up', self.null) self.throwingPie = False return Task.done
def throwObject(self, projectile=True): if not self.weapon: return self.acceptOnce('enter' + self.wsnp.node().getName(), self.handleWeaponCollision) self.playWeaponSound() if self.weapon: self.weapon.wrtReparentTo(render) self.weapon.setHpr(Vec3(0, 0, 0)) if self.attack not in ('glowerpower', ): parent = self.suit.find('**/joint_Rhold') else: parent = self.suit.find('**/joint_head') startNP = parent.attachNewNode('startNp') startNP.lookAt(render, self.targetX, self.targetY, self.targetZ) pathNP = NodePath('throwPath') pathNP.reparentTo(startNP) pathNP.setScale(render, 1.0) pathNP.setPos(0, 50, 0) if self.attack in ('clipontie', 'powertie', 'halfwindsor'): self.weapon.setHpr(pathNP.getHpr(render)) if projectile == True: self.throwTrajectory = ProjectileInterval(self.weapon, startPos=self.suit.find('**/joint_Rhold').getPos(render), endPos=pathNP.getPos(render), gravityMult=0.7, duration=1.0) else: self.weapon.setH(pathNP.getH(render)) self.throwTrajectory = LerpPosInterval(self.weapon, duration=0.5, pos=pathNP.getPos(render), startPos=startNP.getPos(render) + (0, 3, 0)) self.throwTrajectory.start() self.weapon_state = 'released' startNP.removeNode() del startNP pathNP.removeNode() del pathNP
def release(self): throwPath = NodePath('ThrowPath') throwPath.reparentTo(self.avatar) throwPath.setScale(render, 1) throwPath.setPos(0, 160, -120) throwPath.setHpr(0, 90, 0) if not self.gag: self.build() self.entity = self.gag self.gag = None self.entity.wrtReparentTo(render) self.entity.setHpr(throwPath.getHpr(render)) self.setHandJoint() self.track = ProjectileInterval(self.entity, startPos=self.handJoint.getPos(render), endPos=throwPath.getPos(render), gravityMult=0.9, duration=3) self.track.start() if self.isLocal(): self.startTimeout() self.buildCollisions() self.avatar.acceptOnce('gagSensor-into', self.onCollision) self.reset() TrapGag.release(self)
def release(self): Gag.release(self) base.audio3d.attachSoundToObject(self.woosh, self.gag) base.playSfx(self.woosh, node=self.gag) throwPath = NodePath('ThrowPath') throwPath.reparentTo(self.avatar) throwPath.setScale(render, 1) throwPath.setPos(0, self.power, -90) throwPath.setHpr(90, -90, 90) entity = self.gag if not entity: entity = self.build() entity.wrtReparentTo(render) entity.setHpr(throwPath.getHpr(render)) self.gag = None if not self.handJoint: self.handJoint = self.avatar.find('**/def_joint_right_hold') track = ProjectileInterval(entity, startPos=self.handJoint.getPos(render), endPos=throwPath.getPos(render), gravityMult=0.9, duration=3) event = self.avatar.uniqueName('throwIvalDone') + '-' + str(hash(entity)) track.setDoneEvent(event) base.acceptOnce(event, self.__handlePieIvalDone, [entity]) track.start() self.entities.append([entity, track]) if self.isLocal(): self.buildCollisions(entity) base.localAvatar.sendUpdate('usedGag', [self.id]) self.reset() return
def throw(self): if not self.gag and not self.isLocal(): self.setHandJoint() self.build() if self.gag and self.getLocation(): self.startEntity() elif self.gag and self.trapMode == 1: throwPath = NodePath('ThrowPath') throwPath.reparentTo(self.avatar) throwPath.setScale(render, 1) throwPath.setPos(0, 160, -120) throwPath.setHpr(0, 90, 0) self.gag.setScale(self.gag.getScale(render)) self.gag.reparentTo(render) self.gag.setHpr(throwPath.getHpr(render)) self.setHandJoint() self.track = ProjectileInterval( self.gag, startPos=self.handJoint.getPos(render), endPos=throwPath.getPos(render), gravityMult=0.9, duration=3) self.track.start() self.buildProjCollisions() self.reset() self.avatar.acceptOnce('projSensor-into', self.onProjCollision)
def shoot(self, rangeVector): if not self.gag: return rangeNode = NodePath('Shoot Range') rangeNode.reparentTo(self.turret.getCannon()) rangeNode.setScale(render, 1) rangeNode.setPos(rangeVector) rangeNode.setHpr(90, -90, 90) self.gag.setScale(self.gag.getScale(render)) self.gag.setScale(self.gag.getScale(render)) self.gag.setPos(self.gag.getPos(render)) self.gag.reparentTo(render) self.gag.setHpr(rangeNode.getHpr(render)) base.audio3d.attachSoundToObject(self.gagClass.woosh, self.gag) self.gagClass.woosh.play() self.track = ProjectileInterval(self.gag, startPos=self.gag.getPos(render), endPos=rangeNode.getPos(render), gravityMult=self.gravityMult, duration=self.duration, name=self.trackName) self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getDoneEvent(), self.cleanup) self.track.start() fireSfx = base.audio3d.loadSfx( 'phase_4/audio/sfx/MG_cannon_fire_alt.ogg') base.audio3d.attachSoundToObject(fireSfx, self.turret.getCannon()) fireSfx.play() if self.turret.isLocal(): self.buildCollisions() self.acceptOnce(self.eventName, self.handleCollision)
def throwObject(self, projectile = True): if not self.weapon: return self.acceptOnce('enter' + self.wsnp.node().getName(), self.handleWeaponCollision) self.playWeaponSound() if self.weapon: self.weapon.wrtReparentTo(render) self.weapon.setHpr(Vec3(0, 0, 0)) if self.attack not in ('glowerpower',): parent = self.suit.find('**/joint_Rhold') else: parent = self.suit.find('**/joint_head') startNP = parent.attachNewNode('startNp') startNP.lookAt(render, self.targetX, self.targetY, self.targetZ) pathNP = NodePath('throwPath') pathNP.reparentTo(startNP) pathNP.setScale(render, 1.0) pathNP.setPos(0, 50, 0) if self.attack in ('clipontie', 'powertie', 'halfwindsor'): self.weapon.setHpr(pathNP.getHpr(render)) if projectile == True: self.throwTrajectory = ProjectileInterval(self.weapon, startPos=self.suit.find('**/joint_Rhold').getPos(render), endPos=pathNP.getPos(render), gravityMult=0.7, duration=1.0) else: self.weapon.setH(pathNP.getH(render)) self.throwTrajectory = LerpPosInterval(self.weapon, duration=0.5, pos=pathNP.getPos(render), startPos=startNP.getPos(render) + (0, 3, 0)) self.throwTrajectory.start() self.weapon_state = 'released' startNP.removeNode() del startNP pathNP.removeNode() del pathNP
def release(self): TrapGag.release(self) throwPath = NodePath('ThrowPath') throwPath.reparentTo(self.avatar) throwPath.setScale(render, 1) throwPath.setPos(0, 160, -120) throwPath.setHpr(0, 90, 0) if not self.gag: self.build() self.gag.wrtReparentTo(render) self.gag.setHpr(throwPath.getHpr(render)) self.setHandJoint() self.track = ProjectileInterval(self.gag, startPos=self.handJoint.getPos(render), endPos=throwPath.getPos(render), gravityMult=0.9, duration=3) self.track.start() if base.localAvatar == self.avatar: self.buildCollisions() self.avatar.acceptOnce('gagSensor-into', self.onCollision) self.reset()
def throw(self): if not self.gag and not self.isLocal(): self.setHandJoint() self.build() if self.gag and self.getLocation(): self.startEntity() elif self.gag and self.trapMode == 1: throwPath = NodePath('ThrowPath') throwPath.reparentTo(self.avatar) throwPath.setScale(render, 1) throwPath.setPos(0, 160, -120) throwPath.setHpr(0, 90, 0) self.gag.setScale(self.gag.getScale(render)) self.gag.reparentTo(render) self.gag.setHpr(throwPath.getHpr(render)) self.setHandJoint() self.track = ProjectileInterval(self.gag, startPos=self.handJoint.getPos(render), endPos=throwPath.getPos(render), gravityMult=0.9, duration=3) self.track.start() self.buildProjCollisions() self.reset() self.avatar.acceptOnce('projSensor-into', self.onProjCollision) if self.isLocal(): base.localAvatar.enablePieKeys()
def save(self, filePath=None): if filePath == None: filePath = self.fromFile config = [] for element in self.elements: np = NodePath(element) od = {} od["type"] = element.getTypeName() od["pos"] = tuple(np.getPos()) od["rot"] = tuple(np.getHpr()) if element.getSkin() is not None: od["skin"] = element.getSkin() if element.getTypeName() == "Pinger": od["frequency"] = element.pinger_frequency config.append(od) plistlib.writePlist(config, filePath)
def release(self): Gag.release(self) base.audio3d.attachSoundToObject(self.woosh, self.gag) self.woosh.play() throwPath = NodePath('ThrowPath') throwPath.reparentTo(self.avatar) throwPath.setScale(render, 1) throwPath.setPos(0, 160, -90) throwPath.setHpr(90, -90, 90) entity = self.gag if not entity: entity = self.build() entity.wrtReparentTo(render) entity.setHpr(throwPath.getHpr(render)) self.gag = None if not self.handJoint: self.handJoint = self.avatar.find('**/def_joint_right_hold') track = ProjectileInterval(entity, startPos=self.handJoint.getPos(render), endPos=throwPath.getPos(render), gravityMult=0.9, duration=3) track.start() self.entities.append([entity, track]) if self.isLocal(): self.buildCollisions(entity) self.reset() return
def test_door_setup(self): parent_np = NodePath('parent_np') parent_np.setPosHpr(0, 10, .5, 180, 0, 0) door_origin = parent_np.attachNewNode('door_origin') door_origin.setPos(10, -25, .5) block = 4 color = Vec4(.842, .167, .361, 1) # Set up door_np nodes door_np = NodePath('door_np') left_hole = door_np.attachNewNode('door_0_hole_left') right_hole = door_np.attachNewNode('door_0_hole_right') left_door = door_np.attachNewNode('door_0_left') right_door = door_np.attachNewNode('door_0_right') door_flat = door_np.attachNewNode('door_0_flat') door_trigger = door_np.attachNewNode('door_0_trigger') DNADoor.setupDoor(door_np, parent_np, door_origin, self.store, block, color) # Check if the nodes attributes and parents are correct self.assertEqual(door_np.getPos(door_origin), Point3(0, 0, 0)) self.assertEqual(door_np.getHpr(door_origin), Point3(0, 0, 0)) self.assertEqual(door_np.getScale(door_origin), Point3(1, 1, 1)) def verify_color(color1, color2): self.assertAlmostEqual(color1.getX(), color2.getX(), places=4) self.assertAlmostEqual(color1.getY(), color2.getY(), places=4) self.assertAlmostEqual(color1.getZ(), color2.getZ(), places=4) self.assertAlmostEqual(color1.getW(), color2.getW(), places=4) verify_color(color, door_np.getColor()) self.assertEqual(left_hole.getParent(), door_flat) self.assertEqual(left_hole.getName(), 'doorFrameHoleLeft') self.assertEqual(right_hole.getParent(), door_flat) self.assertEqual(right_hole.getName(), 'doorFrameHoleRight') self.assertEqual(left_door.getParent(), parent_np) self.assertEqual(left_door.getName(), 'leftDoor') verify_color(color, right_door.getColor()) self.assertEqual(right_door.getParent(), parent_np) self.assertEqual(right_door.getName(), 'rightDoor') verify_color(color, right_door.getColor()) self.assertEqual(door_trigger.getParent(), parent_np) self.assertEqual(door_trigger.getName(), 'door_trigger_%d' % block) store_np = self.store.getDoorPosHprFromBlockNumber(block) self.assertFalse(store_np.isEmpty()) # Testing the pos is a pain because of decimal precision pos = store_np.getPos() self.assertAlmostEqual(pos.getX(), -10, places=2) self.assertAlmostEqual(pos.getY(), 35, places=2) self.assertAlmostEqual(pos.getZ(), 1, places=2) # Sometimes getH() returns -180 and others 180 # Test the modulus (better than abs I guess) self.assertEqual(store_np.getH() % 180, 0)
class SpotLight(Light, DebugObject): """ This light type simulates a SpotLight. It has a position and an orientation. """ def __init__(self): """ Creates a new spot light. """ Light.__init__(self) DebugObject.__init__(self, "SpotLight") self.typeName = "SpotLight" self.nearPlane = 0.5 self.radius = 30.0 self.spotSize = Vec2(30, 30) # Used to compute the MVP self.ghostCamera = Camera("PointLight") self.ghostCamera.setActive(False) self.ghostLens = PerspectiveLens() self.ghostLens.setFov(130) self.ghostCamera.setLens(self.ghostLens) self.ghostCameraNode = NodePath(self.ghostCamera) self.ghostCameraNode.reparentTo(Globals.render) self.ghostCameraNode.hide() def getLightType(self): """ Internal method to fetch the type of this light, used by Light """ return LightType.Spot def _updateLens(self): """ Internal method which gets called when the lens properties changed """ for source in self.shadowSources: source.rebuildMatrixCache() def cleanup(self): """ Internal method which gets called when the light got deleted """ self.ghostCameraNode.removeNode() Light.cleanup(self) def setFov(self, fov): """ Sets the field of view of the spotlight """ assert(fov > 1 and fov < 180) self.ghostLens.setFov(fov) self._updateLens() def setPos(self, pos): """ Sets the position of the spotlight """ self.ghostCameraNode.setPos(pos) Light.setPos(self, pos) def lookAt(self, pos): """ Makes the spotlight look at the given position """ self.ghostCameraNode.lookAt(pos) def _computeAdditionalData(self): """ Internal method to recompute the spotlight MVP """ self.ghostCameraNode.setPos(self.position) projMat = self.ghostLens.getProjectionMat() modelViewMat = Globals.render.getTransform(self.ghostCameraNode).getMat() self.mvp = modelViewMat * projMat def _computeLightBounds(self): """ Recomputes the bounds of this light. For a SpotLight, we for now use a simple BoundingSphere """ self.bounds = BoundingSphere(Point3(self.position), self.radius * 2.0) def setNearFar(self, near, far): """ Sets the near and far plane of the spotlight """ self.nearPlane = near self.radius = far self.ghostLens.setNearFar(near, far) self._updateLens() def _updateDebugNode(self): """ Internal method to generate new debug geometry. """ debugNode = NodePath("SpotLightDebugNode") # Create the inner image cm = CardMaker("SpotLightDebug") cm.setFrameFullscreenQuad() innerNode = NodePath(cm.generate()) innerNode.setTexture(Globals.loader.loadTexture("Data/GUI/Visualization/SpotLight.png")) innerNode.setBillboardPointEye() innerNode.reparentTo(debugNode) innerNode.setPos(self.position) innerNode.setColorScale(1,1,0,1) # Create the outer lines lineNode = debugNode.attachNewNode("lines") currentNodeTransform = render.getTransform(self.ghostCameraNode).getMat() currentCamTransform = self.ghostLens.getProjectionMat() currentRelativeCamPos = self.ghostCameraNode.getPos(render) currentCamBounds = self.ghostLens.makeBounds() currentCamBounds.xform(self.ghostCameraNode.getMat(render)) p = lambda index: currentCamBounds.getPoint(index) # Make a circle at the bottom frustumBottomCenter = (p(0) + p(1) + p(2) + p(3)) * 0.25 upVector = (p(0) + p(1)) / 2 - frustumBottomCenter rightVector = (p(1) + p(2)) / 2 - frustumBottomCenter points = [] for idx in xrange(64): rad = idx / 64.0 * math.pi * 2.0 pos = upVector * math.sin(rad) + rightVector * math.cos(rad) pos += frustumBottomCenter points.append(pos) frustumLine = self._createDebugLine(points, True) frustumLine.setColorScale(1,1,0,1) frustumLine.reparentTo(lineNode) # Create frustum lines which connect the origin to the bottom circle pointArrays = [ [self.position, frustumBottomCenter + upVector], [self.position, frustumBottomCenter - upVector], [self.position, frustumBottomCenter + rightVector], [self.position, frustumBottomCenter - rightVector], ] for pointArray in pointArrays: frustumLine = self._createDebugLine(pointArray, False) frustumLine.setColorScale(1,1,0,1) frustumLine.reparentTo(lineNode) # Create line which is in the direction of the spot light startPoint = (p(0) + p(1) + p(2) + p(3)) * 0.25 endPoint = (p(4) + p(5) + p(6) + p(7)) * 0.25 line = self._createDebugLine([startPoint, endPoint], False) line.setColorScale(1,1,1,1) line.reparentTo(lineNode) # Remove the old debug node self.debugNode.node().removeAllChildren() # Attach the new debug node debugNode.reparentTo(self.debugNode) # self.debugNode.flattenStrong() def _initShadowSources(self): """ Internal method to init the shadow sources """ source = ShadowSource() source.setResolution(self.shadowResolution) source.setLens(self.ghostLens) self._addShadowSource(source) def _updateShadowSources(self): """ Recomputes the position of the shadow source """ self.shadowSources[0].setPos(self.position) self.shadowSources[0].setHpr(self.ghostCameraNode.getHpr()) def __repr__(self): """ Generates a string representation of this instance """ return "SpotLight[]"
class CogdoExecutiveSuiteIntro(CogdoGameMovie): notify = DirectNotifyGlobal.directNotify.newCategory('CogdoExecutiveSuiteIntro') introDuration = 7 cameraMoveDuration = 3 def __init__(self, shopOwner): CogdoGameMovie.__init__(self) self._shopOwner = shopOwner self._lookAtCamTarget = False self._camTarget = None self._camHelperNode = None self._toonDialogueSfx = None self.toonHead = None self.frame = None return def displayLine(self, text): self.notify.debug('displayLine') self._dialogueLabel.node().setText(text) self.toonHead.reparentTo(aspect2d) self._toonDialogueSfx.play() self.toonHead.setClipPlane(self.clipPlane) def makeSuit(self, suitType): self.notify.debug('makeSuit()') suit = Suit.Suit() dna = SuitDNA.SuitDNA() dna.newSuit(suitType) suit.setStyle(dna) suit.isDisguised = 1 suit.generateSuit() suit.setScale(1, 1, 2) suit.setPos(0, 0, -4.4) suit.reparentTo(self.toonHead) for part in suit.getHeadParts(): part.hide() suit.loop('neutral') def load(self): self.notify.debug('load()') CogdoGameMovie.load(self) backgroundGui = loader.loadModel('phase_5/models/cogdominium/tt_m_gui_csa_flyThru') self.bg = backgroundGui.find('**/background') self.chatBubble = backgroundGui.find('**/chatBubble') self.chatBubble.setScale(6.5, 6.5, 7.3) self.chatBubble.setPos(0.32, 0, -0.78) self.bg.setScale(5.2) self.bg.setPos(0.14, 0, -0.6667) self.bg.reparentTo(aspect2d) self.chatBubble.reparentTo(aspect2d) self.frame = DirectFrame(geom=self.bg, relief=None, pos=(0.2, 0, -0.6667)) self.bg.wrtReparentTo(self.frame) self.gameTitleText = DirectLabel(parent=self.frame, text=TTLocalizer.CogdoExecutiveSuiteTitle, scale=TTLocalizer.MRPgameTitleText * 0.8, text_align=TextNode.ACenter, text_font=getSignFont(), text_fg=(1.0, 0.33, 0.33, 1.0), pos=TTLocalizer.MRgameTitleTextPos, relief=None) self.chatBubble.wrtReparentTo(self.frame) self.frame.hide() backgroundGui.removeNode() self.toonDNA = ToonDNA.ToonDNA() self.toonDNA.newToonFromProperties('dss', 'ss', 'm', 'm', 2, 0, 2, 2, 1, 8, 1, 8, 1, 14) self.toonHead = Toon.Toon() self.toonHead.setDNA(self.toonDNA) self.makeSuit('sc') self.toonHead.getGeomNode().setDepthWrite(1) self.toonHead.getGeomNode().setDepthTest(1) self.toonHead.loop('neutral') self.toonHead.setPosHprScale(-0.73, 0, -1.27, 180, 0, 0, 0.18, 0.18, 0.18) self.toonHead.reparentTo(hidden) self.toonHead.startBlink() self.clipPlane = self.toonHead.attachNewNode(PlaneNode('clip')) self.clipPlane.node().setPlane(Plane(0, 0, 1, 0)) self.clipPlane.setPos(0, 0, 2.45) self._toonDialogueSfx = loader.loadSfx('phase_3.5/audio/dial/AV_dog_long.ogg') self._camHelperNode = NodePath('CamHelperNode') self._camHelperNode.reparentTo(render) dialogue = TTLocalizer.CogdoExecutiveSuiteIntroMessage def start(): self.frame.show() base.setCellsActive(base.bottomCells + base.leftCells + base.rightCells, 0) def showShopOwner(): self._setCamTarget(self._shopOwner, -10, offset=Point3(0, 0, 5)) def end(): self._dialogueLabel.reparentTo(hidden) self.toonHead.reparentTo(hidden) self.frame.hide() base.setCellsActive(base.bottomCells + base.leftCells + base.rightCells, 1) self._stopUpdateTask() self._ival = Sequence(Func(start), Func(self.displayLine, dialogue), Func(showShopOwner), ParallelEndTogether(camera.posInterval(self.cameraMoveDuration, Point3(8, 0, 13), blendType='easeInOut'), camera.hprInterval(0.5, self._camHelperNode.getHpr(), blendType='easeInOut')), Wait(self.introDuration), Func(end)) self._startUpdateTask() return def _setCamTarget(self, targetNP, distance, offset = Point3(0, 0, 0), angle = Point3(0, 0, 0)): camera.wrtReparentTo(render) self._camTarget = targetNP self._camOffset = offset self._camAngle = angle self._camDistance = distance self._camHelperNode.setPos(self._camTarget, self._camOffset) self._camHelperNode.setHpr(self._camTarget, 180 + self._camAngle[0], self._camAngle[1], self._camAngle[2]) self._camHelperNode.setPos(self._camHelperNode, 0, self._camDistance, 0) def _updateTask(self, task): dt = globalClock.getDt() return task.cont def unload(self): self._shopOwner = None self._camTarget = None if hasattr(self, '_camHelperNode') and self._camHelperNode: self._camHelperNode.removeNode() del self._camHelperNode self.frame.destroy() del self.frame self.bg.removeNode() del self.bg self.chatBubble.removeNode() del self.chatBubble self.toonHead.stopBlink() self.toonHead.stop() self.toonHead.removeNode() self.toonHead.delete() del self.toonHead CogdoGameMovie.unload(self) return
class CogdoFlyingCameraManager: def __init__(self, cam, parent, player, level): self._toon = player.toon self._camera = cam self._parent = parent self._player = player self._level = level self._enabled = False def enable(self): if self._enabled: return self._toon.detachCamera() self._prevToonY = 0.0 levelBounds = self._level.getBounds() l = Globals.Camera.LevelBoundsFactor self._bounds = ((levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]), (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]), (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2])) self._lookAtZ = self._toon.getHeight( ) + Globals.Camera.LookAtToonHeightOffset self._camParent = NodePath('CamParent') self._camParent.reparentTo(self._parent) self._camParent.setPos(self._toon, 0, 0, 0) self._camParent.setHpr(180, Globals.Camera.Angle, 0) self._camera.reparentTo(self._camParent) self._camera.setPos(0, Globals.Camera.Distance, 0) self._camera.lookAt(self._toon, 0, 0, self._lookAtZ) self._cameraLookAtNP = NodePath('CameraLookAt') self._cameraLookAtNP.reparentTo(self._camera.getParent()) self._cameraLookAtNP.setPosHpr(self._camera.getPos(), self._camera.getHpr()) self._levelBounds = self._level.getBounds() self._enabled = True self._frozen = False self._initCollisions() def _initCollisions(self): self._camCollRay = CollisionRay() camCollNode = CollisionNode('CameraToonRay') camCollNode.addSolid(self._camCollRay) camCollNode.setFromCollideMask(OTPGlobals.WallBitmask | OTPGlobals.CameraBitmask | ToontownGlobals.FloorEventBitmask | ToontownGlobals.CeilingBitmask) camCollNode.setIntoCollideMask(0) self._camCollNP = self._camera.attachNewNode(camCollNode) self._camCollNP.show() self._collOffset = Vec3(0, 0, 0.5) self._collHandler = CollisionHandlerQueue() self._collTrav = CollisionTraverser() self._collTrav.addCollider(self._camCollNP, self._collHandler) self._betweenCamAndToon = {} self._transNP = NodePath('trans') self._transNP.reparentTo(render) self._transNP.setTransparency(True) self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon) self._transNP.setBin('fixed', 10000) def _destroyCollisions(self): self._collTrav.removeCollider(self._camCollNP) self._camCollNP.removeNode() del self._camCollNP del self._camCollRay del self._collHandler del self._collOffset del self._betweenCamAndToon self._transNP.removeNode() del self._transNP def freeze(self): self._frozen = True def unfreeze(self): self._frozen = False def disable(self): if not self._enabled: return self._destroyCollisions() self._camera.wrtReparentTo(render) self._cameraLookAtNP.removeNode() del self._cameraLookAtNP self._camParent.removeNode() del self._camParent del self._prevToonY del self._lookAtZ del self._bounds del self._frozen self._enabled = False def update(self, dt=0.0): self._updateCam(dt) self._updateCollisions() def _updateCam(self, dt): toonPos = self._toon.getPos() camPos = self._camParent.getPos() x = camPos[0] z = camPos[2] toonWorldX = self._toon.getX(render) maxX = Globals.Camera.MaxSpinX toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX) spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / ( maxX * maxX) newH = 180.0 + spinAngle self._camParent.setH(newH) spinAngle = spinAngle * (pi / 180.0) distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle) distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle) d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0]) if abs(d) > Globals.Camera.LeewayX: if d > Globals.Camera.LeewayX: x = toonPos[0] + Globals.Camera.LeewayX else: x = toonPos[0] - Globals.Camera.LeewayX x = self._toon.getX(render) + distToRightOfToon boundToonZ = min(toonPos[2], self._bounds[2][1]) d = z - boundToonZ if d > Globals.Camera.MinLeewayZ: if self._player.velocity[2] >= 0 and toonPos[ 1] != self._prevToonY or self._player.velocity[2] > 0: z = boundToonZ + d * INVERSE_E**(dt * Globals.Camera.CatchUpRateZ) elif d > Globals.Camera.MaxLeewayZ: z = boundToonZ + Globals.Camera.MaxLeewayZ elif d < -Globals.Camera.MinLeewayZ: z = boundToonZ - Globals.Camera.MinLeewayZ if self._frozen: y = camPos[1] else: y = self._toon.getY(render) - distBehindToon self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z)) if toonPos[2] < self._bounds[2][1]: h = self._cameraLookAtNP.getH() if d >= Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ) elif d <= -Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._camParent, 0, 0, self._lookAtZ) self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0) self._camera.setHpr( smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr())) self._prevToonY = toonPos[1] def _updateCollisions(self): pos = self._toon.getPos(self._camera) + self._collOffset self._camCollRay.setOrigin(pos) direction = -Vec3(pos) direction.normalize() self._camCollRay.setDirection(direction) self._collTrav.traverse(render) nodesInBetween = {} if self._collHandler.getNumEntries() > 0: self._collHandler.sortEntries() for entry in self._collHandler.getEntries(): name = entry.getIntoNode().getName() if name.find('col_') >= 0: np = entry.getIntoNodePath().getParent() if np not in nodesInBetween: nodesInBetween[np] = np.getParent() for np in nodesInBetween.keys(): if np in self._betweenCamAndToon: del self._betweenCamAndToon[np] else: np.setTransparency(True) np.wrtReparentTo(self._transNP) if np.getName().find('lightFixture') >= 0: if not np.find('**/*floor_mesh').isEmpty(): np.find('**/*floor_mesh').hide() elif np.getName().find('platform') >= 0: if not np.find('**/*Floor').isEmpty(): np.find('**/*Floor').hide() for np, parent in self._betweenCamAndToon.items(): np.wrtReparentTo(parent) np.setTransparency(False) if np.getName().find('lightFixture') >= 0: if not np.find('**/*floor_mesh').isEmpty(): np.find('**/*floor_mesh').show() elif np.getName().find('platform') >= 0: if not np.find('**/*Floor').isEmpty(): np.find('**/*Floor').show() self._betweenCamAndToon = nodesInBetween
class FPSCamera(DirectObject): MaxP = 90.0 MinP = -90.0 PitchUpdateEpsilon = 0.1 ViewModelFOV = 70.0 BobCycleMin = 1.0 BobCycleMax = 0.45 Bob = 0.002 BobUp = 0.5 PunchDamping = 9.0 PunchSpring = 65.0 PrintAnimLengths = False def __init__(self): DirectObject.__init__(self) self.mouseEnabled = False self.lastCamRoot2Quat = Quat(Quat.identQuat()) self.punchAngleVel = Vec3(0) self.punchAngle = Vec3(0) self.lastFacing = Vec3(0) self.lastMousePos = Point2(0) self.currMousePos = Point2(0) self.bobTime = 0 self.lastBobTime = 0 self.lastVMPos = Point3(0) self.camRoot = NodePath("camRoot") self.camRoot2 = self.camRoot.attachNewNode("camRoot2") self.lastPitch = 0 self.lastEyeHeight = 0.0 # Updates to the transform of camRoot self.vmRender = NodePath( BSPRender('vmRender', BSPLoader.getGlobalPtr())) self.vmRender.setShaderAuto() self.vmRoot = self.vmRender.attachNewNode('vmRoot') self.vmRoot2 = self.vmRoot.attachNewNode(ModelRoot('vmRoot2')) self.viewModel = Actor( "phase_14/models/char/v_toon_arms.bam", { "zero": "phase_14/models/char/v_toon_arms.egg", # Squirt gun viewmodel animations "sg_draw": "phase_14/models/char/v_toon_arms-draw.egg", "sg_idle": "phase_14/models/char/v_toon_arms-idle.egg", "sg_inspect": "phase_14/models/char/v_toon_arms-inspect.egg", "sg_shoot_begin": "phase_14/models/char/v_toon_arms-shoot_begin.egg", "sg_shoot_loop": "phase_14/models/char/v_toon_arms-shoot_loop.egg", "sg_shoot_end": "phase_14/models/char/v_toon_arms-shoot_end.egg", "pie_draw": "phase_14/models/char/v_toon_arms-pie_draw.egg", "pie_idle": "phase_14/models/char/v_toon_arms-pie_idle.egg", "button_draw": "phase_14/models/char/v_toon_arms-button_draw.egg", "button_idle": "phase_14/models/char/v_toon_arms-button_idle.egg", "button_press": "phase_14/models/char/v_toon_arms-button_press.egg", "gumball_draw": "phase_14/models/char/v_toon_arms-gumball_draw.egg", "gumball_idle": "phase_14/models/char/v_toon_arms-gumball_idle.egg", "gumball_fire": "phase_14/models/char/v_toon_arms-gumball_fire.egg", "hose_draw": "phase_14/models/char/v_toon_arms-hose_draw.egg", "hose_idle": "phase_14/models/char/v_toon_arms-hose_idle.egg", "hose_shoot_begin": "phase_14/models/char/v_toon_arms-hose_shoot_begin.egg", "hose_shoot_loop": "phase_14/models/char/v_toon_arms-hose_shoot_loop.egg", "hose_shoot_end": "phase_14/models/char/v_toon_arms-hose_shoot_end.egg", "tnt_draw": "phase_14/models/char/v_toon_arms-tnt_draw.egg", "tnt_idle": "phase_14/models/char/v_toon_arms-tnt_idle.egg", "tnt_throw": "phase_14/models/char/v_toon_arms-tnt_throw.egg", "slap_idle": "phase_14/models/char/v_toon_arms-slap_idle.egg", "slap_hit": "phase_14/models/char/v_toon_arms-slap_hit.egg", "sound": "phase_14/models/char/v_toon_arms-sound.egg" }) self.viewModel.setBlend( frameBlend=base.config.GetBool("interpolate-frames", False)) self.viewModel.reparentTo(self.vmRoot2) self.viewModel.find("**/hands").setTwoSided(True) self.viewModel.hide() self.defaultViewModel = self.viewModel self.idealFov = self.ViewModelFOV precacheActor(self.viewModel) #self.viewModel.clearMaterial() #self.viewModel.setMaterial(CIGlobals.getCharacterMaterial(specular = (0, 0, 0, 1)), 1) self.viewportLens = PerspectiveLens() self.viewportLens.setMinFov(self.ViewModelFOV / (4. / 3.)) self.viewportLens.setNear(0.3) # Updates to the transform of base.camera self.viewportCam = base.makeCamera(base.win, clearDepth=True, camName='fpsViewport', mask=CIGlobals.ViewModelCamMask, lens=self.viewportLens) # Pretend to be the main camera so the viewmodel gets ambient probes updated self.viewportCam.node().setTag("__mainpass__", "1") self.viewportCam.reparentTo(self.vmRoot) self.vmGag = None self.vmAnimTrack = None self.dmgFade = OnscreenImage(image="phase_14/maps/damage_effect.png", parent=render2d) self.dmgFade.setBin('gui-popup', 100) self.dmgFade.setTransparency(1) self.dmgFade.setColorScale(1, 1, 1, 0) self.dmgFadeIval = None #self.accept('v', self.vmRender.ls) #base.bspLoader.addDynamicNode(self.vmRoot) if self.PrintAnimLengths: print "v_toon_arms animation lengths:" for anim in self.viewModel.getAnimNames(): print "\t{0}\t:\t{1}".format(anim, self.viewModel.getDuration(anim)) taskMgr.add(self.__vpDebugTask, "vpdebutask", sort=-100) def setViewModelFOV(self, fov): self.idealFov = fov def restoreViewModelFOV(self): self.idealFov = self.ViewModelFOV def swapViewModel(self, newViewModel, fov=70.0): if newViewModel.isEmpty(): return isHidden = False if not self.viewModel.isEmpty(): self.viewModel.reparentTo(hidden) isHidden = self.viewModel.isHidden() self.viewModel = newViewModel self.viewModel.reparentTo(self.vmRoot2) if isHidden: self.viewModel.hide() else: self.viewModel.show() self.setViewModelFOV(fov) def restoreViewModel(self): isHidden = False if not self.viewModel.isEmpty(): self.viewModel.reparentTo(hidden) isHidden = self.viewModel.isHidden() self.viewModel = self.defaultViewModel self.viewModel.reparentTo(self.vmRoot2) if isHidden: self.viewModel.hide() else: self.viewModel.show() self.restoreViewModelFOV() def addViewPunch(self, punch): self.punchAngleVel += punch * 20 def resetViewPunch(self, tolerance=0.0): if tolerance != 0.0: tolerance *= tolerance check = self.punchAngleVel.lengthSquared( ) + self.punchAngle.lengthSquared() if check > tolerance: return self.punchAngle = Vec3(0) self.punchAngleVel = Vec3(0) def decayPunchAngle(self): if self.punchAngle.lengthSquared( ) > 0.001 or self.punchAngleVel.lengthSquared() > 0.001: dt = globalClock.getDt() self.punchAngle += self.punchAngleVel * dt damping = 1 - (self.PunchDamping * dt) if damping < 0: damping = 0 self.punchAngleVel *= damping # Torsional spring springForceMag = self.PunchSpring * dt springForceMag = CIGlobals.clamp(springForceMag, 0.0, 2.0) self.punchAngleVel -= self.punchAngle * springForceMag # Don't wrap around self.punchAngle.set(CIGlobals.clamp(self.punchAngle[0], -179, 179), CIGlobals.clamp(self.punchAngle[1], -89, 89), CIGlobals.clamp(self.punchAngle[2], -89, 89)) else: self.punchAngle = Vec3(0) self.punchAngleVel = Vec3(0) def hideViewModel(self): self.viewModel.hide(BitMask32.allOn()) def showViewModel(self): if not base.localAvatar.isFirstPerson(): return self.viewModel.showThrough(CIGlobals.ViewModelCamMask) def __vpDebugTask(self, task): if self.vmRender.getState() != render.getState(): # pretend like the view model is part of the main scene self.vmRender.setState(render.getState()) self.viewportLens.setAspectRatio(base.getAspectRatio()) self.viewportLens.setMinFov(self.idealFov / (4. / 3.)) self.vmRoot.setTransform(render, self.camRoot.getTransform(render)) self.viewportCam.setTransform(render, base.camera.getTransform(render)) # Since the viewmodel is not underneath BSPRender, it's not going to be automatically # influenced by the ambient probes. We need to do this explicitly. #base.bspLoader.updateDynamicNode(self.vmRoot) #self.viewportDebug.setImage(self.viewportCam.node().getDisplayRegion(0).getScreenshot()) return task.cont def handleSuitAttack(self, attack): print "FPSCamera handleSuitAttack:", attack def doDamageFade(self, r, g, b, severity=1.0): if self.dmgFadeIval: self.dmgFadeIval.finish() self.dmgFadeIval = None severity = min(1.0, severity) self.dmgFadeIval = Sequence( LerpColorScaleInterval(self.dmgFade, 0.25, (r, g, b, severity), (r, g, b, 0), blendType='easeOut'), Wait(1.0), LerpColorScaleInterval(self.dmgFade, 2.0, (r, g, b, 0), (r, g, b, severity), blendType='easeInOut')) self.dmgFadeIval.start() def setVMAnimTrack(self, track, loop=False): self.clearVMAnimTrack() self.vmAnimTrack = track if loop: self.vmAnimTrack.loop() else: self.vmAnimTrack.start() def clearVMAnimTrack(self): if self.vmAnimTrack: self.vmAnimTrack.pause() self.vmAnimTrack = None def setVMGag(self, gag, pos=(0, 0, 0), hpr=(0, 0, 0), scale=(1, 1, 1), hand=0, animate=True): self.clearVMGag() handNode = NodePath() if hand == ATTACK_HOLD_RIGHT: handNode = self.getViewModelRightHand() elif hand == ATTACK_HOLD_LEFT: handNode = self.getViewModelLeftHand() if isinstance(gag, Actor) and animate: self.vmGag = Actor(other=gag) self.vmGag.reparentTo(handNode) self.vmGag.loop('chan') else: self.vmGag = gag.copyTo(handNode) self.vmGag.setPos(pos) self.vmGag.setHpr(hpr) self.vmGag.setScale(scale) def clearVMGag(self): if self.vmGag: if isinstance(self.vmGag, Actor): self.vmGag.cleanup() self.vmGag.removeNode() self.vmGag = None def setup(self): try: # Match the arm color with the torso color of local avatar self.viewModel.find("**/arms").setColorScale( base.localAvatar.getTorsoColor(), 1) # Same with glove cover self.viewModel.find("**/hands").setColorScale( base.localAvatar.getGloveColor(), 1) except: pass self.attachCamera() def attachCamera(self, reset=True): if reset: self.camRoot.reparentTo(base.localAvatar) if base.localAvatar.isFirstPerson(): self.camRoot.setPos(base.localAvatar.getEyePoint()) else: self.camRoot.setPos(0, 0, max(base.localAvatar.getHeight(), 3.0)) self.camRoot.setHpr(0, 0, 0) self.camRoot2.setPosHpr(0, 0, 0, 0, 0, 0) base.camera.reparentTo(self.camRoot2) if base.localAvatar.isFirstPerson(): base.camera.setPosHpr(0, 0, 0, 0, 0, 0) elif base.localAvatar.isThirdPerson(): pos, lookAt = self.getThirdPersonBattleCam() base.localAvatar.smartCamera.setIdealCameraPos(pos) base.localAvatar.smartCamera.setLookAtPoint(lookAt) def getThirdPersonBattleCam(self): camHeight = max(base.localAvatar.getHeight(), 3.0) heightScaleFactor = camHeight * 0.3333333333 return ((1, -5 * heightScaleFactor, 0), (1, 10, 0)) def getViewModelLeftHand(self): return self.viewModel.find("**/def_left_hold") def getViewModelRightHand(self): return self.viewModel.find("**/def_right_hold") def getViewModel(self): return self.viewModel def acceptEngageKeys(self): self.acceptOnce("escape", self.__handleEscapeKey) def ignoreEngageKeys(self): self.ignore("escape") def enableMouseMovement(self): props = WindowProperties() props.setMouseMode(WindowProperties.MConfined) props.setCursorHidden(True) base.win.requestProperties(props) self.attachCamera(False) if base.localAvatar.isFirstPerson(): base.localAvatar.getGeomNode().hide() base.win.movePointer(0, base.win.getXSize() / 2, base.win.getYSize() / 2) base.taskMgr.add(self.__updateTask, "mouseUpdateFPSCamera", sort=-40) self.acceptEngageKeys() self.mouseEnabled = True base.localAvatar.enableGagKeys() def disableMouseMovement(self, allowEnable=False, showAvatar=True): props = WindowProperties() props.setMouseMode(WindowProperties.MAbsolute) props.setCursorHidden(False) base.win.requestProperties(props) base.taskMgr.remove("mouseUpdateFPSCamera") base.localAvatar.disableGagKeys() if allowEnable: self.acceptEngageKeys() else: self.ignoreEngageKeys() if showAvatar or base.localAvatar.isThirdPerson(): base.localAvatar.getGeomNode().show() else: base.localAvatar.getGeomNode().hide() self.mouseEnabled = False def __handleEscapeKey(self): if self.mouseEnabled: self.disableMouseMovement(True) else: self.enableMouseMovement() #def doCameraJolt(self, amplitude, horizRange = [-1, 1], vertRange = [1]): #h = random.choice(horizRange) * amplitude #p = random.choice(vertRange) * amplitude #nquat = Quat(Quat.identQuat()) #nquat.setHpr((h, p, 0)) #self.lastCamRoot2Quat = self.lastCamRoot2Quat + nquat #Effects.createPBounce(self.camRoot2, 3, self.camRoot2.getHpr(), 1, amplitude).start() #Effects.createHBounce(self.camRoot2, 3, self.camRoot2.getHpr(), 1, amplitude).start() def handleJumpHardLand(self): down = Parallel( LerpPosInterval(base.cam, 0.1, (-0.1, 0, -0.2), (0, 0, 0), blendType='easeOut'), LerpHprInterval(base.cam, 0.1, (0, 0, -2.5), (0, 0, 0), blendType='easeOut')) up = Parallel( LerpPosInterval(base.cam, 0.7, (0, 0, 0), (-0.1, 0, -0.2), blendType='easeInOut'), LerpHprInterval(base.cam, 0.7, (0, 0, 0), (0, 0, -2.5), blendType='easeInOut')) Sequence(down, up).start() def __updateTask(self, task): # TODO -- This function does a lot of math, I measured it to take .5 ms on my laptop # That's a lot of time for something miniscule like sway and bob. dt = globalClock.getDt() time = globalClock.getFrameTime() if base.localAvatar.isFirstPerson(): eyePoint = base.localAvatar.getEyePoint() if base.localAvatar.walkControls.crouching: eyePoint[2] = eyePoint[2] / 2.0 eyePoint[2] = CIGlobals.lerpWithRatio(eyePoint[2], self.lastEyeHeight, 0.4) self.lastEyeHeight = eyePoint[2] camRootAngles = Vec3(0) # Mouse look around mw = base.mouseWatcherNode if mw.hasMouse(): md = base.win.getPointer(0) center = Point2(base.win.getXSize() / 2, base.win.getYSize() / 2) xDist = md.getX() - center.getX() yDist = md.getY() - center.getY() sens = self.__getMouseSensitivity() angular = -(xDist * sens) / dt base.localAvatar.walkControls.controller.setAngularMovement( angular) camRootAngles.setY(self.lastPitch - yDist * sens) if camRootAngles.getY() > FPSCamera.MaxP: camRootAngles.setY(FPSCamera.MaxP) yDist = 0 elif camRootAngles.getY() < FPSCamera.MinP: yDist = 0 camRootAngles.setY(FPSCamera.MinP) base.win.movePointer(0, int(center.getX()), int(center.getY())) if base.localAvatar.isFirstPerson(): # Camera / viewmodel bobbing vmBob = Point3(0) vmAngles = Vec3(0) vmRaise = Point3(0) camBob = Point3(0) maxSpeed = base.localAvatar.walkControls.BattleRunSpeed * 16.0 speed = base.localAvatar.walkControls.speeds.length() * 16.0 speed = max(-maxSpeed, min(maxSpeed, speed)) bobOffset = CIGlobals.remapVal(speed, 0, maxSpeed, 0.0, 1.0) self.bobTime += (time - self.lastBobTime) * bobOffset self.lastBobTime = time # Calculate the vertical bob cycle = self.bobTime - int( self.bobTime / self.BobCycleMax) * self.BobCycleMax cycle /= self.BobCycleMax if cycle < self.BobUp: cycle = math.pi * cycle / self.BobUp else: cycle = math.pi + math.pi * (cycle - self.BobUp) / (1.0 - self.BobUp) verticalBob = speed * 0.005 verticalBob = verticalBob * 0.3 + verticalBob * 0.7 * math.sin( cycle) verticalBob = max(-7.0, min(4.0, verticalBob)) verticalBob /= 16.0 # Calculate the lateral bob cycle = self.bobTime - int( self.bobTime / self.BobCycleMax * 2) * self.BobCycleMax * 2 cycle /= self.BobCycleMax * 2 if cycle < self.BobUp: cycle = math.pi * cycle / self.BobUp else: cycle = math.pi + math.pi * (cycle - self.BobUp) / (1.0 - self.BobUp) lateralBob = speed * 0.005 lateralBob = lateralBob * 0.3 + lateralBob * 0.7 * math.sin(cycle) lateralBob = max(-7.0, min(4.0, lateralBob)) lateralBob /= 16.0 # Apply bob, but scaled down a bit vmBob.set(lateralBob * 0.8, 0, verticalBob * 0.1) # Z bob a bit more vmBob[2] += verticalBob * 0.1 # Bob the angles vmAngles[2] += verticalBob * 0.5 vmAngles[1] -= verticalBob * 0.4 vmAngles[0] -= lateralBob * 0.3 # ================================================================ # Viewmodel lag/sway angles = self.camRoot.getHpr(render) quat = Quat() quat.setHpr(angles) invQuat = Quat() invQuat.invertFrom(quat) maxVMLag = 1.5 lagforward = quat.getForward() if dt != 0.0: lagdifference = lagforward - self.lastFacing lagspeed = 5.0 lagdiff = lagdifference.length() if (lagdiff > maxVMLag) and (maxVMLag > 0.0): lagscale = lagdiff / maxVMLag lagspeed *= lagscale self.lastFacing = CIGlobals.extrude(self.lastFacing, lagspeed * dt, lagdifference) self.lastFacing.normalize() lfLocal = invQuat.xform(lagdifference) vmBob = CIGlobals.extrude(vmBob, 5.0 / 16.0, lfLocal * -1.0) pitch = angles[1] if pitch > 180: pitch -= 360 elif pitch < -180: pitch += 360 vmBob = CIGlobals.extrude(vmBob, pitch * (0.035 / 16), Vec3.forward()) vmBob = CIGlobals.extrude(vmBob, pitch * (0.03 / 16), Vec3.right()) vmBob = CIGlobals.extrude(vmBob, pitch * (0.02 / 16), Vec3.up()) # ================================================================ vmRaise.set( 0, 0, 0 ) #(0, abs(camRootAngles.getY()) * -0.002, camRootAngles.getY() * 0.002) camBob.set(0, 0, 0) # Apply bob, raise, and sway to the viewmodel. self.viewModel.setPos(vmBob + vmRaise + self.lastVMPos) self.vmRoot2.setHpr(vmAngles) self.camRoot.setPos(eyePoint + camBob) newPitch = camRootAngles.getY() if abs(newPitch - self.lastPitch) > self.PitchUpdateEpsilon: # Broadcast where our head is looking head = base.localAvatar.getPart("head") if head and not head.isEmpty(): # Constrain the head pitch a little bit so it doesn't look like their head snapped headPitch = max(-47, newPitch) headPitch = min(75, headPitch) base.localAvatar.b_setLookPitch(headPitch) self.lastPitch = newPitch if base.localAvatar.isFirstPerson(): # Apply punch angle self.decayPunchAngle() camRootAngles += self.punchAngle self.camRoot.setHpr(camRootAngles) return task.cont def __getMouseSensitivity(self): return CIGlobals.getSettingsMgr().getSetting('fpmgms').getValue() def cleanup(self): taskMgr.remove("vpdebutask") self.disableMouseMovement(False, False) self.clearVMAnimTrack() self.clearVMGag() if self.viewModel: self.viewModel.cleanup() self.viewModel.removeNode() self.viewModel = None if self.vmRender: self.vmRender.removeNode() self.vmRender = None self.vmRoot = None self.vmRoot2 = None self.viewportLens = None if self.viewportCam: self.viewportCam.removeNode() self.viewportCam = None if self.camRoot: self.camRoot.removeNode() self.camRoot = None self.camRoot2 = None self.lastEyeHeight = None self.lastPitch = None self.bobTime = None self.lastBobTime = None self.mouseEnabled = None self.lastCamRoot2Quat = None self.punchAngleVel = None self.punchAngle = None self.lastFacing = None self.lastMousePos = None self.currMousePos = None self.lastVMPos = None self.defaultViewModel = None self.idealFov = None self.vmGag = None self.vmAnimTrack = None self.dmgFade = None self.dmgFadeIval = None self.ignoreAll()
class Transform(Component): """Each game object has exactly one of these. A transform holds data about position, rotation, scale and parent relationship. In Panity this is a wrapper for a NodePath. """ def __init__(self, game_object, name): # Component class sets self.game_object = game_object Component.__init__(self, game_object) self.node = NodePath(name) self.node.setPythonTag("transform", self) @classmethod def getClassSerializedProperties(cls): """Return all special property attributes in a dict. Only attributes derived from SerializedProperty are respected. On transform component this method always returns local position, -rotation and scale only. """ d = {} d["local_position"] = Transform.local_position d["local_euler_angles"] = Transform.local_euler_angles d["local_scale"] = Transform.local_scale return d def getSerializedProperties(self): """Return all properties for serialization. In the case of transform this only returns local position, -rotation and -scale, which are required to restore the state of the node. """ d = {} d["local_position"] = self.local_position d["local_euler_angles"] = self.local_euler_angles d["local_scale"] = self.local_scale return d # We use the panda node to save the name on it for better debugging and # efficient finding of nodes with NodePath().find() @SerializedPropertyDecorator def name(self): return self.node.getName() @name.setter def name(self, name): if name == "render": name = "_render" self.node.setName(name) @SerializedPropertyDecorator def position(self): return self.node.getPos(self.root.node) @position.setter def position(self, position): self.node.setPos(self.root.node, *position) @SerializedPropertyDecorator def local_position(self): return self.node.getPos() @local_position.setter def local_position(self, position): self.node.setPos(*position) @SerializedPropertyDecorator def euler_angles(self): return self.node.getHpr(self.root.node) @euler_angles.setter def euler_angles(self, angles): self.node.setHpr(self.root.node, *angles) @SerializedPropertyDecorator def local_euler_angles(self): return self.node.getHpr() @local_euler_angles.setter def local_euler_angles(self, angles): self.node.setHpr(*angles) @SerializedPropertyDecorator def rotation(self): return self.node.getQuat(self.root.node) @rotation.setter def rotation(self, quaternion): self.node.setQuat(self.root.node, *quaternion) @SerializedPropertyDecorator def local_rotation(self): return self.node.getQuat() @local_rotation.setter def local_rotation(self, quaternion): self.node.setQuat(*quaternion) @SerializedPropertyDecorator def local_scale(self): return self.node.getScale() @local_scale.setter def local_scale(self, scale): self.node.setScale(*scale) @SerializedPropertyDecorator def parent(self): p = self.node.getParent() if p.isEmpty() or p.getName() == "render": return self elif p.hasPythonTag("transform"): return p.getPythonTag("transform") @parent.setter def parent(self, parent): self.node.wrtReparentTo(parent.node) @SerializedPropertyDecorator def root(self): if self.parent is not self: return self.parent.root() else: return self def destroy(self): """Ultimately remove this transform. Warning: this might cause errors for other components on this game object. Use this only when removing the whole GameObject. """ self.node.removeNode() def getChildren(self): """Return children as Transforms.""" # this requires the __iter__() method return [c for c in self] def __iter__(self): """Iterate over children nodes and yield the transform instances.""" for child in self.node.getChildren(): if child.hasPythonTag("transform"): yield child.getPythonTag("transform") def __str__(self): r = "Transform for '{}'\n".format(self.name) r += "local position: {}\n".format(self.local_position) r += "local rotation: {}\n".format(self.local_euler_angles) r += "local scale: {}\n".format(self.local_scale) return r
class DistributedButterfly(DistributedObject.DistributedObject): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedButterfly') id = 0 wingTypes = ('wings_1', 'wings_2', 'wings_3', 'wings_4', 'wings_5', 'wings_6') yellowColors = (Vec4(1, 1, 1, 1), Vec4(0.2, 0, 1, 1), Vec4(0.8, 0, 1, 1)) whiteColors = (Vec4(0.8, 0, 0.8, 1), Vec4(0, 0.8, 0.8, 1), Vec4(0.9, 0.4, 0.6, 1), Vec4(0.9, 0.4, 0.4, 1), Vec4(0.8, 0.5, 0.9, 1), Vec4(0.4, 0.1, 0.7, 1)) paleYellowColors = (Vec4(0.8, 0, 0.8, 1), Vec4(0.6, 0.6, 0.9, 1), Vec4(0.7, 0.6, 0.9, 1), Vec4(0.8, 0.6, 0.9, 1), Vec4(0.9, 0.6, 0.9, 1), Vec4(1, 0.6, 0.9, 1)) shadowScaleBig = Point3(0.07, 0.07, 0.07) shadowScaleSmall = Point3(0.01, 0.01, 0.01) def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.fsm = ClassicFSM.ClassicFSM('DistributedButterfly', [State.State('off', self.enterOff, self.exitOff, ['Flying', 'Landed']), State.State('Flying', self.enterFlying, self.exitFlying, ['Landed']), State.State('Landed', self.enterLanded, self.exitLanded, ['Flying'])], 'off', 'off') self.butterfly = None self.butterflyNode = None self.curIndex = 0 self.destIndex = 0 self.time = 0.0 self.ival = None self.fsm.enterInitialState() return def generate(self): DistributedObject.DistributedObject.generate(self) if self.butterfly: return self.butterfly = Actor.Actor() self.butterfly.loadModel('phase_4/models/props/SZ_butterfly-mod.bam') self.butterfly.loadAnims({'flutter': 'phase_4/models/props/SZ_butterfly-flutter.bam', 'glide': 'phase_4/models/props/SZ_butterfly-glide.bam', 'land': 'phase_4/models/props/SZ_butterfly-land.bam'}) index = self.doId % len(self.wingTypes) chosenType = self.wingTypes[index] node = self.butterfly.getGeomNode() for type in self.wingTypes: wing = node.find('**/' + type) if type != chosenType: wing.removeNode() else: if index == 0 or index == 1: color = self.yellowColors[self.doId % len(self.yellowColors)] elif index == 2 or index == 3: color = self.whiteColors[self.doId % len(self.whiteColors)] elif index == 4: color = self.paleYellowColors[self.doId % len(self.paleYellowColors)] else: color = Vec4(1, 1, 1, 1) wing.setColor(color) self.butterfly2 = Actor.Actor(other=self.butterfly) self.butterfly.enableBlend(blendType=PartBundle.BTLinear) self.butterfly.loop('flutter') self.butterfly.loop('land') self.butterfly.loop('glide') rng = RandomNumGen.RandomNumGen(self.doId) playRate = 0.6 + 0.8 * rng.random() self.butterfly.setPlayRate(playRate, 'flutter') self.butterfly.setPlayRate(playRate, 'land') self.butterfly.setPlayRate(playRate, 'glide') self.butterfly2.setPlayRate(playRate, 'flutter') self.butterfly2.setPlayRate(playRate, 'land') self.butterfly2.setPlayRate(playRate, 'glide') self.glideWeight = rng.random() * 2 lodNode = LODNode('butterfly-node') lodNode.addSwitch(100, 40) lodNode.addSwitch(40, 0) self.butterflyNode = NodePath(lodNode) self.butterfly2.setH(180.0) self.butterfly2.reparentTo(self.butterflyNode) self.butterfly.setH(180.0) self.butterfly.reparentTo(self.butterflyNode) self.__initCollisions() self.dropShadow = loader.loadModel('phase_3/models/props/drop_shadow') self.dropShadow.setColor(0, 0, 0, 0.3) self.dropShadow.setPos(0, 0.1, -0.05) self.dropShadow.setScale(self.shadowScaleBig) self.dropShadow.reparentTo(self.butterfly) def disable(self): self.butterflyNode.reparentTo(hidden) if self.ival != None: self.ival.finish() self.__ignoreAvatars() DistributedObject.DistributedObject.disable(self) return def delete(self): self.butterfly.cleanup() self.butterfly = None self.butterfly2.cleanup() self.butterfly2 = None self.butterflyNode.removeNode() self.__deleteCollisions() self.ival = None del self.fsm DistributedObject.DistributedObject.delete(self) return def uniqueButterflyName(self, name): DistributedButterfly.id += 1 return name + '-%d' % DistributedButterfly.id def __detectAvatars(self): self.accept('enter' + self.cSphereNode.getName(), self.__handleCollisionSphereEnter) def __ignoreAvatars(self): self.ignore('enter' + self.cSphereNode.getName()) def __initCollisions(self): self.cSphere = CollisionSphere(0.0, 1.0, 0.0, 3.0) self.cSphere.setTangible(0) self.cSphereNode = CollisionNode(self.uniqueButterflyName('cSphereNode')) self.cSphereNode.addSolid(self.cSphere) self.cSphereNodePath = self.butterflyNode.attachNewNode(self.cSphereNode) self.cSphereNodePath.hide() self.cSphereNode.setCollideMask(ToontownGlobals.WallBitmask) def __deleteCollisions(self): del self.cSphere del self.cSphereNode self.cSphereNodePath.removeNode() del self.cSphereNodePath def __handleCollisionSphereEnter(self, collEntry): self.sendUpdate('avatarEnter', []) def setArea(self, playground, area): self.playground = playground self.area = area def setState(self, stateIndex, curIndex, destIndex, time, timestamp): self.curIndex = curIndex self.destIndex = destIndex self.time = time self.fsm.request(ButterflyGlobals.states[stateIndex], [globalClockDelta.localElapsedTime(timestamp)]) def enterOff(self, ts = 0.0): if self.butterflyNode != None: self.butterflyNode.reparentTo(hidden) return def exitOff(self): if self.butterflyNode != None: self.butterflyNode.reparentTo(render) return def enterFlying(self, ts): self.__detectAvatars() curPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][self.curIndex] destPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][self.destIndex] flyHeight = max(curPos[2], destPos[2]) + ButterflyGlobals.BUTTERFLY_HEIGHT[self.playground] curPosHigh = Point3(curPos[0], curPos[1], flyHeight) destPosHigh = Point3(destPos[0], destPos[1], flyHeight) if ts <= self.time: flyTime = self.time - (ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground] + ButterflyGlobals.BUTTERFLY_LANDING[self.playground]) self.butterflyNode.setPos(curPos) self.dropShadow.show() self.dropShadow.setScale(self.shadowScaleBig) oldHpr = self.butterflyNode.getHpr() self.butterflyNode.headsUp(destPos) newHpr = self.butterflyNode.getHpr() self.butterflyNode.setHpr(oldHpr) takeoffShadowT = 0.2 * ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground] landShadowT = 0.2 * ButterflyGlobals.BUTTERFLY_LANDING[self.playground] self.butterfly2.loop('flutter') self.ival = Sequence(Parallel(LerpPosHprInterval(self.butterflyNode, ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground], curPosHigh, newHpr), LerpAnimInterval(self.butterfly, ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground], 'land', 'flutter'), LerpAnimInterval(self.butterfly, ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground], None, 'glide', startWeight=0, endWeight=self.glideWeight), Sequence(LerpScaleInterval(self.dropShadow, takeoffShadowT, self.shadowScaleSmall, startScale=self.shadowScaleBig), HideInterval(self.dropShadow))), LerpPosInterval(self.butterflyNode, flyTime, destPosHigh), Parallel(LerpPosInterval(self.butterflyNode, ButterflyGlobals.BUTTERFLY_LANDING[self.playground], destPos), LerpAnimInterval(self.butterfly, ButterflyGlobals.BUTTERFLY_LANDING[self.playground], 'flutter', 'land'), LerpAnimInterval(self.butterfly, ButterflyGlobals.BUTTERFLY_LANDING[self.playground], None, 'glide', startWeight=self.glideWeight, endWeight=0), Sequence(Wait(ButterflyGlobals.BUTTERFLY_LANDING[self.playground] - landShadowT), ShowInterval(self.dropShadow), LerpScaleInterval(self.dropShadow, landShadowT, self.shadowScaleBig, startScale=self.shadowScaleSmall))), name=self.uniqueName('Butterfly')) self.ival.start(ts) else: self.ival = None self.butterflyNode.setPos(destPos) self.butterfly.setControlEffect('land', 1.0) self.butterfly.setControlEffect('flutter', 0.0) self.butterfly.setControlEffect('glide', 0.0) self.butterfly2.loop('land') return def exitFlying(self): self.__ignoreAvatars() if self.ival != None: self.ival.finish() self.ival = None return def enterLanded(self, ts): self.__detectAvatars() curPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][self.curIndex] self.butterflyNode.setPos(curPos) self.dropShadow.show() self.dropShadow.setScale(self.shadowScaleBig) self.butterfly.setControlEffect('land', 1.0) self.butterfly.setControlEffect('flutter', 0.0) self.butterfly.setControlEffect('glide', 0.0) self.butterfly2.pose('land', random.randrange(self.butterfly2.getNumFrames('land'))) return None def exitLanded(self): self.__ignoreAvatars() return None
class ProjectilePie(DirectObject): def __init__(self, collideEventName, parent, pie, endPos, gravityMult, duration, local, turretClass): self.turret = turretClass self.collideEventName = collideEventName self.pieNp = NodePath('pieNP') self.pieNp.reparentTo(parent) self.pieNp.setScale(render, 1) self.pieNp.setPos(endPos) self.pieNp.setHpr(90, -90, 90) self.pie = pie if local: self.pieCollisions() self.pie.setScale(self.pie.getScale(render)) self.pie.setPos(self.pie.getPos(render)) self.pie.reparentTo(render) self.pie.setHpr(self.pieNp.getHpr(render)) self.trajectory = ProjectileInterval(self.pie, startPos=self.pie.getPos(render), endPos=self.pieNp.getPos(render), gravityMult=gravityMult, duration=duration, name='projectilePieTraj' + str(id(self))) self.trajectory.setDoneEvent(self.trajectory.getName()) self.acceptOnce(self.trajectory.getDoneEvent(), self.handleTrajDone) self.trajectory.start() sfx = base.localAvatar.audio3d.loadSfx( "phase_4/audio/sfx/MG_cannon_fire_alt.mp3") base.localAvatar.audio3d.attachSoundToObject(sfx, parent) base.playSfx(sfx) if local: self.acceptOnce('projectilePieSensor' + str(id(self)) + '-into', self.handleCollision) def pieCollisions(self): pss = CollisionSphere(0, 0, 0, 1) psnode = CollisionNode('projectilePieSensor' + str(id(self))) psnode.add_solid(pss) self.psnp = self.pie.attach_new_node(psnode) self.psnp.set_collide_mask(BitMask32(0)) self.psnp.node().set_from_collide_mask(CIGlobals.WallBitmask | CIGlobals.FloorBitmask) event = CollisionHandlerEvent() event.set_in_pattern("%fn-into") event.set_out_pattern("%fn-out") base.cTrav.add_collider(self.psnp, event) def handleCollision(self, entry): messenger.send(self.collideEventName, [entry, self]) def handleTrajDone(self): self.cleanup() def cleanup(self): self.ignore(self.trajectory.getDoneEvent()) self.trajectory.finish() del self.trajectory if self.turret.piesInFlight: self.turret.piesInFlight.remove(self) self.ignore('projectilePieSensor' + str(id(self)) + '-into') del self.collideEventName if hasattr(self, 'psnp'): self.psnp.removeNode() del self.psnp self.pie.removeNode() del self.pie del self.pieNp del self.turret
class Bot(object): def __init__(self, team, position, direction): self._orders = Actions.DoNothing self._hp = 5 self._death_played = False self._interval = None self.kills = 0 self.team = team self._model = NodePath('bot') self._model.reparentTo(render) self._model.setPos(position) self._model.setHpr(direction, 0, 0) self._model.setColorScale(*self.team) self._model.setScale(.2, .2, .2) # Load the animations self._actor = Actor("models/RockGolem", { 'idle': 'models/RockGolem-idle', 'walk': 'models/RockGolem-walk', 'reverse-walk': 'models/RockGolem-walk', 'punch': 'models/RockGolem-punch', 'death': 'models/RockGolem-death', 'throw': 'models/RockGolem-throw', }) self._actor.setPlayRate(2.65, 'walk') self._actor.setPlayRate(-2.65, 'reverse-walk') self._actor.setPlayRate(4, 'punch') self._actor.setPlayRate(5.25, 'throw') self._actor.setBlend(frameBlend=True) self._actor.reparentTo(self._model) self._actor.loop('idle') self._actor.setH(180) # Floating Label text = TextNode('node name') text.setText(self.__class__.__name__) text.setAlign(TextNode.ACenter) self._name_label = self._model.attachNewNode(text) self._name_label.setBillboardPointEye() self._name_label.setPos(Vec3(0, 0, 6)) self._name_label.setScale(3, 3, 3) # Debug Field of View Cones # fov = make_fov() # fov.reparentTo(self._model) def update(self, tick_number, visible_objects): return Actions.DoNothing def get_position(self): """Return a rounded version of the position vector.""" p = self._model.getPos() return Vec3(round(p.x, 0), round(p.y, 0), round(p.z, 0)) def get_direction(self): """Return a rounded version of the direction vector.""" v = render.getRelativeVector(self._model, Vec3(0, 1, 0)) v.normalize() return Vec3(round(v.x, 0), round(v.y, 0), round(v.z, 0)) def get_name(self): return self.__class__.__name__ def _get_orders(self, tick_number, visible_objects): # If the health is too low, die. if self._hp <= 0: self._orders = Actions.Suicide return # noinspection PyBroadException try: self._orders = self.update(tick_number, visible_objects) except Exception as e: print(type(self), e) self._orders = None def _execute_orders(self, tick_length, battle): # Pre-calculate some useful things new_pos = self.get_position() new_dir = self._model.getHpr() # TODO: Getting rounding errors here velocity = self.get_direction() # If we're outside of the arena, take damage ARENA_SIZE = 13 if new_pos.length() > ARENA_SIZE: battle.announce("{} fled the battle!".format(self.get_name())) self.take_damage(999) # Execute the order if self._orders == Actions.MoveForward: new_pos += velocity self.safe_loop('walk') elif self._orders == Actions.MoveBackward: new_pos -= velocity self.safe_loop('reverse-walk') elif self._orders == Actions.StrafeLeft: v = render.getRelativeVector(self._model, Vec3(-1, 0, 0)) v.normalize() v = Vec3(round(v.x, 0), round(v.y, 0), round(v.z, 0)) new_pos += v self.safe_loop('walk') elif self._orders == Actions.StrafeRight: v = render.getRelativeVector(self._model, Vec3(1, 0, 0)) v.normalize() v = Vec3(round(v.x, 0), round(v.y, 0), round(v.z, 0)) new_pos += v self.safe_loop('walk') elif self._orders == Actions.TurnLeft: new_dir.x += 90 self.safe_loop('walk') elif self._orders == Actions.TurnAround: new_dir.x += 180 self.safe_loop('walk') elif self._orders == Actions.TurnRight: new_dir.x -= 90 self.safe_loop('walk') elif self._orders == Actions.Punch: self.punch(battle) elif self._orders == Actions.DoNothing: self.safe_loop('idle') elif self._orders == Actions.Suicide: self._hp = 0 battle.announce("{} killed itself.".format(self.get_name())) self.take_damage(999) else: # Bad orders detected! Kill this bot. self._hp = 0 battle.announce("{} made an illegal move and died.".format(self.get_name())) self.take_damage(999) # Animate the motion if self._hp <= 0: return self._interval = LerpPosHprInterval( self._model, tick_length-0.05, new_pos, new_dir) self._interval.start() def safe_loop(self, animation): if self._death_played: return if self._actor.getCurrentAnim() != animation: self._actor.loop(animation) def punch(self, battle): if not self._death_played: self._actor.play('punch') hazard = self.get_direction() + self.get_position() bot = battle.get_object_at_position(hazard) if isinstance(bot, Bot): bot.take_damage(5) # TODO: This is fun as 1 if bot._hp > 0: return if bot.team == self.team: message = "{self} killed its teammate {target}!" self.kills -= 1 else: message = "{self} just pwned {target}!" self.kills += 1 battle.announce(message.format(self=self.get_name(), target=bot.get_name()), color=self.team, sfx="Ownage" if self.kills == 1 else None) if self.kills == 2: battle.announce("{} is ON FIRE!".format(self.get_name()), color=(1.0, 0.5, 0.0, 1.0), sfx="DoubleKill") elif self.kills == 3: battle.announce("{} is UNSTOPPABLE!".format(self.get_name()), color=(1.0, 0.5, 0.0, 1.0), sfx="TripleKill") elif self.kills == 4: battle.announce("{} is DOMINATING!".format(self.get_name()), color=(1.0, 0.5, 0.0, 1.0), sfx="Dominating") elif self.kills > 4: battle.announce("{} is GODLIKE!".format(self.get_name()), color=(1.0, 0.5, 0.0, 1.0), sfx="Godlike") def take_damage(self, amount): self._hp -= amount if self._hp <= 0: self._name_label.hide() if self._interval: self._interval.pause() if not self._death_played: self._actor.play('death') self._death_played = True def delete(self): self._model.removeNode() self._actor.cleanup() self._name_label.removeNode()
class Bot: _orders = Actions.DoNothing _hp = 5 _death_played = False def __init__(self, team, position, direction): self.team = team self._model = NodePath("bot") self._model.reparentTo(render) self._model.setPos(position) self._model.setHpr(direction, 0, 0) self._model.setColorScale(*self.team) self._model.setScale(0.15, 0.15, 0.15) # Load the animations self._actor = Actor( "models/RockGolem", { "idle": "models/RockGolem-idle", "walk": "models/RockGolem-walk", "reverse-walk": "models/RockGolem-walk", "punch": "models/RockGolem-punch", "death": "models/RockGolem-death", }, ) self._actor.setPlayRate(2.65, "walk") self._actor.setPlayRate(-2.65, "reverse-walk") self._actor.setPlayRate(4, "punch") self._actor.setBlend(frameBlend=True) self._actor.reparentTo(self._model) self._actor.loop("idle") self._actor.setH(90) # fov = make_fov() # fov.reparentTo(self._model) def update(self, tick_number, visible_objects): return Actions.DoNothing def _get_orders(self, tick_number, visible_objects): if self._hp <= 0: return # noinspection PyBroadException try: self._orders = self.update(tick_number, visible_objects) except Exception as e: print(type(self), e) self._orders = Actions.Suicide def _execute_orders(self, tick_length): # Pre-calculate some useful things new_pos = self._model.getPos() new_dir = self._model.getHpr() velocity = render.getRelativeVector(self._model, Vec3(1, 0, 0)) velocity.normalize() if self._orders == Actions.MoveForward: new_pos += velocity self.safe_loop("walk") elif self._orders == Actions.MoveBackward: new_pos -= velocity self.safe_loop("reverse-walk") elif self._orders == Actions.StrafeLeft: new_pos += velocity self.safe_loop("walk") elif self._orders == Actions.StrafeRight: new_pos += velocity self.safe_loop("walk") elif self._orders == Actions.TurnLeft: new_dir.x += 90 self.safe_loop("walk") elif self._orders == Actions.TurnAround: new_dir.x += 180 self.safe_loop("walk") elif self._orders == Actions.TurnRight: new_dir.x -= 90 self.safe_loop("walk") elif self._orders == Actions.Punch: self.punch() elif self._orders == Actions.Shoot: self.shoot() elif self._orders == Actions.DoNothing: self.safe_loop("idle") elif self._orders == Actions.Suicide: self._hp = 0 self.die() else: # Bad orders detected! Kill this bot. self._hp = 0 self.die() # Animate the motion tick = tick_length - 0.05 # Shave off a tiny bit to finish the interval LerpPosHprInterval(self._model, tick, new_pos, new_dir).start() def safe_loop(self, animation): if self._actor.getCurrentAnim() != animation: self._actor.loop(animation) def die(self): if not self._death_played: self._actor.play("death") self._death_played = True def punch(self): print("Punching not implemented yet!") self._actor.play("punch") def shoot(self): print("Shooting not implemented yet!") self._actor.play("shoot")
class MapObject(MapWritable): ObjectName = "object" def __init__(self, id): MapObjectInit.start() MapWritable.__init__(self, base.document) self.temporary = False self.id = id self.selected = False self.classname = "" self.parent = None self.children = {} self.boundingBox = BoundingBox(Vec3(-0.5, -0.5, -0.5), Vec3(0.5, 0.5, 0.5)) self.boundsBox = Box() self.boundsBox.addView(GeomView.Lines, VIEWPORT_3D_MASK, state = BoundsBox3DState) self.boundsBox.addView(GeomView.Lines, VIEWPORT_2D_MASK, state = BoundsBox2DState) self.boundsBox.generateGeometry() self.collNp = None self.group = None self.properties = {} # All MapObjects have transform self.addProperty(OriginProperty(self)) self.addProperty(AnglesProperty(self)) self.addProperty(ScaleProperty(self)) self.addProperty(ShearProperty(self)) self.np = NodePath(ModelNode(self.ObjectName + ".%i" % self.id)) self.np.setPythonTag("mapobject", self) self.applyCollideMask() # Test bounding volume at this node and but nothing below it. self.np.node().setFinal(True) MapObjectInit.stop() def getClassName(self): return self.classname def isWorld(self): return False def r_findAllParents(self, parents, type): if not self.parent or self.parent.isWorld(): return if type is None or isinstance(self.parent, type): parents.append(self.parent) self.parent.r_findAllParents(parents, type) def findAllParents(self, type = None): parents = [] self.r_findAllParents(parents, type) return parents def findTopmostParent(self, type = None): parents = self.findAllParents(type) if len(parents) == 0: return None return parents[len(parents) - 1] def r_findAllChildren(self, children, type): for child in self.children.values(): if type is None or isinstance(child, type): children.append(child) child.r_findAllChildren(children, type) def findAllChildren(self, type = None): children = [] self.r_findAllChildren(children, type) return children def applyCollideMask(self): self.np.setCollideMask(LEGlobals.ObjectMask) def setTemporary(self, flag): self.temporary = flag # Returns the bounding volume of the object itself, not including children objects. def getObjBounds(self, other = None): if not other: other = self.np.getParent() return self.np.getTightBounds(other) # Returns the min and max points of the bounds of the object, not including children. def getBounds(self, other = None): if not other: other = self.np.getParent() mins = Point3() maxs = Point3() self.np.calcTightBounds(mins, maxs, other) return [mins, maxs] def findChildByID(self, id): if id == self.id: return self if id in self.children: return self.children[id] for child in self.children.values(): ret = child.findChildByID(id) if ret is not None: return ret return None def hasChildWithID(self, id): return id in self.children def copy(self, generator): raise NotImplementedError def paste(self, o, generator): raise NotImplementedError def clone(self): raise NotImplementedError def unclone(self, o): raise NotImplementedError # # Base copy and paste functions shared by all MapObjects. # Each specific MapObject must implement the functions above for their # specific functionality. # def copyProperties(self, props): newProps = {} for key, prop in props.items(): newProp = prop.clone(self) newProp.setValue(prop.getValue()) newProps[key] = newProp self.updateProperties(newProps) def copyBase(self, other, generator, clone = False): if clone and other.id != self.id: parent = other.parent setPar = other.parent is not None and other.parent.hasChildWithID(other.id) and other.parent.children[other.id] == other if setPar: other.reparentTo(NodePath()) other.id = self.id if setPar: other.reparentTo(parent) other.parent = self.parent for child in self.children.values(): if clone: newChild = child.clone() else: newChild = child.copy(generator) newChild.reparentTo(other) other.setClassname(self.classname) other.copyProperties(self.properties) other.selected = self.selected def pasteBase(self, o, generator, performUnclone = False): if performUnclone and o.id != self.id: parent = self.parent setPar = self.parent is not None and self.parent.hasChildWithID(self.id) and self.parent.children[self.id] == self if setPar: self.reparentTo(NodePath()) self.id = o.id if setPar: self.reparentTo(parent) for child in o.children.values(): if performUnclone: newChild = child.clone() else: newChild = child.copy(generator) newChild.reparentTo(self) self.setClassname(o.classname) self.copyProperties(o.properties) self.selected = o.selected def getName(self): return "Object" def getDescription(self): return "Object in a map." def addProperty(self, prop): self.properties[prop.name] = prop # Returns list of property names with the specified value types. def getPropsWithValueType(self, types): if isinstance(types, str): types = [types] props = [] for propName, prop in self.properties.items(): if prop.valueType in types: props.append(propName) return props def getPropNativeType(self, key): prop = self.properties.get(key, None) if not prop: return str return prop.getNativeType() def getPropValueType(self, key): prop = self.properties.get(key, None) if not prop: return "string" return prop.valueType def getPropDefaultValue(self, prop): if isinstance(prop, str): prop = self.properties.get(prop, None) if not prop: return "" return prop.defaultValue def getPropertyValue(self, key, asString = False, default = ""): prop = self.properties.get(key, None) if not prop: return default if asString: return prop.getSerializedValue() else: return prop.getValue() def getProperty(self, name): return self.properties.get(name, None) def updateProperties(self, data): for key, value in data.items(): if not isinstance(value, ObjectProperty): # If only a value was specified and not a property object itself, # this is an update to an existing property. prop = self.properties.get(key, None) if not prop: continue oldValue = prop.getValue() val = prop.getUnserializedValue(value) # If the property has a min/max range, ensure the value we want to # set is within that range. if (not prop.testMinValue(val)) or (not prop.testMaxValue(val)): # Not within range. Use the default value val = prop.defaultValue prop.setValue(val) else: # A property object was given, simply add it to the dict of properties. prop = value oldValue = None val = prop.getValue() self.properties[prop.name] = prop self.propertyChanged(prop, oldValue, val) def propertyChanged(self, prop, oldValue, newValue): if oldValue != newValue: self.send('objectPropertyChanged', [self, prop, newValue]) def setAbsOrigin(self, origin): self.np.setPos(base.render, origin) self.transformChanged() def setOrigin(self, origin): self.np.setPos(origin) self.transformChanged() def getAbsOrigin(self): return self.np.getPos(base.render) def getOrigin(self): return self.np.getPos() def setAngles(self, angles): self.np.setHpr(angles) self.transformChanged() def setAbsAngles(self, angles): self.np.setHpr(base.render, angles) self.transformChanged() def getAbsAngles(self): return self.np.getHpr(base.render) def getAngles(self): return self.np.getHpr() def setScale(self, scale): self.np.setScale(scale) self.transformChanged() def setAbsScale(self, scale): self.np.setScale(base.render, scale) self.transformChanged() def getAbsScale(self): return self.np.getScale(base.render) def getScale(self): return self.np.getScale() def setShear(self, shear): self.np.setShear(shear) self.transformChanged() def setAbsShear(self, shear): self.np.setShear(base.render, shear) self.transformChanged() def getAbsShear(self): return self.np.getShear(base.render) def getShear(self): return self.np.getShear() def transformChanged(self): self.recalcBoundingBox() self.send('objectTransformChanged', [self]) def showBoundingBox(self): self.boundsBox.np.reparentTo(self.np) def hideBoundingBox(self): self.boundsBox.np.reparentTo(NodePath()) def select(self): self.selected = True self.showBoundingBox() #self.np.setColorScale(1, 0, 0, 1) def deselect(self): self.selected = False self.hideBoundingBox() #self.np.setColorScale(1, 1, 1, 1) def setClassname(self, classname): self.classname = classname def fixBounds(self, mins, maxs): # Ensures that the bounds are not flat on any axis sameX = mins.x == maxs.x sameY = mins.y == maxs.y sameZ = mins.z == maxs.z invalid = False if sameX: # Flat horizontal if sameY and sameZ: invalid = True elif not sameY: mins.x = mins.y maxs.x = maxs.y elif not sameZ: mins.x = mins.z maxs.x = maxs.z if sameY: # Flat forward/back if sameX and sameZ: invalid = True elif not sameX: mins.y = mins.x maxs.y = maxs.x elif not sameZ: mins.y = mins.z maxs.y = maxs.z if sameZ: if sameX and sameY: invalid = True elif not sameX: mins.z = mins.x maxs.z = maxs.x elif not sameY: mins.z = mins.y maxs.z = maxs.y return [invalid, mins, maxs] def recalcBoundingBox(self): if not self.np: return # Don't have the picker box or selection visualization contribute to the # calculation of the bounding box. if self.collNp: self.collNp.stash() self.hideBoundingBox() # Calculate a bounding box relative to ourself mins, maxs = self.getBounds(self.np) invalid, mins, maxs = self.fixBounds(mins, maxs) if invalid: mins = Point3(-8) maxs = Point3(8) self.boundingBox = BoundingBox(mins, maxs) self.boundsBox.setMinMax(mins, maxs) if self.selected: self.showBoundingBox() if self.collNp: self.collNp.unstash() self.collNp.node().clearSolids() self.collNp.node().addSolid(CollisionBox(mins, maxs)) self.collNp.hide(~VIEWPORT_3D_MASK) self.send('mapObjectBoundsChanged', [self]) def removePickBox(self): if self.collNp: self.collNp.removeNode() self.collNp = None def delete(self): if not self.temporary: # Take the children with us for child in list(self.children.values()): child.delete() self.children = None # if we are selected, deselect base.selectionMgr.deselect(self) if self.boundsBox: self.boundsBox.cleanup() self.boundsBox = None self.removePickBox() if not self.temporary: self.reparentTo(NodePath()) self.np.removeNode() self.np = None self.properties = None self.metaData = None self.temporary = None def __clearParent(self): if self.parent: self.parent.__removeChild(self) self.np.reparentTo(NodePath()) self.parent = None def __setParent(self, other): if isinstance(other, NodePath): # We are reparenting directly to a NodePath, outside of the MapObject tree. self.parent = None self.np.reparentTo(other) else: self.parent = other if self.parent: self.parent.__addChild(self) self.np.reparentTo(self.parent.np) else: # If None was passed, assume base.render self.np.reparentTo(base.render) def reparentTo(self, other): # If a NodePath is passed to this method, the object will be placed under the specified node # in the Panda3D scene graph, but will be taken out of the MapObject tree. If None is passed, # the object will be parented to base.render and taken out of the MapObject tree. # # Use reparentTo(NodePath()) to place the object outside of both the scene graph and the # MapObject tree. self.__clearParent() self.__setParent(other) def __addChild(self, child): self.children[child.id] = child #self.recalcBoundingBox() def __removeChild(self, child): if child.id in self.children: del self.children[child.id] #self.recalcBoundingBox() def doWriteKeyValues(self, parent): kv = CKeyValues(self.ObjectName, parent) self.writeKeyValues(kv) for child in self.children.values(): child.doWriteKeyValues(kv) def writeKeyValues(self, keyvalues): keyvalues.setKeyValue("id", str(self.id)) # Write out our object properties for name, prop in self.properties.items(): prop.writeKeyValues(keyvalues) def readKeyValues(self, keyvalues): for i in range(keyvalues.getNumKeys()): key = keyvalues.getKey(i) value = keyvalues.getValue(i) if MetaData.isPropertyExcluded(key): continue # Find the property with this name. prop = self.properties.get(key, None) if not prop: # Prop wasn't explicit or part of FGD metadata (if it's an Entity) continue nativeValue = prop.getUnserializedValue(value) # Set the value! self.updateProperties({prop.name: nativeValue})
class CogdoExecutiveSuiteIntro(CogdoGameMovie): notify = DirectNotifyGlobal.directNotify.newCategory( 'CogdoExecutiveSuiteIntro') introDuration = 7 cameraMoveDuration = 3 def __init__(self, shopOwner): CogdoGameMovie.__init__(self) self._shopOwner = shopOwner self._lookAtCamTarget = False self._camTarget = None self._camHelperNode = None self._toonDialogueSfx = None self.toonHead = None self.frame = None return def displayLine(self, text): self.notify.debug('displayLine') self._dialogueLabel.node().setText(text) self.toonHead.reparentTo(aspect2d) self._toonDialogueSfx.play() self.toonHead.setClipPlane(self.clipPlane) def makeSuit(self, suitType): self.notify.debug('makeSuit()') suit = Suit.Suit() dna = SuitDNA.SuitDNA() dna.newSuit(suitType) suit.setStyle(dna) suit.isDisguised = 1 suit.generateSuit() suit.setScale(1, 1, 2) suit.setPos(0, 0, -4.4) suit.reparentTo(self.toonHead) for part in suit.getHeadParts(): part.hide() suit.loop('neutral') def load(self): self.notify.debug('load()') CogdoGameMovie.load(self) backgroundGui = loader.loadModel( 'phase_5/models/cogdominium/tt_m_gui_csa_flyThru') self.bg = backgroundGui.find('**/background') self.chatBubble = backgroundGui.find('**/chatBubble') self.chatBubble.setScale(6.5, 6.5, 7.3) self.chatBubble.setPos(0.32, 0, -0.78) self.bg.setScale(5.2) self.bg.setPos(0.14, 0, -0.6667) self.bg.reparentTo(aspect2d) self.chatBubble.reparentTo(aspect2d) self.frame = DirectFrame(geom=self.bg, relief=None, pos=(0.2, 0, -0.6667)) self.bg.wrtReparentTo(self.frame) self.gameTitleText = DirectLabel( parent=self.frame, text=TTLocalizer.CogdoExecutiveSuiteTitle, scale=TTLocalizer.MRPgameTitleText * 0.8, text_align=TextNode.ACenter, text_font=getSignFont(), text_fg=(1.0, 0.33, 0.33, 1.0), pos=TTLocalizer.MRgameTitleTextPos, relief=None) self.chatBubble.wrtReparentTo(self.frame) self.frame.hide() backgroundGui.removeNode() self.toonDNA = ToonDNA.ToonDNA() self.toonDNA.newToonFromProperties('dss', 'ss', 'm', 'm', 2, 0, 2, 2, 1, 8, 1, 8, 1, 14) self.toonHead = Toon.Toon() self.toonHead.setDNA(self.toonDNA) self.makeSuit('sc') self.toonHead.getGeomNode().setDepthWrite(1) self.toonHead.getGeomNode().setDepthTest(1) self.toonHead.loop('neutral') self.toonHead.setPosHprScale(-0.73, 0, -1.27, 180, 0, 0, 0.18, 0.18, 0.18) self.toonHead.reparentTo(hidden) self.toonHead.startBlink() self.clipPlane = self.toonHead.attachNewNode(PlaneNode('clip')) self.clipPlane.node().setPlane(Plane(0, 0, 1, 0)) self.clipPlane.setPos(0, 0, 2.45) self._toonDialogueSfx = loader.loadSfx( 'phase_3.5/audio/dial/AV_dog_long.ogg') self._camHelperNode = NodePath('CamHelperNode') self._camHelperNode.reparentTo(render) dialogue = TTLocalizer.CogdoExecutiveSuiteIntroMessage def start(): self.frame.show() base.setCellsActive( base.bottomCells + base.leftCells + base.rightCells, 0) def showShopOwner(): self._setCamTarget(self._shopOwner, -10, offset=Point3(0, 0, 5)) def end(): self._dialogueLabel.reparentTo(hidden) self.toonHead.reparentTo(hidden) self.frame.hide() base.setCellsActive( base.bottomCells + base.leftCells + base.rightCells, 1) self._stopUpdateTask() self._ival = Sequence( Func(start), Func(self.displayLine, dialogue), Func(showShopOwner), ParallelEndTogether( camera.posInterval(self.cameraMoveDuration, Point3(8, 0, 13), blendType='easeInOut'), camera.hprInterval(0.5, self._camHelperNode.getHpr(), blendType='easeInOut')), Wait(self.introDuration), Func(end)) self._startUpdateTask() return def _setCamTarget(self, targetNP, distance, offset=Point3(0, 0, 0), angle=Point3(0, 0, 0)): camera.wrtReparentTo(render) self._camTarget = targetNP self._camOffset = offset self._camAngle = angle self._camDistance = distance self._camHelperNode.setPos(self._camTarget, self._camOffset) self._camHelperNode.setHpr(self._camTarget, 180 + self._camAngle[0], self._camAngle[1], self._camAngle[2]) self._camHelperNode.setPos(self._camHelperNode, 0, self._camDistance, 0) def _updateTask(self, task): dt = globalClock.getDt() return task.cont def unload(self): self._shopOwner = None self._camTarget = None if hasattr(self, '_camHelperNode') and self._camHelperNode: self._camHelperNode.removeNode() del self._camHelperNode self.frame.destroy() del self.frame self.bg.removeNode() del self.bg self.chatBubble.removeNode() del self.chatBubble self.toonHead.stopBlink() self.toonHead.stop() self.toonHead.removeNode() self.toonHead.delete() del self.toonHead CogdoGameMovie.unload(self) return
class CogdoFlyingCameraManager: def __init__(self, cam, parent, player, level): self._toon = player.toon self._camera = cam self._parent = parent self._player = player self._level = level self._enabled = False def enable(self): if self._enabled: return self._toon.detachCamera() self._prevToonY = 0.0 levelBounds = self._level.getBounds() l = Globals.Camera.LevelBoundsFactor self._bounds = ((levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]), (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]), (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2])) self._lookAtZ = self._toon.getHeight() + Globals.Camera.LookAtToonHeightOffset self._camParent = NodePath('CamParent') self._camParent.reparentTo(self._parent) self._camParent.setPos(self._toon, 0, 0, 0) self._camParent.setHpr(180, Globals.Camera.Angle, 0) self._camera.reparentTo(self._camParent) self._camera.setPos(0, Globals.Camera.Distance, 0) self._camera.lookAt(self._toon, 0, 0, self._lookAtZ) self._cameraLookAtNP = NodePath('CameraLookAt') self._cameraLookAtNP.reparentTo(self._camera.getParent()) self._cameraLookAtNP.setPosHpr(self._camera.getPos(), self._camera.getHpr()) self._levelBounds = self._level.getBounds() self._enabled = True self._frozen = False self._initCollisions() def _initCollisions(self): self._camCollRay = CollisionRay() camCollNode = CollisionNode('CameraToonRay') camCollNode.addSolid(self._camCollRay) camCollNode.setFromCollideMask(OTPGlobals.WallBitmask | OTPGlobals.CameraBitmask | ToontownGlobals.FloorEventBitmask | ToontownGlobals.CeilingBitmask) camCollNode.setIntoCollideMask(0) self._camCollNP = self._camera.attachNewNode(camCollNode) self._camCollNP.show() self._collOffset = Vec3(0, 0, 0.5) self._collHandler = CollisionHandlerQueue() self._collTrav = CollisionTraverser() self._collTrav.addCollider(self._camCollNP, self._collHandler) self._betweenCamAndToon = {} self._transNP = NodePath('trans') self._transNP.reparentTo(render) self._transNP.setTransparency(True) self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon) self._transNP.setBin('fixed', 10000) def _destroyCollisions(self): self._collTrav.removeCollider(self._camCollNP) self._camCollNP.removeNode() del self._camCollNP del self._camCollRay del self._collHandler del self._collOffset del self._betweenCamAndToon self._transNP.removeNode() del self._transNP def freeze(self): self._frozen = True def unfreeze(self): self._frozen = False def disable(self): if not self._enabled: return self._destroyCollisions() self._camera.wrtReparentTo(render) self._cameraLookAtNP.removeNode() del self._cameraLookAtNP self._camParent.removeNode() del self._camParent del self._prevToonY del self._lookAtZ del self._bounds del self._frozen self._enabled = False def update(self, dt = 0.0): self._updateCam(dt) self._updateCollisions() def _updateCam(self, dt): toonPos = self._toon.getPos() camPos = self._camParent.getPos() x = camPos[0] z = camPos[2] toonWorldX = self._toon.getX(render) maxX = Globals.Camera.MaxSpinX toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX) spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / (maxX * maxX) newH = 180.0 + spinAngle self._camParent.setH(newH) spinAngle = spinAngle * (pi / 180.0) distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle) distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle) d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0]) if abs(d) > Globals.Camera.LeewayX: if d > Globals.Camera.LeewayX: x = toonPos[0] + Globals.Camera.LeewayX else: x = toonPos[0] - Globals.Camera.LeewayX x = self._toon.getX(render) + distToRightOfToon boundToonZ = min(toonPos[2], self._bounds[2][1]) d = z - boundToonZ if d > Globals.Camera.MinLeewayZ: if self._player.velocity[2] >= 0 and toonPos[1] != self._prevToonY or self._player.velocity[2] > 0: z = boundToonZ + d * INVERSE_E ** (dt * Globals.Camera.CatchUpRateZ) elif d > Globals.Camera.MaxLeewayZ: z = boundToonZ + Globals.Camera.MaxLeewayZ elif d < -Globals.Camera.MinLeewayZ: z = boundToonZ - Globals.Camera.MinLeewayZ if self._frozen: y = camPos[1] else: y = self._toon.getY(render) - distBehindToon self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z)) if toonPos[2] < self._bounds[2][1]: h = self._cameraLookAtNP.getH() if d >= Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ) elif d <= -Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._camParent, 0, 0, self._lookAtZ) self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0) self._camera.setHpr(smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr())) self._prevToonY = toonPos[1] def _updateCollisions(self): pos = self._toon.getPos(self._camera) + self._collOffset self._camCollRay.setOrigin(pos) direction = -Vec3(pos) direction.normalize() self._camCollRay.setDirection(direction) self._collTrav.traverse(render) nodesInBetween = {} if self._collHandler.getNumEntries() > 0: self._collHandler.sortEntries() for entry in self._collHandler.getEntries(): name = entry.getIntoNode().getName() if name.find('col_') >= 0: np = entry.getIntoNodePath().getParent() if np not in nodesInBetween: nodesInBetween[np] = np.getParent() for np in nodesInBetween.keys(): if np in self._betweenCamAndToon: del self._betweenCamAndToon[np] else: np.setTransparency(True) np.wrtReparentTo(self._transNP) if np.getName().find('lightFixture') >= 0: np.find('**/*floor_mesh').hide() elif np.getName().find('platform') >= 0: np.find('**/*Floor').hide() for np, parent in self._betweenCamAndToon.items(): np.wrtReparentTo(parent) np.setTransparency(False) if np.getName().find('lightFixture') >= 0: np.find('**/*floor_mesh').show() elif np.getName().find('platform') >= 0: np.find('**/*Floor').show() self._betweenCamAndToon = nodesInBetween
class TQGraphicsNodePath: """ Anything that fundamentally is a only a graphics object in this engine should have these properties. Kwargs: TQGraphicsNodePath_creation_parent_node : this is assigned in the constructor, and after makeObject and the return of the p3d Nodepath, each TQGraphicsNodePath object has to call set_p3d_node """ def __init__(self, **kwargs): """ """ self.TQGraphicsNodePath_creation_parent_node = None self.p3d_nodepath = NodePath("empty") self.p3d_nodepath_changed_post_init_p = False self.p3d_parent_nodepath = NodePath("empty") self.node_p3d = None self.p3d_nodepath.reparentTo(self.p3d_parent_nodepath) self.apply_kwargs(**kwargs) def apply_kwargs(self, **kwargs): """ """ if 'color' in kwargs: TQGraphicsNodePath.setColor(self, kwargs.get('color')) else: TQGraphicsNodePath.setColor(self, Vec4(1., 1., 1., 1.)) def attach_to_render(self): """ """ # assert self.p3d_nodepath # self.p3d_nodepath.reparentTo(render) assert self.p3d_nodepath self.reparentTo(engine.tq_graphics_basics.tq_render) def attach_to_aspect2d(self): """ """ # assert self.p3d_nodepath # self.p3d_nodepath.reparentTo(aspect2d) assert self.p3d_nodepath self.reparentTo(engine.tq_graphics_basics.tq_aspect2d) def _set_p3d_nodepath_plain_post_init(p3d_nodepath): """ """ self.p3d_nodepath = p3d_nodepath self.p3d_nodepath_changed_post_init_p = True @staticmethod def from_p3d_nodepath(p3d_nodepath, **tq_graphics_nodepath_kwargs): """ factory """ go = TQGraphicsNodePath(**tq_graphics_nodepath_kwargs) go.set_p3d_nodepath(p3d_nodepath) return go def set_parent_node_for_nodepath_creation( self, TQGraphicsNodePath_creation_parent_node): """ when calling attachNewNode_p3d, a new node pat is generated. E.g.: To attach a line to render (3d world) is different than attaching it to aspect2d (2d GUI plane), since the aspect2d children are not directly affected by camera movements Args: - TQGraphicsNodePath_creation_parent_node : the NodePath to attach the TQGraphicsNodePath to (e.g. render or aspect2d in p3d) """ # self.set_parent_node_for_nodepath_creation(self.TQGraphicsNodePath_creation_parent_node) self.TQGraphicsNodePath_creation_parent_node = TQGraphicsNodePath_creation_parent_node def set_p3d_nodepath(self, p3d_nodepath, remove_old_nodepath=True): """ """ self.p3d_nodepath = p3d_nodepath def get_p3d_nodepath(self): """ """ return self.p3d_nodepath def set_render_above_all(self, p): """ set render order to be such that it renders normally (false), or above all (true) Args: p: True or False to enable or disable the 'above all' rendering mode """ try: if p == True: self.p3d_nodepath.setBin("fixed", 0) self.p3d_nodepath.setDepthTest(False) self.p3d_nodepath.setDepthWrite(False) else: self.p3d_nodepath.setBin("default", 0) self.p3d_nodepath.setDepthTest(True) self.p3d_nodepath.setDepthWrite(True) except NameError: # if p3d_nodepath is not yet defined print("NameError in set_render_above_all()") def remove(self): """ """ self.p3d_nodepath.removeNode() def setPos(self, *args, **kwargs): """ """ return self.p3d_nodepath.setPos(*args, **kwargs) def getPos(self): """ """ return self.p3d_nodepath.getPos() def setScale(self, *args, **kwargs): """ """ return self.p3d_nodepath.setScale(*args, **kwargs) def getScale(self): """ """ return self.p3d_nodepath.getScale() def setMat(self, *args, **kwargs): """ """ return self.p3d_nodepath.setMat(*args, **kwargs) def setMat_normal(self, mat4x4_normal_np): """ normal convention (numpy array), i.e. convert to forrowvecs convention for p3d setMat call """ return self.p3d_nodepath.setMat(math_utils.to_forrowvecs(mat4x4_normal_np)) def getMat(self, *args, **kwargs): """ """ return self.p3d_nodepath.getMat(*args, **kwargs) def getMat_normal(self, *args, **kwargs): """ """ return math_utils.from_forrowvecs(self.p3d_nodepath.getMat(*args, **kwargs)) def setTexture(self, *args, **kwargs): """ """ return self.p3d_nodepath.setTexture(*args, **kwargs) def setColor(self, *args, **kwargs): """ """ return self.p3d_nodepath.setColor(*args, **kwargs) def setTwoSided(self, *args, **kwargs): """ """ return self.p3d_nodepath.setTwoSided(*args, **kwargs) def setRenderModeWireframe(self, *args, **kwargs): """ """ return self.p3d_nodepath.setRenderModeWireframe(*args, **kwargs) def reparentTo(self, *args, **kwargs): """ """ new_args = list(args) new_args[0] = new_args[0].p3d_nodepath return self.p3d_nodepath.reparentTo(*new_args, **kwargs) def reparentTo_p3d(self, *args, **kwargs): """ input a p3d nodepath directly """ # new_args = list(args) # new_args[0] = new_args[0].p3d_nodepath return self.p3d_nodepath.reparentTo(*args, **kwargs) def get_node_p3d(self): """ """ # return self.p3d_nodepath.node() return self.node_p3d def set_node_p3d(self, node_p3d): """ not available in p3d NodePath class """ self.node_p3d = node_p3d def setRenderModeFilled(self, *args, **kwargs): """ """ return self.p3d_nodepath.setRenderModeFilled(*args, **kwargs) def setLightOff(self, *args, **kwargs): """ """ return self.p3d_nodepath.setLightOff(*args, **kwargs) def show(self): """ """ return self.p3d_nodepath.show() def hide(self): """ """ return self.p3d_nodepath.hide() def setRenderModeThickness(self, *args, **kwargs): """ """ return self.p3d_nodepath.setRenderModeThickness(*args, **kwargs) def removeNode(self): """ """ return self.p3d_nodepath.removeNode() def setHpr(self, *args, **kwargs): """ """ return self.p3d_nodepath.setHpr(*args, **kwargs) def showBounds(self): """ """ return self.p3d_nodepath.showBounds() def setCollideMask(self, *args, **kwargs): """ """ return self.p3d_nodepath.setCollideMask(*args, **kwargs) def getParent_p3d(self, *args, **kwargs): """ """ return self.p3d_nodepath.getParent(*args, **kwargs) def wrtReparentTo(self, *args, **kwargs): """ """ return self.p3d_nodepath.wrtReparentTo(*args, **kwargs) def setBin(self, *args, **kwargs): """ """ return self.p3d_nodepath.setBin(*args, **kwargs) def setDepthTest(self, *args, **kwargs): """ """ return self.p3d_nodepath.setDepthTest(*args, **kwargs) def setDepthWrite(self, *args, **kwargs): """ """ return self.p3d_nodepath.setDepthWrite(*args, **kwargs) def get_children_p3d(self, *args, **kwargs): """ """ return self.p3d_nodepath.get_children(*args, **kwargs) def attachNewNode_p3d(self, *args, **kwargs): """ """ return self.p3d_nodepath.attachNewNode(*args, **kwargs) def lookAt(self, *args, **kwargs): """ """ return self.p3d_nodepath.lookAt(*args, **kwargs) def setLight(self, *args, **kwargs): """ """ return self.p3d_nodepath.setLight(*args, **kwargs) def setAntialias(self, *args, **kwargs): """ """ return self.p3d_nodepath.setAntialias(*args, **kwargs) def getRelativeVector(self, *args, **kwargs): """ """ return self.p3d_nodepath.getRelativeVector(*args, **kwargs) def setTransparency(self, *args, **kwargs): """ """ return self.p3d_nodepath.setTransparency(*args, **kwargs) def getHpr(self, *args, **kwargs): """ """ return self.p3d_nodepath.getHpr(*args, **kwargs) def setHpr(self, *args, **kwargs): """ """ return self.p3d_nodepath.setHpr(*args, **kwargs) def getTightBounds(self, *args, **kwargs): """ """ return self.p3d_nodepath.getTightBounds(*args, **kwargs) def showTightBounds(self, *args, **kwargs): """ """ return self.p3d_nodepath.showTightBounds(*args, **kwargs)