예제 #1
0
    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())
예제 #3
0
    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)
예제 #5
0
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()
예제 #6
0
 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)
예제 #7
0
    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')