def _add_box_body(self, lane_start, lane_end, middle, parent_np: NodePath, line_type, line_color): length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1]) if LineType.prohibit(line_type): node_name = BodyName.White_continuous_line if line_color == LineColor.GREY else BodyName.Yellow_continuous_line else: node_name = BodyName.Broken_line body_node = BulletGhostNode(node_name) body_node.set_active(False) body_node.setKinematic(False) body_node.setStatic(True) body_np = parent_np.attachNewNode(body_node) shape = BulletBoxShape( Vec3(length / 2, Block.LANE_LINE_WIDTH / 2, Block.LANE_LINE_GHOST_HEIGHT)) body_np.node().addShape(shape) mask = Block.CONTINUOUS_COLLISION_MASK if line_type != LineType.BROKEN else Block.BROKEN_COLLISION_MASK body_np.node().setIntoCollideMask(BitMask32.bit(mask)) self.static_nodes.append(body_np.node()) body_np.setPos(panda_position(middle, Block.LANE_LINE_GHOST_HEIGHT / 2)) direction_v = lane_end - lane_start theta = -numpy.arctan2(direction_v[1], direction_v[0]) body_np.setQuat( LQuaternionf(numpy.cos(theta / 2), 0, 0, numpy.sin(theta / 2)))
def __setupCollisions(self): sphere = BulletSphereShape(4.0) gnode = BulletGhostNode(self.uniqueName('NPCToonSphere')) gnode.addShape(sphere) gnode.setKinematic(True) self.collisionNodePath = self.attachNewNode(gnode) self.collisionNodePath.setY(1.5) self.collisionNodePath.setCollideMask(CIGlobals.EventGroup) base.physicsWorld.attachGhost(self.collisionNodePath.node())
def _add_lane_line2bullet(self, lane_start, lane_end, middle, parent_np: NodePath, color: Vec4, line_type: LineType, straight_stripe=False): length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1]) if length <= 0: return if LineType.prohibit(line_type): node_name = BodyName.White_continuous_line if color == LineColor.GREY else BodyName.Yellow_continuous_line else: node_name = BodyName.Broken_line # add bullet body for it if straight_stripe: body_np = parent_np.attachNewNode(node_name) else: body_node = BulletGhostNode(node_name) body_node.set_active(False) body_node.setKinematic(False) body_node.setStatic(True) body_np = parent_np.attachNewNode(body_node) # its scale will change by setScale body_height = DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT shape = BulletBoxShape( Vec3(length / 2 if line_type != LineType.BROKEN else length, DrivableAreaProperty.LANE_LINE_WIDTH / 2, body_height)) body_np.node().addShape(shape) mask = DrivableAreaProperty.CONTINUOUS_COLLISION_MASK if line_type != LineType.BROKEN else DrivableAreaProperty.BROKEN_COLLISION_MASK body_np.node().setIntoCollideMask(mask) self.static_nodes.append(body_np.node()) # position and heading body_np.setPos( panda_position(middle, DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT / 2)) direction_v = lane_end - lane_start # theta = -numpy.arctan2(direction_v[1], direction_v[0]) theta = -math.atan2(direction_v[1], direction_v[0]) body_np.setQuat( LQuaternionf(math.cos(theta / 2), 0, 0, math.sin(theta / 2))) if self.render: # For visualization lane_line = self.loader.loadModel( AssetLoader.file_path("models", "box.bam")) lane_line.setScale(length, DrivableAreaProperty.LANE_LINE_WIDTH, DrivableAreaProperty.LANE_LINE_THICKNESS) lane_line.setPos( Vec3(0, 0 - DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT / 2)) lane_line.reparentTo(body_np) body_np.set_color(color)
def __init__(self): try: self.__initialized return except: self.__initialized = 1 NodePath.__init__(self, hidden.attachNewNode('PositionExaminer')) bsph = BulletSphereShape(1.5) bgh = BulletGhostNode('positionExaminer_sphereGhost') bgh.addShape(bsph) bgh.setKinematic(True) self.cSphereNodePath = self.attachNewNode(bgh)
def makeBulletCollFromPandaColl(rootNode, exclusions=[]): """ Replaces all of the CollisionNodes underneath `rootNode` with static BulletRigidBodyNodes/GhostNodes which contain the shapes from the CollisionNodes. Applies the same transform as the node it is replacing, goes underneath same parent, has same name, has same collide mask. If the Panda CollisionNode is intangible, a BulletGhostNode is created. Else, a BulletRigidBodyNode is created. """ # First combine any redundant CollisionNodes. optimizePhys(rootNode) for pCollNp in rootNode.findAllMatches("**"): if pCollNp.getName() in exclusions: continue if pCollNp.node().getType() != CollisionNode.getClassType(): continue if pCollNp.node().getNumSolids() == 0: continue mask = pCollNp.node().getIntoCollideMask() group = CIGlobals.WallGroup if mask == CIGlobals.FloorBitmask: group = CIGlobals.FloorGroup elif mask == CIGlobals.EventBitmask: group = CIGlobals.LocalAvGroup elif mask == CIGlobals.CameraBitmask: group = CIGlobals.CameraGroup isGhost = not pCollNp.node().getSolid(0).isTangible() if isGhost: rbnode = BulletGhostNode(pCollNp.getName()) group = CIGlobals.LocalAvGroup else: rbnode = BulletRigidBodyNode(pCollNp.getName()) rbnode.addShapesFromCollisionSolids(pCollNp.node()) for shape in rbnode.getShapes(): if shape.isOfType(BulletTriangleMeshShape.getClassType()): shape.setMargin(0.1) rbnode.setKinematic(True) rbnodeNp = NodePath(rbnode) rbnodeNp.reparentTo(pCollNp.getParent()) rbnodeNp.setTransform(pCollNp.getTransform()) rbnodeNp.setCollideMask(group) # Now that we're using bullet collisions, we don't need the panda collisions anymore. pCollNp.removeNode()
def __initCollisions(self, name): self.notify.debug("Initializing collision sphere...") numSlots = len(self.circles) ss = BulletSphereShape(self.numPlayers2SphereRadius[numSlots]) snode = BulletGhostNode(name) snode.addShape(ss) snode.setKinematic(True) snode.setIntoCollideMask(CIGlobals.LocalAvGroup) self.snp = self.attach_new_node(snode) self.snp.setZ(3) self.snp.setY(self.numPlayers2SphereY[numSlots]) self.snp.setSx(self.numPlayers2SphereSx[numSlots]) self.snp.setSy(self.numPlayers2SphereSy[numSlots]) base.physicsWorld.attachGhost(snode) self.acceptOnce("enter" + self.snp.node().getName(), self.__handleEnterCollisionSphere)
def load(self, physName='useableObject'): if self.autoPhysBox: min = Point3(0) max = Point3(0) self.getUseableBounds(min, max) min -= Point3(0.1, 0.1, 0.1) max += Point3(0.1, 0.1, 0.1) extents = PhysicsUtils.extentsFromMinMax(min, max) shape = BulletBoxShape(extents) # Use the box as a trigger and collision geometry. if self.hasPhysGeom: bodyNode = BulletGhostNode(physName) else: bodyNode = BulletRigidBodyNode(physName) bodyNode.setKinematic(True) if not self.underneathSelf: center = PhysicsUtils.centerFromMinMax(min, max) bodyNode.addShape(shape, TransformState.makePos(center)) else: bodyNode.addShape(shape) self.setupPhysics(bodyNode) else: for np in self.findAllMatches("**/+BulletRigidBodyNode"): if (np.getCollideMask() & CIGlobals.WallGroup) != 0: np.setCollideMask(np.getCollideMask() | CIGlobals.UseableGroup) self.bodyNP = np self.bodyNode = np.node() if self.bodyNP: self.bodyNP.setPythonTag('useableObject', self)
def load(self): if self.autoPhysBox: min = Point3(0) max = Point3(0) self.getUseableBounds(min, max) min -= Point3(0.1, 0.1, 0.1) max += Point3(0.1, 0.1, 0.1) center = PhysicsUtils.centerFromMinMax(min, max) extents = PhysicsUtils.extentsFromMinMax(min, max) shape = BulletBoxShape(extents) # Use the box as a trigger and collision geometry. if self.hasPhysGeom: bodyNode = BulletGhostNode('useableObject') else: bodyNode = BulletRigidBodyNode('useableObject') bodyNode.setKinematic(True) bodyNode.addShape(shape, TransformState.makePos(center)) self.setupPhysics(bodyNode) if self.bodyNP: self.bodyNP.setPythonTag('useableObject', self)
class DistributedElevator(DistributedObject): notify = directNotify.newCategory('DistributedElevator') def __init__(self, cr): DistributedObject.__init__(self, cr) self.openSfx = base.audio3d.loadSfx( 'phase_5/audio/sfx/elevator_door_open.ogg') self.closeSfx = base.audio3d.loadSfx( 'phase_5/audio/sfx/elevator_door_close.ogg') self.elevatorPoints = ElevatorPoints self.type = ELEVATOR_NORMAL self.countdownTime = ElevatorData[self.type]['countdown'] self.localAvOnElevator = False self.thebldg = None self.bldgDoId = None self.toZoneId = None self.elevatorModel = None self.countdownTextNP = None self.toonsInElevator = [] self.hopOffButton = None self.fsm = ClassicFSM.ClassicFSM('DistributedElevator', [ State.State('off', self.enterOff, self.exitOff), State.State('opening', self.enterOpening, self.exitOpening), State.State('waitEmpty', self.enterWaitEmpty, self.exitWaitEmpty), State.State('waitCountdown', self.enterWaitCountdown, self.exitWaitCountdown), State.State('closing', self.enterClosing, self.exitClosing), State.State('closed', self.enterClosed, self.exitClosed) ], 'off', 'off') self.fsm.enterInitialState() # The following is a workaround to fix the issue where self.cr is apparently not set. def sendUpdate(self, fieldName, args=[], sendToId=None): if hasattr(self, 'cr') and not self.cr: self.cr = base.cr DistributedObject.sendUpdate(self, fieldName, args=args, sendToId=sendToId) def setElevatorType(self, etype): self.type = etype def getElevatorType(self): return self.type def setBldgDoId(self, doId): self.bldgDoId = doId def getBldgDoId(self): return self.bldgDoId def setToZoneId(self, zoneId): self.toZoneId = zoneId def getToZoneId(self): return self.toZoneId def enterOpening(self, ts=0): self.openDoors.start(ts) def exitOpening(self): self.openDoors.finish() def enterClosing(self, ts=0): if self.localAvOnElevator: self.hideHopOffButton() self.closeDoors.start(ts) def exitClosing(self): if self.closeDoors.isPlaying(): self.closeDoors.finish() def enterClosed(self, ts=0): closeDoors(self.getLeftDoor(), self.getRightDoor()) def exitClosed(self): pass def __handleElevatorTrigger(self, collNp): if not self.localAvOnElevator: self.cr.playGame.getPlace().fsm.request('stop') self.sendUpdate('requestEnter') def enterWaitEmpty(self, ts=0): if not self.localAvOnElevator: self.acceptOnce('enter' + self.uniqueName('elevatorSphere'), self.__handleElevatorTrigger) openDoors(self.getLeftDoor(), self.getRightDoor()) def exitWaitEmpty(self): self.ignore('enter' + self.uniqueName('elevatorSphere')) def enterWaitCountdown(self, ts=0): if not self.localAvOnElevator: self.acceptOnce('enter' + self.uniqueName('elevatorSphere'), self.__handleElevatorTrigger) openDoors(self.getLeftDoor(), self.getRightDoor()) if self.countdownTextNP: self.countdownTextNP.show() self.countdownTrack = Sequence() time = int(ElevatorData[self.type]['countdown']) for i in range(time): self.countdownTrack.append( Func(self.countdownTextNP.node().setText, str(time - i))) self.countdownTrack.append(Wait(1.0)) self.countdownTrack.start(ts) def exitWaitCountdown(self): if self.countdownTextNP: self.countdownTextNP.hide() self.countdownTrack.finish() del self.countdownTrack def enterOff(self, ts=0): pass def exitOff(self): pass def getLeftDoor(self): # Can be overridden by inheritors. return self.thebldg.leftDoor def getRightDoor(self): return self.thebldg.rightDoor def startPoll(self): # Start polling for the building taskMgr.add(self.__pollBuilding, self.uniqueName('pollBuilding')) def __pollBuilding(self, task): self.getTheBldg() if self.thebldg: self.postAnnounceGenerate() return task.done return task.cont def stopPoll(self): taskMgr.remove(self.uniqueName('pollBuilding')) def announceGenerate(self): DistributedObject.announceGenerate(self) self.getTheBldg() if not self.thebldg: self.startPoll() return self.postAnnounceGenerate() def postAnnounceGenerate(self, makeIvals=True): self.leftDoor = self.getLeftDoor() self.rightDoor = self.getRightDoor() self.setupElevator(makeIvals) self.setupCountdownText() base.audio3d.attachSoundToObject(self.closeSfx, self.getElevatorModel()) base.audio3d.attachSoundToObject(self.openSfx, self.getElevatorModel()) self.sendUpdate('requestStateAndTimestamp') def setState(self, state, timestamp): if not self.thebldg: return self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def stateAndTimestamp(self, state, timestamp): self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def setupCountdownText(self): tn = TextNode('countdownText') tn.setFont(CIGlobals.getMickeyFont()) tn.setTextColor(VBase4(0.5, 0.5, 0.5, 1.0)) tn.setAlign(TextNode.ACenter) self.countdownTextNP = self.getElevatorModel().attachNewNode(tn) self.countdownTextNP.setScale(2) self.countdownTextNP.setPos(0, 1, 7) #self.countdownTextNP.setH(180) def setupElevator(self, makeIvals=True): collisionRadius = ElevatorData[self.type]['collRadius'] self.elevatorSphere = BulletSphereShape(collisionRadius) self.elevatorSphereNode = BulletGhostNode( self.uniqueName('elevatorSphere')) self.elevatorSphereNode.setKinematic(True) self.elevatorSphereNode.setIntoCollideMask(CIGlobals.EventGroup) self.elevatorSphereNode.addShape( self.elevatorSphere, TransformState.makePos(Point3(0, 5, 0))) self.elevatorSphereNodePath = self.getElevatorModel().attachNewNode( self.elevatorSphereNode) self.elevatorSphereNodePath.reparentTo(self.getElevatorModel()) base.physicsWorld.attachGhost(self.elevatorSphereNode) if makeIvals: self.makeIvals() def makeIvals(self): self.openDoors = getOpenInterval(self, self.getLeftDoor(), self.getRightDoor(), self.openSfx, None, self.type) closeIval = getCloseInterval(self, self.getLeftDoor(), self.getRightDoor(), self.closeSfx, None, self.type) def maybeDoTransition(): if self.localAvOnElevator: base.transitions.irisOut(t=closeIval.getDuration() / 1.75, blendType='easeIn') self.closeDoors = Parallel( Func(maybeDoTransition), Sequence(closeIval, Func(self.onDoorCloseFinish))) self.closeDoors.setDoneEvent(self.uniqueName('closeDoorsElevatorIval')) def disable(self): self.stopPoll() if hasattr(self, 'openDoors'): self.openDoors.pause() if hasattr(self, 'closeDoors'): self.closeDoors.pause() self.ignore('enter' + self.uniqueName('elevatorSphere')) base.physicsWorld.removeGhost(self.elevatorSphereNode) self.elevatorSphereNodePath.removeNode() del self.elevatorSphereNodePath del self.elevatorSphereNode del self.elevatorSphere self.fsm.request('off') self.openSfx = None self.closeSfx = None self.elevatorPoints = None self.type = None self.countdownTime = None self.localAvOnElevator = None self.thebldg = None self.bldgDoId = None self.toZoneId = None self.elevatorModel = None self.toonsInElevator = None self.hopOffButton = None self.leftDoor = None self.rightDoor = None self.openDoors = None self.closeDoors = None if self.countdownTextNP: self.countdownTextNP.removeNode() self.countdownTextNP = None DistributedObject.disable(self) def onDoorCloseFinish(self): print "Door close finish" if self.localAvOnElevator: base.localAvatar.wrtReparentTo(render) loader = 'suitInterior' where = 'suitInterior' how = 'IDK' world = base.cr.playGame.getCurrentWorldName() if self.thebldg.fsm.getCurrentState().getName() == 'bldgComplete': loader = 'townLoader' where = 'street' how = 'elevatorIn' world = ZoneUtil.CogTropolis requestStatus = { 'zoneId': self.getToZoneId(), 'hoodId': self.cr.playGame.hood.hoodId, 'where': where, 'avId': base.localAvatar.doId, 'loader': loader, 'shardId': None, 'wantLaffMeter': 1, 'world': world, 'how': how } self.cr.playGame.getPlace().doneStatus = requestStatus messenger.send(self.cr.playGame.getPlace().doneEvent) def doMusic(self): self.elevMusic = base.loadMusic('phase_7/audio/bgm/tt_elevator.ogg') base.playMusic(self.elevMusic, looping=1) def fillSlot(self, index, avId): toon = self.cr.doId2do.get(avId) if toon: print "fillSlot", toon point = ElevatorPoints[index] track = Sequence() track.append(Func(toon.animFSM.request, 'run')) track.append( LerpPosInterval(toon, duration=0.5, pos=point, startPos=toon.getPos(self.getElevatorModel()))) track.append( LerpHprInterval(toon, duration=0.3, hpr=(180, 0, 0), startHpr=toon.getHpr(self.getElevatorModel()))) track.append(Func(toon.animFSM.request, 'neutral')) if avId == base.localAvatar.doId: self.localAvOnElevator = True print "We are now on this elevator" track.append(Func(self.showHopOffButton)) base.localAvatar.stopSmartCamera() base.localAvatar.walkControls.setCollisionsActive(0) netTrans = base.camera.getNetTransform() base.camera.reparentTo(self.getElevatorModel()) base.camera.setTransform(render, netTrans) cameraBoardTrack = LerpPosHprInterval(camera, 1.5, Point3(0, -16, 5.5), Point3(0, 0, 0)) cameraBoardTrack.start() toon.stopSmooth() toon.wrtReparentTo(self.getElevatorModel()) toon.headsUp(point) track.start() def emptySlot(self, index, avId): toon = self.cr.doId2do.get(avId) if toon: print "emptySlot", toon OutPoint = ElevatorOutPoints[index] InPoint = ElevatorPoints[index] toon.stopSmooth() toon.headsUp(OutPoint) track = Sequence( Func(toon.animFSM.request, 'run'), LerpPosInterval(toon, duration=0.5, pos=OutPoint, startPos=InPoint), Func(toon.animFSM.request, 'neutral'), Func(toon.wrtReparentTo, render), Func(toon.startSmooth)) if avId == base.localAvatar.doId: self.localAvOnElevator = False track.append(Func(self.freedom)) track.start() def freedom(self): if self.fsm.getCurrentState().getName() in [ 'waitEmpty', 'waitCountdown' ]: self.acceptOnce('enter' + self.uniqueName('elevatorSphere'), self.__handleElevatorTrigger) base.localAvatar.walkControls.setCollisionsActive(1) self.cr.playGame.getPlace().fsm.request('walk') def setToonsInElevator(self, toonsInElevator): for i in xrange(len(toonsInElevator)): avId = toonsInElevator[i] toon = self.cr.doId2do.get(avId) if toon: toon.reparentTo(self.getElevatorModel()) toon.stopSmooth() point = ElevatorPoints[i] toon.setPos(point) toon.setHpr(180, 0, 0) toon.animFSM.request('neutral') def getTheBldg(self): self.thebldg = self.cr.doId2do.get(self.bldgDoId) def getElevatorModel(self): return self.thebldg.getElevatorModel() def enterRejected(self): self.cr.playGame.getPlace().fsm.request('walk') def showHopOffButton(self): if self.fsm.getCurrentState().getName() not in [ 'waitEmpty', 'waitCountdown' ]: return gui = loader.loadModel('phase_3.5/models/gui/inventory_gui.bam') upButton = gui.find('**/InventoryButtonUp') downButton = gui.find('**/InventoryButtonDown') rlvrButton = gui.find('**/InventoryButtonRollover') self.hopOffBtn = DirectButton(relief=None, text="Hop off", text_fg=(0.9, 0.9, 0.9, 1), text_pos=(0, -0.23), text_scale=0.75, image=(upButton, downButton, rlvrButton), image_color=(0.5, 0.5, 0.5, 1), image_scale=(20, 1, 11), pos=(0, 0, 0.8), scale=0.15, command=self.handleHopOffButton) def hideHopOffButton(self): if hasattr(self, 'hopOffBtn'): self.hopOffBtn.destroy() del self.hopOffBtn def handleHopOffButton(self): self.hideHopOffButton() self.sendUpdate('requestExit')