Example #1
0
    def getObjectsInBox(self, mins, maxs):
        objects = []

        # Create a one-off collision box, traverser, and queue to test against all MapObjects
        box = CollisionBox(mins, maxs)
        node = CollisionNode("selectToolCollBox")
        node.addSolid(box)
        node.setFromCollideMask(self.Mask)
        node.setIntoCollideMask(BitMask32.allOff())
        boxNp = self.doc.render.attachNewNode(node)
        queue = CollisionHandlerQueue()
        base.clickTraverse(boxNp, queue)
        queue.sortEntries()
        key = self.Key
        entries = queue.getEntries()
        # Select every MapObject our box intersected with
        for entry in entries:
            np = entry.getIntoNodePath().findNetPythonTag(key)
            if not np.isEmpty():
                obj = np.getPythonTag(key)
                actual = self.getActualObject(obj, entry)
                if isinstance(actual, list):
                    for a in actual:
                        if not any(a == x[0] for x in objects):
                            objects.append((a, entry))
                else:
                    objects.append((actual, entry))
        boxNp.removeNode()

        return objects
Example #2
0
def is_collided(objcm_list0,
                objcm_list1,
                toggle_contact_points=False,
                toggle_plot_cdprimit=False):
    """
    detect the collision between collision models
    :param: objcm_list0, a single collision model or a list of collision models
    :param: objcm_list1
    :return: True or False
    author: weiwei
    date: 20190312osaka, 20201214osaka
    """
    if not isinstance(objcm_list0, list):
        objcm_list0 = [objcm_list0]
    if not isinstance(objcm_list1, list):
        objcm_list1 = [objcm_list1]
    if toggle_plot_cdprimit:
        for one_objcm in objcm_list0:
            one_objcm.show_cdprimit()
        for one_objcm in objcm_list1:
            one_objcm.show_cdprimit()
    tmpnp = NodePath("collision nodepath")
    ctrav = CollisionTraverser()
    chan = CollisionHandlerQueue()
    for one_objcm in objcm_list0:
        ctrav.addCollider(one_objcm.copy_cdnp_to(tmpnp), chan)
    for one_objcm in objcm_list1:
        one_objcm.copy_cdnp_to(tmpnp)
    ctrav.traverse(tmpnp)
    if chan.getNumEntries() > 0:
        if toggle_contact_points:
            contact_points = [
                da.pdv3_to_npv3(cd_entry.getSurfacePoint(base.render))
                for cd_entry in chan.getEntries()
            ]
            return True, contact_points
        else:
            return True
    else:
        return False
class moveMario(ShowBase):
    def __init__(self):

        # Set up the window, camera, etc.
        ShowBase.__init__(self)
        self.ser = serial.Serial('/dev/tty.usbmodem1421', 9600)
        # Set the background color to black
        self.win.setClearColor((0, 0, 0, 1))

        # This is used to store which keys are currently pressed.
        self.keyMap = {
            "left": 0,
            "right": 0,
            "forward": 0,
            "reverse": 0,
            "cam-left": 0,
            "cam-right": 0
        }

        #Initialize Track
        self.track = self.loader.loadModel("luigi_circuit")
        self.track.setScale(1.5)
        self.track.reparentTo(render)

        #Intitial where Mario needs to be
        #marioStartPos = self.track.find("**/start_point").getPos()
        marioStartPos = Vec3(50, -29, 0.35)  #Actual start possition
        #Using ralph because the model is made with correct collision masking and animation
        self.marioActor = Actor("models/ralph", {
            "run": "models/ralph-run",
            "walk": "models/ralph-walk"
        })
        self.marioActor.setScale(0.1, 0.1, 0.1)
        self.marioActor.setH(self.marioActor, 270)
        self.marioActor.reparentTo(self.render)
        self.marioActor.setPos(marioStartPos + (0, 0, 0.5))

        #Floater above so Camera has something to look at
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(self.marioActor)
        self.floater.setZ(2.0)

        taskMgr.add(self.move, "moveTask")
        # Game state variables
        self.isMoving = False

        # Set up the camera
        self.disableMouse()
        self.camera.setPos(self.marioActor.getX() + 100,
                           self.marioActor.getY(), 1)

        #Collision Rays
        self.cTrav = CollisionTraverser()

        self.marioGroundRay = CollisionRay()
        self.marioGroundRay.setOrigin(0, 0, 9)
        self.marioGroundRay.setDirection(0, 0, -1)
        self.marioGroundCol = CollisionNode('marioRay')
        self.marioGroundCol.addSolid(self.marioGroundRay)
        self.marioGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.marioGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.marioGroundColNp = self.marioActor.attachNewNode(
            self.marioGroundCol)
        self.marioGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.marioGroundColNp, self.marioGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 9)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.camGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.camGroundColNp = self.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    def move(self, task):

        elapsed = globalClock.getDt()
        # If a move-key is pressed, move Mario in the specified direction.
        startpos = self.marioActor.getPos()

        line = self.ser.readline()
        listOfCoord = line.split(":")
        if (len(listOfCoord) == 7):
            x = listOfCoord[1]
            g = listOfCoord[3]
            r = listOfCoord[5]

            if (10 <= float(x) <= 180):
                #MAKE IT TURN RIGHT
                self.setKey("right", True)

                self.setKey("left", False)

            elif (180 < float(x) <= 350):
                #MAKE IT TURN LEFT
                self.setKey("right", False)
                self.setKey("left", True)
            else:
                self.setKey("right", False)
                self.setKey("left", False)

            #Make it move forward
            if (int(g) == 1): self.setKey("forward", True)
            else: self.setKey("forward", False)
            #Make it move in Reverse
            if (int(r) == 1): self.setKey("reverse", True)
            else: self.setKey("reverse", False)

        if self.keyMap["left"]:
            self.marioActor.setH(self.marioActor.getH() + 50 * elapsed)
            self.camera.setX(self.camera, +5 * elapsed)
        if self.keyMap["right"]:
            self.marioActor.setH(self.marioActor.getH() - 50 * elapsed)
            self.camera.setX(self.camera, -5 * elapsed)
        if self.keyMap["forward"]:
            self.marioActor.setY(self.marioActor, -100 * elapsed)
        if self.keyMap["reverse"]:
            self.marioActor.setY(self.marioActor, 100 * elapsed)

        #When moving - run the animation - Taken from roaming ralph example
        if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap[
                "right"]:
            if self.isMoving is False:
                self.marioActor.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.marioActor.stop()
                self.marioActor.pose("walk", 5)
                self.isMoving = False

        #Camera uses - modified from roaming ralph
        camvec = self.marioActor.getPos() - self.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if camdist > 5.0:
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 5))
            camdist = 5.0
        if camdist < 2.5:
            self.camera.setPos(self.camera.getPos() - camvec * (2.5 - camdist))
            camdist = 2.5

        #Collission terrain checking - taken from roaming ralph
        entries = list(self.marioGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName(
        ) == "terrain":
            self.marioActor.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.marioActor.setPos(startpos)

        # Keep the camera at level - taken from roaming ralph
        entries = list(self.camGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName(
        ) == "terrain":
            self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)
        if self.camera.getZ() < self.marioActor.getZ() + 1.0:
            self.camera.setZ(self.marioActor.getZ() + 1.0)

        self.camera.lookAt(self.floater)

        return task.cont
Example #4
0
class RoamingRalphDemo(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)

        # Set the background color to black
        self.win.setClearColor((0, 0, 0, 1))

        # Post the instructions
        self.title = addTitle(
            "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.06, "[ESC]: Quit")
        self.inst2 = addInstructions(0.12, "[Left trackpad]: Rotate Left")
        self.inst3 = addInstructions(0.18, "[Right trackpad]: Rotate Right")
        self.inst4 = addInstructions(0.24, "[Up trackpad]: Walk Forward")
        self.inst4 = addInstructions(0.30, "[Down trackpad]: Walk Backward")

        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)

        # Create the main character, Ralph

        self.vr = RoamingRalphVR()
        self.vr.init(msaa=4)

        self.ralph = render.attachNewNode('ralph')
        self.ralphStartPos = self.environ.find("**/start_point").getPos()
        self.vr.tracking_space.setPos(self.ralphStartPos)
        self.ralph.setPos(self.vr.hmd_anchor.getPos(render))

        self.accept("escape", sys.exit)

        taskMgr.add(self.collision, "collisionTask")

        # Set up the camera
        self.disableMouse()

        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above ralph's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.
        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 9)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.ralphGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        # Uncomment this line to see the collision rays
        #self.ralphGroundColNp.show()

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #self.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    # Grid checking and collision detection
    def collision(self, task):

        # Normally, we would have to call traverse() to check for collisions.
        # However, the class ShowBase that we inherit from has a task to do
        # this for us, if we assign a CollisionTraverser to self.cTrav.
        #self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = list(self.ralphGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName(
        ) == "terrain":
            self.vr.tracking_space.setZ(
                entries[0].getSurfacePoint(render).getZ())
        else:
            self.vr.tracking_space.setPos(self.ralphStartPos)
        self.ralph.setPos(self.vr.hmd_anchor.getPos(render))

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        self.ralphStartPos = self.vr.tracking_space.getPos()

        return task.cont
Example #5
0
class MousePicker(object):
    def __init__(self, pickTag="MyPickingTag", nodeName="pickRay", showCollisions=False):
        self.pickTag = pickTag
        self.nodeName = nodeName
        self.showCollisions = showCollisions

    def create(self):
        self.mPickerTraverser = CollisionTraverser()
        self.mCollisionQue = CollisionHandlerQueue()

        self.mPickRay = CollisionRay()
        self.mPickRay.setOrigin(base.camera.getPos(base.render))
        self.mPickRay.setDirection(base.render.getRelativeVector(base.camera, Vec3(0, 1, 0)))

        # create our collison Node to hold the ray
        self.mPickNode = CollisionNode(self.nodeName)
        self.mPickNode.addSolid(self.mPickRay)

        # Attach that node to the camera since the ray will need to be positioned
        # relative to it, returns a new nodepath
        # well use the default geometry mask
        # this is inefficent but its for mouse picking only

        self.mPickNP = base.camera.attachNewNode(self.mPickNode)

        # we'll use what panda calls the "from" node.  This is reall a silly convention
        # but from nodes are nodes that are active, while into nodes are usually passive environments
        # this isnt a hard rule, but following it usually reduces processing

        # Everything to be picked will use bit 1. This way if we were doing other
        # collision we could seperate it, we use bitmasks to determine what we check other objects against
        # if they dont have a bitmask for bit 1 well skip them!
        self.mPickNode.setFromCollideMask(BitMask32(1))

        # Register the ray as something that can cause collisions
        self.mPickerTraverser.addCollider(self.mPickNP, self.mCollisionQue)

        # Setup 2D picker
        self.mPickerTraverser2D = CollisionTraverser()
        self.mCollisionQue2D = CollisionHandlerQueue()

        self.mPickNode2D = CollisionNode("2D PickNode")
        self.mPickNode2D.setFromCollideMask(BitMask32(1))
        self.mPickNode2D.setIntoCollideMask(BitMask32.allOff())

        self.mPick2DNP = base.camera2d.attachNewNode(self.mPickNode2D)

        self.mPickRay2D = CollisionRay()
        self.mPickNode2D.addSolid(self.mPickRay2D)

        self.mPickerTraverser2D.addCollider(self.mPick2DNP, self.mCollisionQue2D)

        if self.showCollisions:
            self.mPickerTraverser.showCollisions(base.render)
            self.mPickerTraverser2D.showCollisions(base.aspect2d)

    def mousePick(self, traverse=None, tag=None):
        # do we have a mouse
        if base.mouseWatcherNode.hasMouse() == False:
            return None, None

        traverse = traverse or base.render
        tag = tag or self.pickTag

        mpos = base.mouseWatcherNode.getMouse()

        # Set the position of the ray based on the mouse position
        self.mPickRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
        self.mPickerTraverser.traverse(traverse)

        if self.mCollisionQue.getNumEntries() > 0:
            self.mCollisionQue.sortEntries()

            for entry in self.mCollisionQue.getEntries():
                pickedObj = entry.getIntoNodePath()
                pickedObj = pickedObj.findNetTag(tag)

                if not pickedObj.isEmpty():
                    pos = entry.getSurfacePoint(base.render)
                    return pickedObj, pos

        return None, None

    def mousePick2D(self, traverse=None, tag=None, all=False):
        # do we have a mouse
        if base.mouseWatcherNode.hasMouse() == False:
            return None, None

        traverse = traverse or base.render
        tag = tag or self.pickTag

        mpos = base.mouseWatcherNode.getMouse()

        self.mPickRay2D.setFromLens(base.cam2d.node(), mpos.getX(), mpos.getY())

        self.mPickerTraverser2D.traverse(base.aspect2d)

        if self.mCollisionQue2D.getNumEntries() > 0:
            self.mCollisionQue2D.sortEntries()

            if all:
                return (
                    [
                        (entry.getIntoNodePath().findNetTag(tag), entry.getSurfacePoint(base.aspect2d))
                        for entry in self.mCollisionQue2D.getEntries()
                    ],
                    None,
                )
            else:
                entry = self.mCollisionQue2D.getEntry(0)
                pickedObj = entry.getIntoNodePath()

                pickedObj = pickedObj.findNetTag(tag)
                if not pickedObj.isEmpty():
                    pos = entry.getSurfacePoint(base.aspect2d)
                    return pickedObj, pos

        return None, None
Example #6
0
class SpaceFlight(ShowBase):
  def __init__(self):
    ShowBase.__init__(self)
    self.text = OnscreenText \
    (
      parent = base.a2dBottomCenter,
      align=TextNode.ARight,
      fg=(1, 1, 1, 1),
      pos=(0.2, 1.),
      scale=0.1,
      shadow=(0, 0, 0, 0.5)
    )
    self.setBackgroundColor(0, 0, 0)
    self.disableMouse()
    self.fog = Fog('distanceFog')
    self.fog.setColor(0, 0, 0)
    self.fog.setExpDensity(.002)
    #
    self.queue = CollisionHandlerQueue()
    self.trav = CollisionTraverser('traverser')
    base.cTrav = self.trav
    self.loadSky()
    self.reloadGame()

    self.keyMap = {'left' : 0, 'right' : 0, 'up' : 0, 'down' : 0}
    self.gamePause = False
    #
    self.accept('escape', sys.exit)
    self.accept('p', self.pause)
    self.accept('r', self.reloadGame)
    self.accept('arrow_left', self.setKey, ['left', True])
    self.accept('arrow_right', self.setKey, ['right', True])
    self.accept('arrow_up', self.setKey, ['up', True])
    self.accept('arrow_down', self.setKey, ['down', True])
    self.accept('arrow_left-up', self.setKey, ['left', False])
    self.accept('arrow_right-up', self.setKey, ['right', False])
    self.accept('arrow_up-up', self.setKey, ['up', False])
    self.accept('arrow_down-up', self.setKey, ['down', False])
    #
    taskMgr.add(self.moveShip, 'moveShip')
    taskMgr.add(self.moveAsteroids, 'moveAsteroids')
    taskMgr.add(self.handleCollisions, 'handleCollisions')
    #
    if DEBUG:
      self.trav.showCollisions(render)
      render.find('**/ship_collision').show()
      for asteroid in render.findAllMatches('**/asteroid_collision*'):
        asteroid.show()

  def loadSky(self):
    self.sky = loader.loadModel('models/solar_sky_sphere.egg.pz')
    self.sky_tex = loader.loadTexture('models/stars_1k_tex.jpg')
    self.sky.setTexture(self.sky_tex, 1)
    self.sky.reparentTo(render)
    self.sky.setScale(500)

  def loadShip(self):
    self.ship = loader.loadModel('models/alice-scifi--fighter/fighter.egg')
    self.ship.reparentTo(render)
    self.ship.setPos(START_X, START_Y, START_Z)
    self.ship.setScale(0.25)
    # add some physics
    ship_col = self.ship.attachNewNode(CollisionNode('ship_collision'))
    col_sphere = CollisionSphere(START_X, START_Y, 0, SHIP_SPHERE_RADIUS)
    ship_col.node().addSolid(col_sphere)
    self.trav.addCollider(ship_col, self.queue)

  def spawnAsteroid(self):
    asteroid = loader.loadModel(choice(ASTEROID_SHAPES))
    asteroid_tex = loader.loadTexture('models/rock03.jpg')
    asteroid.setTexture(asteroid_tex, 1)
    asteroid.reparentTo(render)
    asteroid.setFog(self.fog)
    self.asteroids.append(asteroid)
    self.asteroids_rotation.append(randint(ASTEROID_ROTATE_MIN, ASTEROID_ROTATE_MAX))
    #
    num = len(self.asteroids) - 1
    asteroid_col = asteroid.attachNewNode(CollisionNode('asteroid_collision_%d' % num))
    col_sphere = CollisionSphere(0, 0, 0, ASTEROID_SPHERE_RADIUS)
    asteroid_col.node().addSolid(col_sphere)
    #
    asteroid.setX(randint(MIN_X, MAX_X))
    asteroid.setY(randint(ASTEROID_SPAWN_MIN_Y, ASTEROID_SPAWN_MAX_Y))
    asteroid.setZ(randint(MIN_Z, MAX_Z))

  def setKey(self, key, value):
    self.keyMap[key] = value
    if key in ['left', 'right'] and value == False:
      self.ship.setH(0)
    if key in ['up', 'down'] and value == False:
      self.ship.setP(0)

  def updateCamera(self):
    x, y, z = self.ship.getPos()
    self.camera.setPos(x, y - 40, z + 25)
    self.camera.lookAt(x, y, z + 10)

  def moveAsteroids(self, task):
    dt = globalClock.getDt()
    if not self.gamePause:
      for num, asteroid in enumerate(self.asteroids):
        asteroid.setY(asteroid.getY() - ASTEROID_SPEED * dt)
        rotation = self.asteroids_rotation[num]
        asteroid.setH(asteroid.getH() - rotation * ASTEROID_SPEED * dt)
        if asteroid.getY() < self.camera.getY() + 10:
          asteroid.setX(randint(MIN_X, MAX_X))
          asteroid.setY(randint(ASTEROID_SPAWN_MIN_Y, ASTEROID_SPAWN_MAX_Y))
          asteroid.setZ(randint(MIN_Z, MAX_Z))
    return task.cont

  def rollbackOnBoard(self, minPos, maxPos, getFunc, setFunc):
    if getFunc() < minPos:
      setFunc(minPos)
    if getFunc() > maxPos:
      setFunc(maxPos)

  def applyBound(self):
    self.rollbackOnBoard(MIN_X, MAX_X, self.ship.getX, self.ship.setX)
    self.rollbackOnBoard(MIN_Z, MAX_Z, self.ship.getZ, self.ship.setZ)

  def moveShip(self, task):
    dt = globalClock.getDt()
    if not self.gamePause:
      if self.keyMap['left']:
        self.ship.setX(self.ship.getX() - SHIP_SPEED * dt)
        self.ship.setH(TURN_SPEED)
      elif self.keyMap['right']:
        self.ship.setX(self.ship.getX() + SHIP_SPEED * dt)
        self.ship.setH(-TURN_SPEED)
      elif self.keyMap['up']:
        self.ship.setZ(self.ship.getZ() + SHIP_SPEED * dt)
        self.ship.setP(TURN_SPEED)
      elif self.keyMap['down']:
        self.ship.setZ(self.ship.getZ() - 5 * SHIP_SPEED * dt)
        self.ship.setP(-TURN_SPEED)

      self.sky.setP(self.sky.getP() - dt * 10)
      self.applyBound()
      self.updateCamera()

    return task.cont

  def handleCollisions(self, task):
    if not self.gamePause:
      for entry in self.queue.getEntries():
        node = entry.getFromNodePath()
        if node.getName() == 'ship_collision':
          self.gamePause = True
          self.text.setText('You lose :(')
    return task.cont

  def pause(self):
    self.gamePause = not self.gamePause

  def reloadGame(self):
    self.gamePause = False
    self.text.clearText()

    if hasattr(self, 'asteroids'):
      for asteroid in self.asteroids:
        asteroid.removeNode()

    self.asteroids = []
    self.asteroids_rotation = []

    if hasattr(self, 'ship'):
      self.ship.removeNode()

    self.loadShip()

    for _ in xrange(ASTEROID_MAX_CNT):
      self.spawnAsteroid()
Example #7
0
class Raycaster(Entity):

    def __init__(self):
        super().__init__(
            name = 'raycaster',
            eternal = True
            )
        self._picker = CollisionTraverser()  # Make a traverser
        self._pq = CollisionHandlerQueue()  # Make a handler
        self._pickerNode = CollisionNode('raycaster')
        self._pickerNP = self.attach_new_node(self._pickerNode)
        self._collision_ray = CollisionRay()  # Make our ray
        self._pickerNode.addSolid(self._collision_ray)
        self._picker.addCollider(self._pickerNP, self._pq)
        self._pickerNP.show()


    def distance(self, a, b):
        return math.sqrt(sum( (a - b)**2 for a, b in zip(a, b)))


    def raycast(self, origin, direction=(0,0,1), dist=math.inf, traverse_target=scene, ignore=list(), debug=False):
        self.position = origin
        self.look_at(self.position + direction)
        # need to do this for it to work for some reason
        self._collision_ray.set_origin(Vec3(0,0,0))
        self._collision_ray.set_direction(Vec3(0,1,0))

        if debug:
            self._pickerNP.show()
        else:
            self._pickerNP.hide()

        self._picker.traverse(traverse_target)

        if self._pq.get_num_entries() == 0:
            self.hit = Hit(hit=False)
            return self.hit

        self._pq.sort_entries()
        self.entries = [        # filter out ignored entities
            e for e in self._pq.getEntries()
            if e.get_into_node_path().parent not in ignore
            ]

        if len(self.entries) == 0:
            self.hit = Hit(hit=False)
            return self.hit

        self.collision = self.entries[0]
        nP = self.collision.get_into_node_path().parent
        point = self.collision.get_surface_point(nP)
        point = Vec3(point[0], point[2], point[1])
        world_point = self.collision.get_surface_point(render)
        world_point = Vec3(world_point[0], world_point[2], world_point[1])
        hit_dist = self.distance(self.world_position, world_point)
        if hit_dist <= dist:
            if nP.name.endswith('.egg'):
                nP = nP.parent

            self.hit = Hit(hit=True)
            for e in scene.entities:
                if e == nP:
                    # print('cast nP to Entity')
                    self.hit.entity = e

            self.hit.point = point
            self.hit.world_point = world_point
            self.hit.distance = hit_dist
            normal = self.collision.get_surface_normal(self.collision.get_into_node_path().parent)
            self.hit.normal = (normal[0], normal[2], normal[1])
            normal = self.collision.get_surface_normal(render)
            self.hit.world_normal = (normal[0], normal[2], normal[1])
            return self.hit

        self.hit = Hit(hit=False)
        return self.hit
class RoamingRalphDemo(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)
        self.orbCollisionHandler = CollisionHandlerQueue()
        self.cTrav = CollisionTraverser()

        #hbPath = NodePath()

        utils3.setUpKeys(self)
        utils3.loadModels(self)
        utils3.setUpLighting(self)
        utils3.setUpFloatingSpheres(self)
        utils3.setUpRalphsShot(self)
        utils3.setUpCamera(self)
        self.healthTxt = utils3.addInstructions(.06,"Health: 100")
        self.orbTxt = utils3.addInstructions(.18,"Orbs: 0")

        self.vec = LVector3(0,1,0)#vector for pawns shot

        # Create a frame
        #frame = DirectFrame(text = "main", scale = 0.001)
        # Add button
        #bar = DirectWaitBar(text = "", value = 50, pos = (0,.4,.4))
        #bar.reparent(render)

        # Game state variables
        self.isMoving = False
        self.jumping = False
        self.vz = 0
        self.numOrbs = 0
        self.healthCount = 100

        #self.shotList = []
        taskMgr.add(self.move, "moveTask")
        #taskMgr.add(utils2.moveChris,"moveChrisTask")
        
        self.sphere = CollisionSphere(0,0,4,2)
        self.sphere2 = CollisionSphere(0,0,2,2)
        self.cnodePath = self.ralph.attachNewNode((CollisionNode('ralphColNode')))
        self.cnodePath.node().addSolid(self.sphere)
        self.cnodePath.node().addSolid(self.sphere2)
        #self.cnodePath.show()
        
        self.pusher = CollisionHandlerPusher()
        self.pusher.addCollider(self.cnodePath, self.ralph)

        #self.cTrav.addCollider(self.cnodePath, self.ralphCollisionHandler)
        self.cTrav.addCollider(self.cnodePath, self.pusher)

        ca = CollisionSphere(0,0,0,20)
        cb = self.chik.attachNewNode(CollisionNode('chikCollisionNode'))
        cb.node().addSolid(ca)
        cb.show()

        cc = CollisionSphere(3,5,12,25)
        cd = self.gianteye.attachNewNode(CollisionNode('gianteyeCollisionNode'))
        cd.node().addSolid(cc)
        cd.show()

        ci = CollisionSphere(0,0,0,2)
        coi = self.catidol.attachNewNode(CollisionNode('catidolCollisionNode'))
        coi.node().addSolid(ci)
        coi.show()

        chi = CollisionSphere(-1,3,3,3)
        chco = self.chris.attachNewNode(CollisionNode('chrisColPath'))
        chco.node().addSolid(chi)
        self.cTrav.addCollider(chco, self.orbCollisionHandler)
        #chco.show()

        self.chris.setH(90)
        self.chris.setR(-90)
        self.chris.setZ(2)

        #cbox = CollisionBox((-50,30,20),10,85,20)
        #cboxPath = self.room.attachNewNode(CollisionNode('roomSide1'))
        #cboxPath.node().addSolid(cbox)
        #cboxPath.show()

        #cbox2 = CollisionBox((200,30,20),10,85,20)
        #cboxPath2 = self.room.attachNewNode(CollisionNode('roomSide1'))
        #cboxPath2.node().addSolid(cbox2)
        #cboxPath2.show()

        #cbox3 = CollisionBox((80,-60,20),120,20,20)
        #cboxPath3 = self.room.attachNewNode(CollisionNode('roomSide1'))
        #cboxPath3.node().addSolid(cbox3)
        #cboxPath3.show()

        ct = CollisionSphere(0,0,0,1)
        cn = self.pawn.attachNewNode(CollisionNode('pawnCollisionNode'))
        cn.node().addSolid(ct)
        cn.show()

        cs2 = CollisionSphere(0,0,0,.2)
        cs2path = self.plnp.attachNewNode((CollisionNode('orbColPath')))
        cs2path.node().addSolid(cs2)
        cs2path.show()

        self.cTrav.addCollider(cs2path, self.orbCollisionHandler)

        #cs3 = CollisionSphere(0,0,0,1)
        cs3path = self.plnp2.attachNewNode((CollisionNode('orbColPath')))
        cs3path.node().addSolid(cs2)
        cs3path.show()

        chrisShotNp = self.chrisShot.attachNewNode((CollisionNode("enemyOrbColPath")))
        chrisShotNp.node().addSolid(cs2)
        chrisShotNp.show()

        self.cTrav.addCollider(cs3path, self.orbCollisionHandler)
        self.cTrav.addCollider(chrisShotNp, self.orbCollisionHandler)


        # Uncomment this line to show a visual representation of the
        # collisions occuring
        self.cTrav.showCollisions(render)

        self.chrisLastShotTime = globalClock.getFrameTime()
        self.chrisTimer = globalClock.getDt()

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):


        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()
        utils3.moveChris(self,dt)

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        if self.keyMap["cam-left"]:
            self.camera.setZ(self.camera, -20 * dt)
        if self.keyMap["cam-right"]:
            self.camera.setZ(self.camera, +20 * dt)

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if self.keyMap["left"]:
            self.ralph.setH(self.ralph.getH() + 150 * dt)
            #self.camera.setX(self.camera, +15.5 * dt)
        if self.keyMap["right"]:
            self.ralph.setH(self.ralph.getH() - 150 * dt)
            #self.camera.setX(self.camera, -15.5 * dt)
        if self.keyMap["forward"]:
            self.ralph.setY(self.ralph, -35 * dt)
            #self.camera.setY(self.camera, -35 * dt)
        if self.keyMap["back"]:
            self.ralph.setY(self.ralph, +35 * dt)
            #self.camera.setY(self.camera, 35 * dt)
        if self.keyMap["c"]:
            if self.jumping is False:
            #self.ralph.setZ(self.ralph.getZ() + 100 * dt)
                self.jumping = True
                self.vz = 7

        if self.keyMap["space"]:
            self.keyMap["space"] = False
            self.shotList[self.shotCount].lpivot.setPos(self.ralph.getPos())
            self.shotList[self.shotCount].lpivot.setZ(self.ralph.getZ() + .5)
            self.shotList[self.shotCount].lpivot.setX(self.ralph.getX() - .25)

            #self.shotList.append(rShot)
            #self.lightpivot3.setPos(self.ralph.getPos())
            #self.lightpivot3.setZ(self.ralph.getZ() + .5)
            #self.lightpivot3.setX(self.ralph.getX() - .25)
            #self.myShot.setHpr(self.ralph.getHpr())
            #parent to ralph
            #node = NodePath("tmp")
            #node.setHpr(self.ralph.getHpr())
            #vec = render.getRelativeVector(node,(0,-1,0))
            #self.myShotVec = vec

            node = NodePath("tmp")
            node.setHpr(self.ralph.getHpr())
            vec = render.getRelativeVector(node,(0,-1,0))
            self.shotList[self.shotCount].vec = vec
            self.shotCount = (self.shotCount + 1) % 5


        for rs in self.shotList:
            rs.lpivot.setPos(rs.lpivot.getPos() + rs.vec * dt * 15 )
            #if shot is too far stop updating



        if self.jumping is True:
            self.vz = self.vz - 16* dt
            self.ralph.setZ(self.ralph.getZ() + self.vz * dt )
            if self.ralph.getZ() < 0:
                self.ralph.setZ(0)
                self.jumping = False
        else:
            if self.ralph.getZ() < 0:
                self.ralph.setZ(0)
            elif self.ralph.getZ() > 0:
                self.ralph.setZ(self.ralph.getZ() -7 * dt)

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.
        if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"] or self.keyMap["c"] or self.keyMap["forward"] or self.keyMap["back"]:
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True

        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        # update pawns shot or set up new shot after it reaches a certain distance
        node = NodePath("tmp")
        node.setHpr(self.pawn.getHpr())
        vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))
        self.shot.setPos(self.shot.getPos() + self.vec * dt * 10 )
        if self.shot.getY() < -15 or self.shot.getY() > 30 or self.shot.getX() < 5 or self.shot.getX() > 15:
            self.shot.setPos(self.pawn.getPos() + (0,0,0))
            self.vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))
            self.vec = render.getRelativeVector(node,(random.random() * random.randrange(-1,2),random.random() + 1,0))

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.
        #self.camera.lookAt(self.floater)
        camvec = self.ralph.getPos() - self.camera.getPos()
        #camvec = Vec3(0,camvec.getY(),0)
        camdist = camvec.length()
        x = self.camera.getZ()
        camvec.normalize()
        #if camdist > 6.0:
        #    self.camera.setPos(self.camera.getPos() + camvec * (camdist - 6))
        #if camdist < 6.0:
        #    self.camera.setPos(self.camera.getPos() - camvec * (6 - camdist))

        # Normally, we would have to call traverse() to check for collisions.
        # However, the class ShowBase that we inherit from has a task to do
        # this for us, if we assign a CollisionTraverser to self.cTrav.
        #self.cTrav.traverse(render)

        # Adjust camera so it stays at same height
        if self.camera.getZ() < self.ralph.getZ() + 1 or self.camera.getZ() > self.ralph.getZ() + 1:
            self.camera.setZ(self.ralph.getZ() + 1)

        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.
        self.camera.lookAt(self.floater)


        entries = list(self.orbCollisionHandler.getEntries())
        if(len(entries) > 0):
            #self.lightpivot.reparentTo(NodePath())
            for entry in self.orbCollisionHandler.getEntries():
                #print(entry)
                fromColNp = entry.getFromNodePath()
                toColNp = entry.getIntoNodePath()
                if fromColNp.getName() == "orbColPath" and toColNp.getName() == "ralphColNode":
                    fromColNp.getParent().reparentTo(NodePath())
                    self.orbTxt.destroy()
                    self.numOrbs += 1
                    str1 = "Orbs: " + str(self.numOrbs)
                    self.orbTxt = utils3.addInstructions(.18, str1)
                elif toColNp.getName() == "orbColPath" and fromColNp.getName() == "ralphColNode":
                    toColNp.getParent().reparentTo(NodePath())
                    self.orbTxt.destroy()
                    self.numOrbs += 1
                    str1 = "Orbs: " + str(self.numOrbs)
                    self.orbTxt = utils3.addInstructions(.18, str1)
                elif toColNp.getName() == "ralphOrbColPath" and fromColNp.getName() == "chrisColPath":
                    toColNp.getParent().setPos(-50,0,2)
                    self.chrisHealth = self.chrisHealth - 1
                    self.chris.setColor(1,0,0,1)
                    self.chrisHit = True
                    self.chrisRedTime = globalClock.getFrameTime()
                    #print self.chrisRedTime
                    if self.chrisHealth < 0:
                        fromColNp.getParent().removeNode()
                        self.chrisAlive = False
                elif toColNp.getName() == "chrisColPath" and fromColNp.getName() == "ralphOrbColPath":
                    fromColNp.getParent().setPos(-50,0,2)
                    self.chrisHealth = self.chrisHealth - 1
                    self.chris.setColor(1,0,0,1)
                    self.chrisHit = True
                    self.chrisRedTime = globalClock.getFrameTime()
                    #print self.chrisRedTime
                    if self.chrisHealth < 0:
                        fromColNp.getParent().removeNode()
                        self.chrisAlive = False
                        self.chrisShot.setZ(26)
                elif toColNp.getName() == "enemyOrbColPath" and fromColNp.getName() == "ralphColNode":
                    toColNp.getParent().setZ(26)
                    self.healthTxt.destroy()
                    self.healthCount -= 3
                    str1 = "Health: " + str(self.healthCount)
                    self.healthTxt = utils3.addInstructions(.06, str1)
                elif toColNp.getName() == "ralphColNode" and fromColNp.getName() == "enemyOrbColPath":
                    fromColNp.getParent().setZ(26)
                    self.healthTxt.destroy()
                    self.healthCount -= 3
                    str1 = "Health: " + str(self.healthCount)
                    self.healthTxt = utils3.addInstructions(.06, str1)



        return task.cont
Example #9
0
class RoamingRalphDemo(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)

        # Create and configure the VR environment

        self.ovr = P3DOpenVR()
        self.ovr.init(msaa=4)
        main_dir = ExecutionEnvironment.getEnvironmentVariable("MAIN_DIR")
        # Setup the application manifest, it will identify and configure the app
        # We force it in case it has changed.
        self.ovr.identify_application(os.path.join(main_dir,
                                                   "ralph.vrmanifest"),
                                      "p3dopenvr.demo.ralph",
                                      force=True)
        # Load the actions manifest, it must be the same as the manifest referenced in the application manifest
        self.ovr.load_action_manifest(
            os.path.join(main_dir, "manifest/actions.json"))
        # Use the '/actions/platformer' action set. This action set will be updated each frame
        self.ovr.add_action_set("/actions/platformer")
        # Get the handle of the action '/actions/platformer/in/Move'. This hande will be used to retrieve the data of the action.
        self.action_move = self.ovr.vr_input.getActionHandle(
            '/actions/platformer/in/Move')

        # Set the background color to black
        self.win.setClearColor((0, 0, 0, 1))

        # Post the instructions
        self.title = addTitle(
            "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.06, "[ESC]: Quit")
        self.inst2 = addInstructions(0.12, "[Left trackpad]: Rotate Left")
        self.inst3 = addInstructions(0.18, "[Right trackpad]: Rotate Right")
        self.inst4 = addInstructions(0.24, "[Up trackpad]: Walk Forward")
        self.inst4 = addInstructions(0.30, "[Down trackpad]: Walk Backward")

        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)

        # Create the main character, Ralph

        self.ralph = render.attachNewNode('ralph')
        self.ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ovr.tracking_space.setPos(self.ralphStartPos)
        self.ralph.setPos(self.ovr.hmd_anchor.getPos(render))

        self.accept("escape", sys.exit)

        taskMgr.add(self.move, "moveTask")
        taskMgr.add(self.collision, "collisionTask")

        # Set up the camera
        self.disableMouse()

        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above ralph's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.
        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 9)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.ralphGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        # Uncomment this line to see the collision rays
        #self.ralphGroundColNp.show()

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #self.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    # Move camera according to user's input
    def move(self, task):
        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()

        # If a move-button is touched, move in the specified direction.
        move_data, device_path = self.ovr.get_analog_action_value(
            self.action_move)
        if move_data is not None:
            x, y = move_data.x, move_data.y
            # The x coordinate is used to turn the camera
            self.ovr.tracking_space.setH(self.ovr.tracking_space.getH() -
                                         x * 60 * dt)
            # The y coordinate is used to move the camera along the view vector
            # We retrieve the orientation of the headset and we generate a 2D direction
            orientation = self.ovr.hmd_anchor.get_quat(render)
            vector = orientation.xform(LVector3(0, 1, 0))
            vector[2] = 0
            vector.normalize()
            # Use the vector and the x value to move the camera relative to itself
            self.ovr.tracking_space.setPos(self.ovr.tracking_space.getPos() +
                                           vector * (y * 5 * dt))

        return task.cont

    # Grid checking and collision detection
    def collision(self, task):

        # Normally, we would have to call traverse() to check for collisions.
        # However, the class ShowBase that we inherit from has a task to do
        # this for us, if we assign a CollisionTraverser to self.cTrav.
        #self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = list(self.ralphGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName(
        ) == "terrain":
            self.ovr.tracking_space.setZ(
                entries[0].getSurfacePoint(render).getZ())
        else:
            self.ovr.tracking_space.setPos(self.ralphStartPos)
        self.ralph.setPos(self.ovr.hmd_anchor.getPos(render))

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        self.ralphStartPos = self.ovr.tracking_space.getPos()

        return task.cont
Example #10
0
class Entity(NodePath):

    rotation_directions = (-1,-1,1)
    default_shader = None

    def __init__(self, add_to_scene_entities=True, **kwargs):
        super().__init__(self.__class__.__name__)

        self.name = camel_to_snake(self.type)
        self.enabled = True     # disabled entities wil not be visible nor run code
        self.visible = True
        self.ignore = False     # if True, will not try to run code
        self.eternal = False    # eternal entities does not get destroyed on scene.clear()
        self.ignore_paused = False
        self.ignore_input = False

        self.parent = scene
        self.add_to_scene_entities = add_to_scene_entities # set to False to be ignored by the engine, but still get rendered.
        if add_to_scene_entities:
            scene.entities.append(self)

        self.model = None       # set model with model='model_name' (without file type extention)
        self.color = color.white
        self.texture = None     # set model with texture='texture_name'. requires a model to be set beforehand.
        self.reflection_map = scene.reflection_map
        self.reflectivity = 0
        self.render_queue = 0
        self.double_sided = False
        self.shader = Entity.default_shader
        # self.always_on_top = False

        self.collision = False  # toggle collision without changing collider.
        self.collider = None    # set to 'box'/'sphere'/'mesh' for auto fitted collider.
        self.scripts = list()   # add with add_script(class_instance). will assign an 'entity' variable to the script.
        self.animations = list()
        self.hovered = False    # will return True if mouse hovers entity.

        self.origin = Vec3(0,0,0)
        self.position = Vec3(0,0,0) # right, up, forward. can also set self.x, self.y, self.z
        self.rotation = Vec3(0,0,0) # can also set self.rotation_x, self.rotation_y, self.rotation_z
        self.scale = Vec3(1,1,1)    # can also set self.scale_x, self.scale_y, self.scale_z

        self.line_definition = None # returns a Traceback(filename, lineno, function, code_context, index).
        if application.trace_entity_definition and add_to_scene_entities:
            from inspect import getframeinfo, stack
            _stack = stack()
            caller = getframeinfo(_stack[1][0])
            if len(_stack) > 2 and _stack[1].code_context and 'super().__init__()' in _stack[1].code_context[0]:
                caller = getframeinfo(_stack[2][0])

            self.line_definition = caller
            if caller.code_context:
                self.code_context = caller.code_context[0]

                if (self.code_context.count('(') == self.code_context.count(')') and
                ' = ' in self.code_context and not 'name=' in self.code_context
                and not 'Ursina()' in self.code_context):

                    self.name = self.code_context.split(' = ')[0].strip().replace('self.', '')
                    # print('set name to:', self.code_context.split(' = ')[0].strip().replace('self.', ''))

                if application.print_entity_definition:
                    print(f'{Path(caller.filename).name} ->  {caller.lineno} -> {caller.code_context}')


        for key, value in kwargs.items():
            setattr(self, key, value)




    def _list_to_vec(self, value):
        if isinstance(value, (int, float, complex)):
            return Vec3(value, value, value)

        if len(value) % 2 == 0:
            new_value = Vec2()
            for i in range(0, len(value), 2):
                new_value.add_x(value[i])
                new_value.add_y(value[i+1])

        if len(value) % 3 == 0:
            new_value = Vec3()
            for i in range(0, len(value), 3):
                new_value.add_x(value[i])
                new_value.add_y(value[i+1])
                new_value.add_z(value[i+2])

        return new_value


    def enable(self):
        self.enabled = True

    def disable(self):
        self.enabled = False


    def __setattr__(self, name, value):

        if name == 'enabled':
            try:
                # try calling on_enable() on classes inheriting from Entity
                if value == True:
                    self.on_enable()
                else:
                    self.on_disable()
            except:
                pass

            if value == True:
                if hasattr(self, 'is_singleton') and not self.is_singleton():
                    self.unstash()
            else:
                if hasattr(self, 'is_singleton') and not self.is_singleton():
                    self.stash()

        if name == 'eternal':
            for c in self.children:
                c.eternal = value

        if name == 'world_parent':
            self.reparent_to(value)

        if name == 'model':
            if value is None:
                if hasattr(self, 'model') and self.model:
                    self.model.removeNode()
                    # print('removed model')
                object.__setattr__(self, name, value)
                return None

            if isinstance(value, NodePath): # pass procedural model
                if self.model is not None and value != self.model:
                    self.model.removeNode()
                object.__setattr__(self, name, value)

            elif isinstance(value, str): # pass model asset name
                m = load_model(value, application.asset_folder)
                if not m:
                    m = load_model(value, application.internal_models_compressed_folder)
                if m:
                    if self.model is not None:
                        self.model.removeNode()
                    object.__setattr__(self, name, m)
                    # if isinstance(m, Mesh):
                    #     m.recipe = value
                    # print('loaded model successively')
                else:
                    # if '.' in value:
                    #     print(f'''trying to load model with specific filename extention. please omit it. '{value}' -> '{value.split('.')[0]}' ''')
                    print('missing model:', value)
                    return

            if self.model:
                self.model.reparentTo(self)
                self.model.setTransparency(TransparencyAttrib.M_dual)
                self.color = self.color # reapply color after changing model
                self.texture = self.texture # reapply texture after changing model
                self._vert_cache = None
                if isinstance(value, Mesh):
                    if hasattr(value, 'on_assign'):
                        value.on_assign(assigned_to=self)
            return

        if name == 'color' and value is not None:
            if isinstance(value, str):
                value = color.hex(value)

            if not isinstance(value, Vec4):
                value = Vec4(value[0], value[1], value[2], value[3])


            if self.model:
                self.model.setColorScaleOff() # prevent inheriting color from parent
                self.model.setColorScale(value)
                object.__setattr__(self, name, value)


        if name == 'collision' and hasattr(self, 'collider') and self.collider:
            if value:
                self.collider.node_path.unstash()
            else:
                self.collider.node_path.stash()

            object.__setattr__(self, name, value)
            return

        if name == 'render_queue':
            if self.model:
                self.model.setBin('fixed', value)

        if name == 'double_sided':
            self.setTwoSided(value)


        try:
            super().__setattr__(name, value)
        except:
            pass
            # print('failed to set attribiute:', name)


    @property
    def parent(self):
        try:
            return self._parent
        except:
            return None

    @parent.setter
    def parent(self, value):
        self._parent = value
        if value is None:
            destroy(self)
        else:
            try:
                self.reparentTo(value)
            except:
                print('invalid parent:', value)

    @property
    def type(self): # get class name.
        return self.__class__.__name__

    @property
    def types(self): # get all class names including those this inhertits from.
        from inspect import getmro
        return [c.__name__ for c in getmro(self.__class__)]


    @property
    def visible(self):
        return self._visible

    @visible.setter
    def visible(self, value):
        self._visible = value
        if value:
            self.show()
        else:
            self.hide()

    @property
    def visible_self(self): # set visibility of self, without affecting children.
        if not hasattr(self, '_visible_self'):
            return True
        return self._visible_self

    @visible_self.setter
    def visible_self(self, value):
        self._visible_self = value
        if not self.model:
            return
        if value:
            self.model.show()
        else:
            self.model.hide()


    @property
    def collider(self):
        return self._collider

    @collider.setter
    def collider(self, value):
        # destroy existing collider
        if value and hasattr(self, 'collider') and self._collider:
            self._collider.remove()

        self._collider = value

        if value == 'box':
            if self.model:
                self._collider = BoxCollider(entity=self, center=-self.origin, size=self.model_bounds)
            else:
                self._collider = BoxCollider(entity=self)
            self._collider.name = value

        elif value == 'sphere':
            self._collider = SphereCollider(entity=self, center=-self.origin)
            self._collider.name = value

        elif value == 'mesh' and self.model:
            self._collider = MeshCollider(entity=self, mesh=None, center=-self.origin)
            self._collider.name = value

        elif isinstance(value, Mesh):
            self._collider = MeshCollider(entity=self, mesh=value, center=-self.origin)

        elif isinstance(value, str):
            m = load_model(value)
            if not m:
                return
            self._collider = MeshCollider(entity=self, mesh=m, center=-self.origin)
            self._collider.name = value


        self.collision = bool(self.collider)
        return


    @property
    def origin(self):
        return self._origin

    @origin.setter
    def origin(self, value):
        if not self.model:
            self._origin = Vec3(0,0,0)
            return
        if not isinstance(value, (Vec2, Vec3)):
            value = self._list_to_vec(value)
        if isinstance(value, Vec2):
            value = Vec3(*value, self.origin_z)

        self._origin = value
        self.model.setPos(-value[0], -value[1], -value[2])


    @property
    def origin_x(self):
        return self.origin[0]
    @origin_x.setter
    def origin_x(self, value):
        self.origin = (value, self.origin_y, self.origin_z)

    @property
    def origin_y(self):
        return self.origin[1]
    @origin_y.setter
    def origin_y(self, value):
        self.origin = (self.origin_x, value, self.origin_z)

    @property
    def origin_z(self):
        return self.origin[2]
    @origin_z.setter
    def origin_z(self, value):
        self.origin = (self.origin_x, self.origin_y, value)

    @property
    def world_position(self):
        return Vec3(self.get_position(render))

    @world_position.setter
    def world_position(self, value):
        if not isinstance(value, (Vec2, Vec3)):
            value = self._list_to_vec(value)
        if isinstance(value, Vec2):
            value = Vec3(*value, self.z)

        self.setPos(render, Vec3(value[0], value[1], value[2]))

    @property
    def world_x(self):
        return self.getX(render)
    @property
    def world_y(self):
        return self.getY(render)
    @property
    def world_z(self):
        return self.getZ(render)

    @world_x.setter
    def world_x(self, value):
        self.setX(render, value)
    @world_y.setter
    def world_y(self, value):
        self.setY(render, value)
    @world_z.setter
    def world_z(self, value):
        self.setZ(render, value)

    @property
    def position(self):
        return Vec3(*self.getPos())

    @position.setter
    def position(self, value):
        if not isinstance(value, (Vec2, Vec3)):
            value = self._list_to_vec(value)
        if isinstance(value, Vec2):
            value = Vec3(*value, self.z)

        self.setPos(value[0], value[1], value[2])

    @property
    def x(self):
        return self.getX()
    @x.setter
    def x(self, value):
        self.setX(value)

    @property
    def y(self):
        return self.getY()
    @y.setter
    def y(self, value):
        self.setY(value)

    @property
    def z(self):
        return self.getZ()
    @z.setter
    def z(self, value):
        self.setZ(value)

    @property
    def world_rotation(self):
        rotation = self.getHpr(base.render)
        return Vec3(rotation[1], rotation[0], rotation[2]) * Entity.rotation_directions
    @world_rotation.setter
    def world_rotation(self, value):
        rotation = self.setHpr(Vec3(value[1], value[0], value[2]) * Entity.rotation_directions, base.render)

    @property
    def world_rotation_x(self):
        return self.world_rotation[0]

    @world_rotation_x.setter
    def world_rotation_x(self, value):
        self.world_rotation = Vec3(value, self.world_rotation[1], self.world_rotation[2])

    @property
    def world_rotation_y(self):
        return self.world_rotation[1]

    @world_rotation_y.setter
    def world_rotation_y(self, value):
        self.world_rotation = Vec3(self.world_rotation[0], value, self.world_rotation[2])

    @property
    def world_rotation_z(self):
        return self.world_rotation[2]

    @world_rotation_z.setter
    def world_rotation_z(self, value):
        self.world_rotation = Vec3(self.world_rotation[0], self.world_rotation[1], value)

    @property
    def rotation(self):
        rotation = self.getHpr()
        return Vec3(rotation[1], rotation[0], rotation[2]) * Entity.rotation_directions

    @rotation.setter
    def rotation(self, value):
        if not isinstance(value, (Vec2, Vec3)):
            value = self._list_to_vec(value)
        if isinstance(value, Vec2):
            value = Vec3(*value, self.rotation_z)

        self.setHpr(Vec3(value[1], value[0], value[2]) * Entity.rotation_directions)

    @property
    def rotation_x(self):
        return self.rotation.x
    @rotation_x.setter
    def rotation_x(self, value):
        self.rotation = Vec3(value, self.rotation[1], self.rotation[2])

    @property
    def rotation_y(self):
        return self.rotation.y
    @rotation_y.setter
    def rotation_y(self, value):
        self.rotation = Vec3(self.rotation[0], value, self.rotation[2])

    @property
    def rotation_z(self):
        return self.rotation.z
    @rotation_z.setter
    def rotation_z(self, value):
        self.rotation = Vec3(self.rotation[0], self.rotation[1], value)

    @property
    def world_scale(self):
        return Vec3(*self.getScale(base.render))
    @world_scale.setter
    def world_scale(self, value):
        if isinstance(value, (int, float, complex)):
            value = Vec3(value, value, value)

        self.setScale(base.render, value)

    @property
    def world_scale_x(self):
        return self.getScale(base.render)[0]
    @world_scale_x.setter
    def world_scale_x(self, value):
        self.setScale(base.render, Vec3(value, self.world_scale_y, self.world_scale_z))

    @property
    def world_scale_y(self):
        return self.getScale(base.render)[1]
    @world_scale_y.setter
    def world_scale_y(self, value):
        self.setScale(base.render, Vec3(self.world_scale_x, value, self.world_scale_z))

    @property
    def world_scale_z(self):
        return self.getScale(base.render)[2]
    @world_scale_z.setter
    def world_scale_z(self, value):
        self.setScale(base.render, Vec3(self.world_scale_x, value, self.world_scale_z))

    @property
    def scale(self):
        scale = self.getScale()
        return Vec3(scale[0], scale[1], scale[2])

    @scale.setter
    def scale(self, value):
        if not isinstance(value, (Vec2, Vec3)):
            value = self._list_to_vec(value)
        if isinstance(value, Vec2):
            value = Vec3(*value, self.scale_z)

        value = [e if e!=0 else .001 for e in value]
        self.setScale(value[0], value[1], value[2])

    @property
    def scale_x(self):
        return self.scale[0]
    @scale_x.setter
    def scale_x(self, value):
        self.setScale(value, self.scale_y, self.scale_z)

    @property
    def scale_y(self):
        return self.scale[1]
    @scale_y.setter
    def scale_y(self, value):
        self.setScale(self.scale_x, value, self.scale_z)

    @property
    def scale_z(self):
        return self.scale[2]
    @scale_z.setter
    def scale_z(self, value):
        self.setScale(self.scale_x, self.scale_y, value)

    @property
    def forward(self): # get forward direction.
        return render.getRelativeVector(self, (0, 0, 1))
    @property
    def back(self): # get backwards direction.
        return -self.forward
    @property
    def right(self): # get right direction.
        return render.getRelativeVector(self, (1, 0, 0))
    @property
    def left(self): # get left direction.
        return -self.right
    @property
    def up(self): # get up direction.
        return render.getRelativeVector(self, (0, 1, 0))
    @property
    def down(self): # get down direction.
        return -self.up

    @property
    def screen_position(self): # get screen position(ui space) from world space.
        from ursina import camera
        p3 = camera.getRelativePoint(self, Vec3.zero())
        full = camera.lens.getProjectionMat().xform(Vec4(*p3, 1))
        recip_full3 = 1 / full[3]
        p2 = Vec3(full[0], full[1], full[2]) * recip_full3
        screen_pos = Vec3(p2[0]*camera.aspect_ratio/2, p2[1]/2, 0)
        return screen_pos

    @property
    def shader(self):
        return self._shader

    @shader.setter
    def shader(self, value):
        self._shader = value
        if value is None:
            self.setShaderAuto()
            return

        if isinstance(value, Panda3dShader): #panda3d shader
            self.setShader(value)
            return

        if isinstance(value, Shader):
            if not value.compiled:
                value.compile()

            self.setShader(value._shader)
            value.entity = self

            for key, value in value.default_input.items():
                self.set_shader_input(key, value)



    def set_shader_input(self, name, value):
        if isinstance(value, Texture):
            value = value._texture    # make sure to send the panda3d texture to the shader

        super().set_shader_input(name, value)




    @property
    def texture(self):
        if not hasattr(self, '_texture'):
            return None
        return self._texture

    @texture.setter
    def texture(self, value):
        if value is None and self._texture:
            # print('remove texture')
            self._texture = None
            self.setTextureOff(True)
            return

        if value.__class__ is Texture:
            texture = value

        elif isinstance(value, str):
            texture = load_texture(value)
            # print('loaded texture:', texture)
            if texture is None:
                print('no texture:', value)
                return

        if texture.__class__ is MovieTexture:
            self._texture = texture
            self.model.setTexture(texture, 1)
            return

        self._texture = texture
        if self.model:
            self.model.setTexture(texture._texture, 1)


    @property
    def texture_scale(self):
        if not hasattr(self, '_texture_scale'):
            return Vec2(1,1)
        return self._texture_scale
    @texture_scale.setter
    def texture_scale(self, value):
        self._texture_scale = value
        if self.model and self.texture:
            self.model.setTexScale(TextureStage.getDefault(), value[0], value[1])

    @property
    def texture_offset(self):
        return self._texture_offset

    @texture_offset.setter
    def texture_offset(self, value):
        if self.model and self.texture:
            self.model.setTexOffset(TextureStage.getDefault(), value[0], value[1])
            self.texture = self.texture
        self._texture_offset = value


    @property
    def alpha(self):
        return self.color[3]

    @alpha.setter
    def alpha(self, value):
        if value > 1:
            value = value / 255
        self.color = color.color(self.color.h, self.color.s, self.color.v, value)


    @property
    def always_on_top(self):
        return self._always_on_top
    @always_on_top.setter
    def always_on_top(self, value):
        self._always_on_top = value
        self.set_bin("fixed", 0)
        self.set_depth_write(not value)
        self.set_depth_test(not value)

    @property
    def billboard(self): # set to True to make this Entity always face the camera.
        return self._billboard

    @billboard.setter
    def billboard(self, value):
        self._billboard = value
        if value:
            self.setBillboardPointEye(value)


    @property
    def reflection_map(self):
        return self._reflection_map

    @reflection_map.setter
    def reflection_map(self, value):
        if value.__class__ is Texture:
            texture = value

        elif isinstance(value, str):
            texture = load_texture(value)

        self._reflection_map = texture


    @property
    def reflectivity(self):
        return self._reflectivity

    @reflectivity.setter
    def reflectivity(self, value):
        self._reflectivity = value

        if value == 0:
            self.texture = None

        if value > 0:
            # if self.reflection_map == None:
            #     self.reflection_map = scene.reflection_map
            #
            # if not self.reflection_map:
            #     print('error setting reflectivity. no reflection map')
            #     return
            if not self.normals:
                self.model.generate_normals()

            # ts = TextureStage('env')
            # ts.setMode(TextureStage.MAdd)
            # self.model.setTexGen(ts, TexGenAttrib.MEyeSphereMap)
            # print('---------------set reflectivity', self.reflection_map)
            # self.model.setTexture(ts, self.reflection_map)

            self.texture = self._reflection_map
            # print('set reflectivity')

    def generate_sphere_map(self, size=512, name=f'sphere_map_{len(scene.entities)}'):
        from ursina import camera
        _name = 'textures/' + name + '.jpg'
        org_pos = camera.position
        camera.position = self.position
        base.saveSphereMap(_name, size=size)
        camera.position = org_pos

        print('saved sphere map:', name)
        self.model.setTexGen(TextureStage.getDefault(), TexGenAttrib.MEyeSphereMap)
        self.reflection_map = name


    def generate_cube_map(self, size=512, name=f'cube_map_{len(scene.entities)}'):
        from ursina import camera
        _name = 'textures/' + name
        org_pos = camera.position
        camera.position = self.position
        base.saveCubeMap(_name+'.jpg', size=size)
        camera.position = org_pos

        print('saved cube map:', name + '.jpg')
        self.model.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldCubeMap)
        self.reflection_map = _name + '#.jpg'
        self.model.setTexture(loader.loadCubeMap(_name + '#.jpg'), 1)


    @property
    def model_bounds(self):
        if self.model:
            bounds = self.model.getTightBounds()
            bounds = Vec3(
                Vec3(bounds[1][0], bounds[1][1], bounds[1][2])  # max point
                - Vec3(bounds[0][0], bounds[0][1], bounds[0][2])    # min point
                )
            return bounds

        return (0,0,0)

    @property
    def bounds(self):
        return Vec3(
            self.model_bounds[0] * self.scale_x,
            self.model_bounds[1] * self.scale_y,
            self.model_bounds[2] * self.scale_z
            )


    def reparent_to(self, entity):
        if entity is not None:
            self.wrtReparentTo(entity)

        self._parent = entity


    def get_position(self, relative_to=scene):
        return self.getPos(relative_to)


    def set_position(self, value, relative_to=scene):
        self.setPos(relative_to, Vec3(value[0], value[1], value[2]))


    def add_script(self, class_instance):
        if isinstance(class_instance, object) and type(class_instance) is not str:
            class_instance.entity = self
            class_instance.enabled = True
            setattr(self, camel_to_snake(class_instance.__class__.__name__), class_instance)
            self.scripts.append(class_instance)
            # print('added script:', camel_to_snake(name.__class__.__name__))
            return class_instance


    def combine(self, analyze=False, auto_destroy=True, ignore=[]):
        from ursina.scripts.combine import combine

        self.model = combine(self, analyze, auto_destroy, ignore)
        return self.model


    def flip_faces(self):
        if not hasattr(self, '_vertex_order'):
            self._vertex_order = True

        self._vertex_order = not self._vertex_order
        if self._vertex_order:
            self.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullClockwise))
        else:
            self.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullCounterClockwise))



    def look_at(self, target, axis='forward'):
        from panda3d.core import Quat
        if not isinstance(target, Entity):
            target = Vec3(*target)

        self.lookAt(target)
        if axis == 'forward':
            return

        rotation_offset = {
            'back'    : Quat(0,0,1,0),
            'down'    : Quat(-.707,.707,0,0),
            'up'      : Quat(-.707,-.707,0,0),
            'right'   : Quat(-.707,0,.707,0),
            'left'    : Quat(-.707,0,-.707,0),
            }[axis]

        self.setQuat(rotation_offset * self.getQuat())


    def look_at_2d(self, target, axis='z'):
        from math import degrees, atan2
        if isinstance(target, Entity):
            target = Vec3(target.world_position)

        pos = target - self.world_position
        if axis == 'z':
            self.rotation_z = degrees(atan2(pos[0], pos[1]))


    def has_ancestor(self, possible_ancestor):
        p = self
        if isinstance(possible_ancestor, Entity):
            # print('ENTITY')
            for i in range(100):
                if p.parent:
                    if p.parent == possible_ancestor:
                        return True

                    p = p.parent

        if isinstance(possible_ancestor, list) or isinstance(possible_ancestor, tuple):
            # print('LIST OR TUPLE')
            for e in possible_ancestor:
                for i in range(100):
                    if p.parent:
                        if p.parent == e:
                            return True
                            break
                        p = p.parent

        elif isinstance(possible_ancestor, str):
            print('CLASS NAME', possible_ancestor)
            for i in range(100):
                if p.parent:
                    if p.parent.__class__.__name__ == possible_ancestor:
                        return True
                        break
                    p = p.parent

        return False


    @property
    def children(self):
        return [e for e in scene.entities if e.parent == self]


    @property
    def attributes(self): # attribute names. used by duplicate() for instance.
        return ('name', 'enabled', 'eternal', 'visible', 'parent',
            'origin', 'position', 'rotation', 'scale',
            'model', 'color', 'texture', 'texture_scale', 'texture_offset',

            # 'world_position', 'world_x', 'world_y', 'world_z',
            # 'world_rotation', 'world_rotation_x', 'world_rotation_y', 'world_rotation_z',
            # 'world_scale', 'world_scale_x', 'world_scale_y', 'world_scale_z',
            # 'x', 'y', 'z',
            # 'origin_x', 'origin_y', 'origin_z',
            # 'rotation_x', 'rotation_y', 'rotation_z',
            # 'scale_x', 'scale_y', 'scale_z',

            'render_queue', 'always_on_top', 'collision', 'collider', 'scripts')

#------------
# ANIMATIONS
#------------
    def animate(self, name, value, duration=.1, delay=0, curve=curve.in_expo, loop=False, resolution=None, interrupt='kill', time_step=None, auto_destroy=True):
        animator_name = name + '_animator'
        # print('start animating value:', name, animator_name )
        if interrupt and hasattr(self, animator_name):
            getattr(getattr(self, animator_name), interrupt)() # call kill() or finish() depending on what the interrupt value is.
            # print('interrupt', interrupt, animator_name)

        sequence = Sequence(loop=loop, time_step=time_step, auto_destroy=auto_destroy)
        setattr(self, animator_name, sequence)
        self.animations.append(sequence)

        sequence.append(Wait(delay))
        if not resolution:
            resolution = max(int(duration * 60), 1)

        for i in range(resolution+1):
            t = i / resolution
            t = curve(t)

            sequence.append(Wait(duration / resolution))
            sequence.append(Func(setattr, self, name, lerp(getattr(self, name), value, t)))

        sequence.start()
        return sequence

    def animate_position(self, value, duration=.1, **kwargs):
        x = self.animate('x', value[0], duration,  **kwargs)
        y = self.animate('y', value[1], duration,  **kwargs)
        z = None
        if len(value) > 2:
            z = self.animate('z', value[2], duration, **kwargs)
        return x, y, z

    def animate_rotation(self, value, duration=.1,  **kwargs):
        x = self.animate('rotation_x', value[0], duration,  **kwargs)
        y = self.animate('rotation_y', value[1], duration,  **kwargs)
        z = self.animate('rotation_z', value[2], duration,  **kwargs)
        return x, y, z

    def animate_scale(self, value, duration=.1, **kwargs):
        if isinstance(value, (int, float, complex)):
            value = Vec3(value, value, value)
        return self.animate('scale', value, duration,  **kwargs)

    # generate animation functions
    for e in ('x', 'y', 'z', 'rotation_x', 'rotation_y', 'rotation_z', 'scale_x', 'scale_y', 'scale_z'):
        exec(dedent(f'''
            def animate_{e}(self, value, duration=.1, delay=0, **kwargs):
                return self.animate('{e}', value, duration=duration, delay=delay, **kwargs)
        '''))


    def shake(self, duration=.2, magnitude=1, speed=.05, direction=(1,1)):
        import random
        s = Sequence()
        original_position = self.position
        for i in range(int(duration / speed)):
            s.append(Func(self.set_position,
                Vec3(
                    original_position[0] + (random.uniform(-.1, .1) * magnitude * direction[0]),
                    original_position[1] + (random.uniform(-.1, .1) * magnitude * direction[1]),
                    original_position[2],
                )))
            s.append(Wait(speed))
            s.append(Func(self.set_position, original_position))

        s.start()
        return s

    def animate_color(self, value, duration=.1, interrupt='finish', **kwargs):
        return self.animate('color', value, duration, interrupt=interrupt, **kwargs)

    def fade_out(self, value=0, duration=.5, **kwargs):
        return self.animate('color', Vec4(self.color[0], self.color[1], self.color[2], value), duration,  **kwargs)

    def fade_in(self, value=1, duration=.5, **kwargs):
        return self.animate('color', Vec4(self.color[0], self.color[1], self.color[2], value), duration,  **kwargs)

    def blink(self, value=color.clear, duration=.1, delay=0, curve=curve.in_expo_boomerang, interrupt='finish', **kwargs):
        return self.animate_color(value, duration=duration, delay=delay, curve=curve, interrupt=interrupt, **kwargs)



    def intersects(self, traverse_target=scene, ignore=(), debug=False):
        from ursina.hit_info import HitInfo

        if not self.collision or not self.collider:
            self.hit = HitInfo(hit=False)
            return self.hit

        from ursina import distance
        if not hasattr(self, '_picker'):
            from panda3d.core import CollisionTraverser, CollisionNode, CollisionHandlerQueue
            from panda3d.core import CollisionRay, CollisionSegment, CollisionBox

            self._picker = CollisionTraverser()  # Make a traverser
            self._pq = CollisionHandlerQueue()  # Make a handler
            self._pickerNode = CollisionNode('raycaster')
            self._pickerNode.set_into_collide_mask(0)
            self._pickerNP = self.attach_new_node(self._pickerNode)
            self._picker.addCollider(self._pickerNP, self._pq)
            self._pickerNP.show()
            self._pickerNode.addSolid(self._collider.shape)

        if debug:
            self._pickerNP.show()
        else:
            self._pickerNP.hide()

        self._picker.traverse(traverse_target)

        if self._pq.get_num_entries() == 0:
            self.hit = HitInfo(hit=False)
            return self.hit

        ignore += (self, )
        ignore += tuple([e for e in scene.entities if not e.collision])

        self._pq.sort_entries()
        self.entries = [        # filter out ignored entities
            e for e in self._pq.getEntries()
            if e.get_into_node_path().parent not in ignore
            ]

        if len(self.entries) == 0:
            self.hit = HitInfo(hit=False, distance=0)
            return self.hit

        collision = self.entries[0]
        nP = collision.get_into_node_path().parent
        point = collision.get_surface_point(nP)
        point = Vec3(*point)
        world_point = collision.get_surface_point(render)
        world_point = Vec3(*world_point)
        hit_dist = distance(self.world_position, world_point)

        self.hit = HitInfo(hit=True)
        self.hit.entity = next(e for e in scene.entities if e == nP)

        self.hit.point = point
        self.hit.world_point = world_point
        self.hit.distance = hit_dist

        normal = collision.get_surface_normal(collision.get_into_node_path().parent).normalized()
        self.hit.normal = Vec3(*normal)

        normal = collision.get_surface_normal(render).normalized()
        self.hit.world_normal = Vec3(*normal)

        self.hit.entities = []
        for collision in self.entries:
            self.hit.entities.append(next(e for e in scene.entities if e == collision.get_into_node_path().parent))

        return self.hit
Example #11
0
class App(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.actorBullet = 0

        self.keyMap = {
            "cam-up": False,
            "cam-down": False,
            "cam-left": False,
            "cam-right": False,
            "up": False,
            "down": False,
            "left": False,
            "right": False,
            "shoot": False
        }

        #load environment model
        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)

        #load actor
        actorStartPos = self.environ.find("**/start_point").getPos()
        self.actor = Actor("models/ralph", {
            "run": "models/ralph-run",
            "walk": "models/ralph-walk"
        })
        self.actor.reparentTo(render)
        self.actor.setScale(.2)
        self.actor.setPos(actorStartPos + (0, 0, 0))

        #load bullets
        for bullets in range(self.actorBullet):
            print("making bullet")
            bullet = loader.loadModel("models/smiley")
            bullet.reparentTo(render)
            bullet.setPos(self.actor.getPos())

        #load floater which is the point of focus for the camera
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(self.actor)
        self.floater.setZ(2.0)

        self.disableMouse()
        # base.useDrive()
        self.camera.setPos(self.actor.getX(), self.actor.getY() + 10, 2.0)
        self.camera.lookAt(self.floater)

        #event handlers
        self.accept("arrow_up", self.setKey, ["cam-up", True])
        self.accept("arrow_up-up", self.setKey, ["cam-up", False])
        self.accept("arrow_down", self.setKey, ["cam-down", True])
        self.accept("arrow_down-up", self.setKey, ["cam-down", False])
        self.accept("arrow_left", self.setKey, ["cam-left", True])
        self.accept("arrow_left-up", self.setKey, ["cam-left", False])
        self.accept("arrow_right", self.setKey, ["cam-right", True])
        self.accept("arrow_right-up", self.setKey, ["cam-right", False])
        self.accept("w", self.setKey, ["up", True])
        self.accept("w-up", self.setKey, ["up", False])
        self.accept("a", self.setKey, ["left", True])
        self.accept("a-up", self.setKey, ["left", False])
        self.accept("s", self.setKey, ["down", True])
        self.accept("s-up", self.setKey, ["down", False])
        self.accept("d", self.setKey, ["right", True])
        self.accept("d-up", self.setKey, ["right", False])
        self.accept("space", self.setKey, ["shoot", True])
        self.accept("space-up", self.setKey, ["shoot", False])

        taskMgr.add(self.moveCamera, "moveCamera")

        self.isMoving = False

        #create collision traverser which handles all the collision stuff
        self.Traverser = CollisionTraverser()

        #create solid
        self.actorGroundRay = CollisionRay()
        #set origin and direction of the collision ray
        self.actorGroundRay.setOrigin(0, 0, 9)
        self.actorGroundRay.setDirection(0, 0, -1)
        #create the collision node
        self.actorGroundCol = CollisionNode('ralphRay')
        #attach solid to node
        self.actorGroundCol.addSolid(self.actorGroundRay)
        #attach node to actor. Create the node path
        self.actorGroundColNp = self.actor.attachNewNode(self.actorGroundCol)
        #create queue
        self.actorGroundHandler = CollisionHandlerQueue()
        #add nodepath and queue to traverser
        self.Traverser.addCollider(self.actorGroundColNp,
                                   self.actorGroundHandler)

        #show collision node
        # self.actorGroundColNp.show()

    def setKey(self, key, val):
        print(key, val)
        self.keyMap[key] = val

    def moveCamera(self, task):
        dt = globalClock.getDt()

        startPos = self.actor.getPos()

        #camera control
        if self.keyMap["cam-up"]:
            self.camera.setZ(self.camera, 20 * dt)
        if self.keyMap["cam-down"]:
            self.camera.setZ(self.camera, -20 * dt)
        if self.keyMap["cam-left"]:
            self.camera.setH(self.camera.getH() + 20 * dt)
        if self.keyMap["cam-right"]:
            self.camera.setH(self.camera.getH() - 20 * dt)

        print(self.camera.getH())

        #character control
        if self.keyMap["up"]:
            self.actor.setY(self.actor, -20 * dt)
        if self.keyMap["down"]:
            self.actor.setY(self.actor, +20 * dt)
        if self.keyMap["left"]:
            self.actor.setH(self.actor.getH() + 300 * dt)
        if self.keyMap["right"]:
            self.actor.setH(self.actor.getH() - 300 * dt)
        if self.keyMap["shoot"]:
            self.actorBullet += 1

        #make the animation of ralph running
        if self.keyMap["up"] or self.keyMap["down"] or self.keyMap["right"]:
            if self.isMoving == False:
                self.actor.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.actor.stop()
                self.actor.pose("walk", 5)
                self.isMoving = False

        #control the camera so that it is always a distance away from ralph
        camvec = self.actor.getPos() - self.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if camdist > 10.0:
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0
        if camdist < 5.0:
            self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist))
            camdist = 5.0

        self.Traverser.traverse(render)
        actorEntries = list(self.actorGroundHandler.getEntries())
        actorEntries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(actorEntries) > 0 and actorEntries[0].getIntoNode().getName(
        ) == "terrain":
            self.actor.setZ(actorEntries[0].getSurfacePoint(render).getZ())
        else:
            self.actor.setPos(startPos)

        self.camera.lookAt(self.floater)

        return task.cont
class RoamingRalphDemo(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)
        self.orbCollisionHandler = CollisionHandlerQueue()
        self.cTrav = CollisionTraverser()
        self.cTrav.setRespectPrevTransform(True)
        self.startgame = False
        self.sound=loader.loadSfx("models/0614.ogg")
        self.sound2=loader.loadSfx("models/01-main-theme.mp3")
        self.sound2.play()
        status=self.sound2.status()
        #hbPath = NodePath()
    
        utils.setUpKeys(self)
        utils.loadModels(self)
        utils.setUpLighting(self)
        #utils.setUpFloatingSpheres(self)
        utils.setUpRalphsShot(self)
        utils.setUpCamera(self)
        utils.setUpCollisionSpheres(self)
        self.healthTxt = utils.addInstructions(.06,"Health: 100")
        self.orbTxt = utils.addInstructions(.18,"Orbs: 0")
        self.hitsTxt = utils.addInstructions(.28,"Enemy Hits: 0")
        self.strHealthStatus = str(self.healthTxt)
        # Create a frame
        frame = DirectFrame(text = "main", scale = 0.001)
        # Add button
        self.flagstartbutton = 0        

        self.imageObject = OnscreenImage(image = 'models/instapage.jpg', pos = (0, 0, 0), scale=1.1)    
        self.imageObject2 = OnscreenImage(image = 'models/gap.jpg', pos = (-2.15, 0, 0), scale=1.1)
        self.imageObject3 = OnscreenImage(image = 'models/gap.jpg', pos = (2.15, 0, 0), scale=1.1)
        self.helpOn = DirectButton(text = ("Start", "on/off", "Start", "disabled"), scale=.10, pos=(-1.1,0,-.9), command=utils.buttonClickedOn, extraArgs=[self, self.imageObject,self.imageObject2,self.imageObject3, self.flagstartbutton])
        #helpOff = DirectButton(text = ("helpOff", "on/off", "helpOff", "disabled"), scale=.10, pos=(-0.5,0,-1), command=utils.buttonClickedOff, extraArgs=[self, self.imageObject, self.buttonflag])
      #  mytimer = DirectLabel()
      #  mytimer.reparentTo(render)
      #  mytimer.setY(7)        
        #Create 4 buttons       
        #print self.strHealthStatus
        #incBar(100)
    
        self.vec = LVector3(0,1,0)#vector for pawns shot

        # Create a frame
        #frame = DirectFrame(text = "main", scale = 0.001)
        # Add button
        #bar = DirectWaitBar(text = "", value = 50, pos = (0,.4,.4))
        #bar.reparent(render)

        # Game state variables
        self.isMoving = False
        self.jumping = False
        self.vz = 0
        self.numOrbs = 0
        self.healthCount = 100
        self.enemyhits = 0
    
        
        

        #self.shotList = []
        #self.sphere = CollisionBox((self.ralph.getX() + -10,self.ralph.getY(),self.ralph.getZ()),10,10,10)
        self.ralphBox1 = CollisionBox((0,2.5,3.5),1.5,0.5,1.5)
        cnodepath = self.ralph.attachNewNode((CollisionNode("ralphColNode")))
        cnodepath.node().addSolid(self.ralphBox1)
        cnodepath.node().addSolid(CollisionBox((0,-2.5,3.5),1.5,0.5,1.5))

        cnodepath.node().addSolid(CollisionBox((2.5,0,3.5),0.5,1.5,1.5))
        cnodepath.node().addSolid(CollisionBox((-2.5,0,3.5),0.5,1.5,1.5))

        #cnodepath.show()
        #self.cTrav.addCollider(cnodepath, self.orbCollisionHandler)

        self.sphere = CollisionSphere(0,-5,4,3)
        self.sphere3 = CollisionSphere(0,5,5,3)
        self.sphere4 = CollisionSphere(-4,0,5,2)
        self.sphere5 = CollisionSphere(4,0,5,2)
        self.sphere2 = CollisionSphere(0,0,3,2)
        self.cnodePath = self.ralph.attachNewNode((CollisionNode("ralphColNode")))
        self.cnodePath2 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck")))
        self.cnodePath3 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck2")))
        self.cnodePath4 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck3")))
        self.cnodePath5 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck4")))
        self.cnodePath.node().addSolid(self.sphere2)
        self.cnodePath2.node().addSolid(self.sphere)
        self.cnodePath3.node().addSolid(self.sphere3)
        self.cnodePath4.node().addSolid(self.sphere4)
        self.cnodePath5.node().addSolid(self.sphere5)
        #self.cnodePath.node().addSolid(self.sphere2)

        #self.cnodePath.show()#ralph pusher

        #self.cnodePath2.show()
        #self.cnodePath3.show()
        #self.cnodePath4.show()
        #self.cnodePath5.show()
        self.cTrav.addCollider(self.cnodePath2, self.orbCollisionHandler)
        self.cTrav.addCollider(self.cnodePath3, self.orbCollisionHandler)
        self.cTrav.addCollider(self.cnodePath4, self.orbCollisionHandler)
        self.cTrav.addCollider(self.cnodePath5, self.orbCollisionHandler)


        self.pusher = CollisionHandlerPusher()
        self.pusher.addCollider(self.cnodePath, self.ralph)

        #self.cTrav.addCollider(self.cnodePath, self.ralphCollisionHandler)
        self.cTrav.addCollider(self.cnodePath, self.pusher)


        self.chrisLastShotTime = globalClock.getFrameTime()
        self.chrisTimer = globalClock.getDt()

        #def __init__(self, pos,showbase, colPathName, dir, length):
        self.chrisList = [utils.cheken((-249,419,0),self,"chrisColPath0","X",5), #earthroom
                            utils.chris((-404,343,2),self,"chrisColPath1","X",5), #yellowroom
                            utils.fetus((-141,-69,1),self,"chrisColPath2","X",5), #lightblueroom

                            utils.cheken((-277,356,0),self,"chrisColPath3","Y",5), #between earth and y
                            utils.rose((-102,-5,1),self,"chrisColPath4","Y",5), #between r and lb

                            utils.cheken((-133,83,0),self,"chrisColPath5","Y",5), #blue hall
                            utils.fetus((-246,280,1),self,"chrisColPath6","X",5), #earth hall

                            utils.cheken((-330,241,0),self,"chrisColPath7","X",5), #yellow hall
                            utils.chris((-60,110,2),self,"chrisColPath8","Y",5), #red hall cheken z 0

                            utils.fetus((-75,52,1),self, "chrisColPath9", "X", 5),
                            utils.cheken((-75,141,0),self, "chrisColPath10", "X", 5),

                          utils.rose((-302,202,1),self,"chrisColPath11","X",5),
                          utils.chris((-303,304,2),self,"chrisColPath12","Y",5)

                              
                         ]
        #rose z = 1
        #cheken z = 0
        #chris z = 2
        #fetus z = 1

        #def _init_(self,showbase,pos,color,speed,radius):
        self.orbList = [utils.orb(self,( 18, 29,2.5),(1,0,0,1),20,2.5), #first red
                        utils.orb(self,( -249, 419,2.5),(1,1,1,1),20,2.5),#earthroom
                        utils.orb(self,( -404, 343,2.5),(1,1,0,1),20,2.5), #yellowroom
                        utils.orb(self,( -141, -69,2.5),(0,0,1,1),20,2.5),#light blue room

                        utils.orb(self,( -277, 356,2.5),(1,1,0,1),20,2.5), #between y and earth
                        utils.orb(self,( -102, -5,2.5),(0,0,1,1),20,2.5),   #between red and lb

                        utils.orb(self,( -135, 22,2.5),(0,0,1,1),20,2.5), #lb hall
                        utils.orb(self,( -248, 329,2.5),(1,1,1,1),20,2.5), #earthhall

                        utils.orb(self,( -330, 241,2.5),(1,1,0,1),20,2.5), #yellow hall
                        utils.orb(self,( -60, 110,2.5),(1,0,0,1),20,2.5) #red hall
                         ]
        self.donutList = [utils.donut(self, (0,0,1),20, 2.5),
                          utils.donut(self,( -330, 250,2.5),20,2.5), #yellow hall
                          utils.donut(self,( -141, -80,2.5),20,2.5),#light blue room
                          utils.donut(self,( -249, 430,2.5),20,2.5),#earthroom
                          utils.donut(self,( -102, -10,2.5),20,2.5),   #between red and lb

                          ]

        self.cameraCollided = False
        self.ralphSpeed = 60
        self.ralphHit = False
        self.ralphRedTime = 0

        self.textTime = -1
        self.textTime2 = -1
        self.textTime3 = -1
        self.mTextPath = utils.addInstructions2(.44,"")
        self.mTextPath2 = utils.addInstructions2(.55,"")
        self.winText2 = utils.addInstructions2(.55, "")
        self.timerText = utils.addInstructions4(.26,"0:00")
        self.introText = utils.addInstructions2(.55,"")

        self.minutes = 4
        self.seconds = 0
        self.timerTime = globalClock.getFrameTime()

        taskMgr.add(self.move, "moveTask")
        taskMgr.add(self.moveChris,"moveChrisTask")
        taskMgr.add(self.timerTask,"timerTask")
        #taskMgr.add(self.timerTask, "timerTask")
        

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value
    def clickResponse():
        pass
        #startgame=1;
        
        
    def timerTask(self,task):
        if self.startgame == False:
            return task.cont
        dt = globalClock.getFrameTime()
        if dt - self.timerTime > 1:
            self.seconds -= 1
            if self.seconds == -1:
                self.seconds = 59
                self.minutes -=1
            self.timerText.destroy()

            if self.seconds < 10:
                str1 = "0" + str(self.minutes) + ":0" + str(self.seconds)
            else:
                str1 = "0" + str(self.minutes) + ":" + str(self.seconds)
            self.timerText = utils.addInstructions4(.26,str1)
            self.timerTime = globalClock.getFrameTime() - ((dt - self.timerTime) - 1)
        if self.minutes == 0 and self.seconds == 0:
            self.startgame = False
            #utils.addInstructions3(.45,"You Lose")
            self.imageObject2 = OnscreenImage(image = 'models/gameover.jpg', pos = (0, 0, 0), scale=1.1)
            self.imageObject2 = OnscreenImage(image = 'models/gap.jpg', pos = (-2.15, 0, 0), scale=1.1)
            self.imageObject3 = OnscreenImage(image = 'models/gap.jpg', pos = (2.15, 0, 0), scale=1.1)
        return task.cont

    def moveChris(self,task):
        if self.startgame == False:
            return task.cont
        else:
            dt = globalClock.getDt()
            self.gianteye.setH(self.gianteye.getH() + 100 * dt)
            for chris in self.chrisList:
                chris.moveChris(dt,self,self.chrisList)
            return task.cont
    

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):

        if self.sound2.status() != self.sound2.PLAYING:
            self.sound2.play()

        if self.startgame == False:
            return task.cont
        else:
        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
            dt = globalClock.getDt()
            dt2 = globalClock.getFrameTime()
            #utils.moveChris(self,dt)
            #self.chris2.moveChris(dt,self)
            #self.startEnemyThread()

            if dt2 - self.textTime > 2 and self.textTime != -1:
                self.textTime = -1;
                self.mTextPath.destroy()

            if dt2 - self.textTime2 > 2 and self.textTime2 != -1:
                self.textTime2 = -1;
                self.mTextPath2.destroy()

            if dt2 - self.textTime3 > 5 and self.textTime3 != -1:
                self.textTime3 = -1;
                self.introText.destroy()



            if globalClock.getFrameTime()- self.ralphRedTime > .3 and self.ralphHit == True:
                    self.ralph.clearColor()
                    self.ralphHit = False

            # If the camera-left key is pressed, move camera left.
            # If the camera-right key is pressed, move camera right.

            if self.keyMap["cam-left"]:
                self.camera.setZ(self.camera, -20 * dt)
            if self.keyMap["cam-right"]:
                self.camera.setZ(self.camera, +20 * dt)

            # save ralph's initial position so that we can restore it,
            # in case he falls off the map or runs into something.

            startpos = self.ralph.getPos()

            # If a move-key is pressed, move ralph in the specified direction.

            if self.keyMap["left"]:
                self.ralph.setH(self.ralph.getH() + 75 * dt)
                #self.camera.setX(self.camera, +15.5 * dt)
            if self.keyMap["right"]:
                self.ralph.setH(self.ralph.getH() - 75 * dt)
                #self.camera.setX(self.camera, -15.5 * dt)
            if self.keyMap["forward"]:#-1
                self.ralph.setFluidY(self.ralph, -1*self.ralphSpeed * dt)
                #self.camera.setY(self.camera, -35 * dt)
            if self.keyMap["back"]:
                self.ralph.setFluidY(self.ralph, self.ralphSpeed * dt)
                #self.camera.setY(self.camera, 35 * dt)
            if self.keyMap["space"]:
                if self.jumping is False:
                #self.ralph.setZ(self.ralph.getZ() + 100 * dt)
                    self.jumping = True
                    self.vz = 8

            if self.keyMap["enter"]:
                self.keyMap["enter"] = False
                self.sound.play()
                self.shotList[self.shotCount].lpivot.setPos(self.ralph.getPos())
                self.shotList[self.shotCount].lpivot.setZ(self.ralph.getZ() + .5)
                self.shotList[self.shotCount].lpivot.setX(self.ralph.getX() - .25)
                print self.ralph.getPos()
                

                #self.shotList.append(rShot)
                #self.lightpivot3.setPos(self.ralph.getPos())
                #self.lightpivot3.setZ(self.ralph.getZ() + .5)
                #self.lightpivot3.setX(self.ralph.getX() - .25)
                #self.myShot.setHpr(self.ralph.getHpr())
                #parent to ralph
                #node = NodePath("tmp")
                #node.setHpr(self.ralph.getHpr())
                #vec = render.getRelativeVector(node,(0,-1,0))
                #self.myShotVec = vec

                node = NodePath("tmp")
                node.setHpr(self.ralph.getHpr())
                vec = render.getRelativeVector(node,(0,-1,0))
                self.shotList[self.shotCount].vec = vec
                self.shotCount = (self.shotCount + 1) % 10
            else:
                self.sound.stop()

            for rs in self.shotList:
                rs.lpivot.setPos(rs.lpivot.getPos() + rs.vec * dt * 25 )
                #if shot is too far stop updating


            
            if self.jumping is True:
                self.vz = self.vz - 16* dt
                self.ralph.setZ(self.ralph.getZ() + self.vz * dt )
                if self.ralph.getZ() < 0:
                    self.ralph.setZ(0)
                    self.jumping = False
            else:
                if self.ralph.getZ() < 0.25:
                    self.ralph.setZ(0.25)
                elif self.ralph.getZ() > 0.25:
                    self.ralph.setZ(self.ralph.getZ() -7 * dt)

            # If ralph is moving, loop the run animation.
            # If he is standing still, stop the animation.
            if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"] or self.keyMap["space"] or self.keyMap["forward"] or self.keyMap["back"]:
                if self.isMoving is False:
                    self.ralph.loop("run")
                    self.isMoving = True

            else:
                if self.isMoving:
                    self.ralph.stop()
                    self.ralph.pose("walk", 5)
                    self.isMoving = False

            # update pawns shot or set up new shot after it reaches a certain distance
            node = NodePath("tmp")
            node.setHpr(self.pawn.getHpr())
            vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))
            self.shot.setPos(self.shot.getPos() + self.vec * dt * 10 )
            if self.shot.getY() < -15 or self.shot.getY() > 30 or self.shot.getX() < 5 or self.shot.getX() > 15:
                self.shot.setPos(self.pawn.getPos() + (0,0,0))
                self.vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))
                self.vec = render.getRelativeVector(node,(random.random() * random.randrange(-1,2),random.random() + 1,0))

            # If the camera is too far from ralph, move it closer.
            # If the camera is too close to ralph, move it farther.
            #self.camera.lookAt(self.floater)
            camvec = self.ralph.getPos() - self.camera.getPos()
            #camvec = Vec3(0,camvec.getY(),0)
            camdist = camvec.length()
            x = self.camera.getZ()
            camvec.normalize()
            #if camdist > 6.0:
            #    self.camera.setPos(self.camera.getPos() + camvec * (camdist - 6))
            #if camdist < 6.0:
            #    self.camera.setPos(self.camera.getPos() - camvec * (6 - camdist))

            # Normally, we would have to call traverse() to check for collisions.
            # However, the class ShowBase that we inherit from has a task to do
            # this for us, if we assign a CollisionTraverser to self.cTrav.
            #self.cTrav.traverse(render)

            # Adjust camera so it stays at same height
            if self.cameraCollided == False:
                if self.camera.getZ() < self.ralph.getZ() + 1 or self.camera.getZ() > self.ralph.getZ() + 1:
                    self.camera.setZ(self.ralph.getZ() + 1)

            # The camera should look in ralph's direction,
            # but it should also try to stay horizontal, so look at
            # a floater which hovers above ralph's head.
            self.camera.lookAt(self.floater)


            entries = list(self.orbCollisionHandler.getEntries())
            if(len(entries) > 0):
                #self.lightpivot.reparentTo(NodePath())
                orbCollected = False
                self.cameraCollided = False
                self.ralphSpeed = 85
                ralphHit = False
                for entry in self.orbCollisionHandler.getEntries():
                    #print(entry)
                    fromColNp = entry.getFromNodePath()
                    toColNp = entry.getIntoNodePath()
                    if fromColNp.getName() == "orbColPath" and toColNp.getName() == "ralphColNode":
                        if orbCollected == False:
                            fromColNp.getParent().reparentTo(NodePath())
                            self.orbTxt.destroy()
                            self.numOrbs += 1
                            str1 = "Orbs: " + str(self.numOrbs)
                            self.orbTxt = utils.addInstructions(.18, str1)
                            orbCollected = True
                    elif toColNp.getName() == "orbColPath" and fromColNp.getName() == "ralphColNode":
                        if orbCollected == False:
                            toColNp.getParent().reparentTo(NodePath())
                            self.orbTxt.destroy()
                            self.numOrbs += 1
                            str1 = "Orbs: " + str(self.numOrbs)
                            self.orbTxt = utils.addInstructions(.18, str1)
                            orbCollected = True

                    elif fromColNp.getName() == "donutCollisionNode" and toColNp.getName() == "ralphColNode":
                        fromColNp.getParent().reparentTo(NodePath())
                        self.healthCount += 15
                        if(self.healthCount > 100):
                            self.healthCount = 100
                        self.healthTxt.destroy()
                        str1 = "Health: " + str(self.healthCount)
                        self.healthTxt = utils.addInstructions(.06, str1)
                    elif toColNp.getName() == "donutCollisionNode" and fromColNp.getName() == "ralphColNode":
                        toColNp.getParent().reparentTo(NodePath())
                        self.healthCount += 15
                        if(self.healthCount > 100):
                            self.healthCount = 100
                        self.healthTxt.destroy()
                        str1 = "Health: " + str(self.healthCount)
                        self.healthTxt = utils.addInstructions(.06, str1)
                    elif toColNp.getName() == "ralphOrbColPath" and (fromColNp.getName()[:-1] == "chrisColPath" or fromColNp.getName()[:-2] == "chrisColPath"):
                        toColNp.getParent().setZ(20)
                        for chriss in self.chrisList:
                            if chriss.chrisColName == fromColNp.getName():
                                chris = chriss
                                break

                        chris.chrisHealth = chris.chrisHealth - 1
                        chris.chris.setColor(1,0,0,1)
                        chris.chrisHit = True
                        chris.chrisRedTime = globalClock.getFrameTime()
                        #print chris.chrisRedTime
                        if chris.chrisHealth < 0 and chris.chrisAlive == True:
                            fromColNp.getParent().removeNode()
                            chris.chrisAlive = False
                            self.hitsTxt.destroy()
                            self.enemyhits += 1
                            str1 = "Enemy Hits: " + str(self.enemyhits)
                            self.hitsTxt = utils.addInstructions(.28, str1)
                            chris.chrisShot.setZ(26)
                    elif (toColNp.getName()[:-1] == "chrisColPath" or toColNp.getName()[:-2] == "chrisColPath") and fromColNp.getName() == "ralphOrbColPath":
                        fromColNp.getParent().setZ(20)
                        for chriss in self.chrisList:
                            if chriss.chrisColName == toColNp.getName():
                                chris = chriss
                                break

                        chris.chrisHealth = chris.chrisHealth - 1
                        chris.chris.setColor(1,0,0,1)
                        chris.chrisHit = True
                        chris.chrisRedTime = globalClock.getFrameTime()
                        #print chris.chrisRedTime
                        if chris.chrisHealth < 0 and chris.chrisAlive == True:
                            toColNp.getParent().removeNode()
                            chris.chrisAlive = False
                            self.hitsTxt.destroy()
                            self.enemyhits += 1
                            str1 = "Enemy Hits: " + str(self.enemyhits)
                            self.hitsTxt = utils.addInstructions(.28, str1)
                            chris.chrisShot.setZ(26)
                    elif toColNp.getName() == "enemyOrbColPath" and fromColNp.getName() == "ralphColNode":
                        if ralphHit == False:
                            toColNp.getParent().setZ(26)
                            self.healthTxt.destroy()
                            self.healthCount -= 5
                            str1 = "Health: " + str(self.healthCount)
                            self.healthTxt = utils.addInstructions(.06, str1)
                            self.ralphHit = True
                            self.ralph.setColor((1,0,0,1))
                            self.ralphRedTime = globalClock.getFrameTime()

                        if self.healthCount <= 0:
                            self.startgame = False
                            #utils.addInstructions3(.45,"You Lose")
                            self.imageObject2 = OnscreenImage(image = 'models/gameover.jpg', pos = (0, 0, 0), scale=1.1)
                            self.imageObject2 = OnscreenImage(image = 'models/gap.jpg', pos = (-2.15, 0, 0), scale=1.1)
                            self.imageObject3 = OnscreenImage(image = 'models/gap.jpg', pos = (2.15, 0, 0), scale=1.1)
                    elif toColNp.getName() == "ralphColNode" and fromColNp.getName() == "enemyOrbColPath":
                        fromColNp.getParent().setZ(26)
                        if ralphHit == False:
                            self.healthTxt.destroy()
                            self.healthCount -= 5
                            str1 = "Health: " + str(self.healthCount)
                            self.healthTxt = utils.addInstructions(.06, str1)
                            self.ralphHit = True
                            self.ralph.setColor((1,0,0,1))
                            self.ralphRedTime = globalClock.getFrameTime()
                            ralphHit = True

                        if self.healthCount <= 0:
                            self.startgame = False
                            #utils.addInstructions3(.45,"You Lose")
                            self.imageObject2 = OnscreenImage(image = 'models/gameover.jpg', pos = (0, 0, 0), scale=1.1)
                            self.imageObject2 = OnscreenImage(image = 'models/gap.jpg', pos = (-2.15, 0, 0), scale=1.1)
                            self.imageObject3 = OnscreenImage(image = 'models/gap.jpg', pos = (2.15, 0, 0), scale=1.1)
                    elif toColNp.getName() == "ralphColNode" and fromColNp.getName() == "portalColPath":
                        if self.numOrbs < 3 and self.enemyhits < 4:
                            self.mTextPath.destroy()
                            self.mTextPath = utils.addInstructions2(.30, "Not enough orbs.")
                            self.textTime = globalClock.getFrameTime()
                            self.mTextPath2.destroy()
                            self.mTextPath2 = utils.addInstructions2(.45, "Not enough kills.")
                            self.textTime2 = globalClock.getFrameTime()
                        elif self.numOrbs < 3:
                            self.mTextPath.destroy()
                            self.mTextPath = utils.addInstructions2(.30, "Not enough orbs.")
                            self.textTime = globalClock.getFrameTime()
                        elif self.enemyhits < 4:
                            self.mTextPath2.destroy()
                            self.mTextPath2 = utils.addInstructions2(.45, "Not enough kills.")
                            self.textTime2 = globalClock.getFrameTime()
                        else:
                            self.winText = utils.addInstructions3(.45, "You Win")
                            self.startgame = False
                            #self.ralph.setPos(-196, 177, 3)
                            if self.isMoving == True:
                                self.ralph.stop()
                                self.ralph.pose("walk", 5)
                                self.isMoving = False



                    elif fromColNp.getName() == "ralphOrbColPath" and toColNp.getName() == "allinclusive":
                        fromColNp.getParent().setZ(50)
                    elif toColNp.getName() == "ralphOrbColPath" and fromColNp.getName() == "allinclusive":
                        toColNp.getParent().setZ(50)
                    elif fromColNp.getName() == "enemyOrbWallCheck" and toColNp.getName() == "allinclusive":
                        fromColNp.getParent().setZ(50)
                        #print toColNp.getName()
                    elif toColNp.getName() == "enemyOrbWallCheck" and fromColNp.getName() == "allinclusive":
                        toColNp.getParent().setZ(50)
                        #print fromColNp.getName()

                    elif fromColNp.getName() == "ralphWallCheck" and toColNp.getName() == "allinclusive":
                        #node = NodePath("tmp")
                        #node.setHpr(self.ralph.getHpr())
                        #vec = render.getRelativeVector(node,(0,-1,0))
                        #self.ralph.setPos(self.ralph.getPos()-vec)
                        #fromColNp.getParent().setZ(26)
                        self.ralphSpeed = 60
                    elif toColNp.getName() == "ralphWallCheck" and fromColNp.getName() == "allinclusive":
                        #node = NodePath("tmp")
                        #node.setHpr(self.ralph.getHpr())
                        #vec = render.getRelativeVector(node,(0,-1,0))
                        #self.ralph.setPos(self.ralph.getPos()-vec)
                        #print "wtf"
                        #toColNp.getParent().setZ(26)
                        self.ralphSpeed = 60
                    elif fromColNp.getName() == "ralphWallCheck2" and toColNp.getName() == "allinclusive":
                        #node = NodePath("tmp")
                        #node.setHpr(self.ralph.getHpr())
                        #vec = render.getRelativeVector(node,(0,1,0))
                        #self.ralph.setPos(self.ralph.getPos()-vec)
                        #fromColNp.getParent().setZ(26)
                        self.ralphSpeed = 60
                    elif toColNp.getName() == "ralphWallCheck2" and fromColNp.getName() == "allinclusive":
                        #node = NodePath("tmp")
                        #node.setHpr(self.ralph.getHpr())
                        #vec = render.getRelativeVector(node,(0,1,0))
                        #self.ralph.setPos(self.ralph.getPos()-vec)
                        #self.camera.setPos(self.ralph.getPos())
                        #self.cameraCollided = True
                        self.ralphSpeed = 60
                    elif fromColNp.getName() == "ralphWallCheck3" and toColNp.getName() == "allinclusive":
                        #node = NodePath("tmp")
                        #node.setHpr(self.ralph.getHpr())
                        #vec = render.getRelativeVector(node,(-1,0,0))
                        #self.ralph.setPos(self.ralph.getPos()-vec)
                        #fromColNp.getParent().setZ(26)
                        self.ralphSpeed = 60
                        
                    elif toColNp.getName() == "ralphWallCheck3" and fromColNp.getName() == "allinclusive":
                        #node = NodePath("tmp")
                        #node.setHpr(self.ralph.getHpr())
                        #vec = render.getRelativeVector(node,(-1,0,0))
                        #self.ralph.setPos(self.ralph.getPos()-vec)
                        #self.camera.setPos(self.ralph.getPos())
                        #self.cameraCollided = True
                        self.ralphSpeed = 60
                        
                    elif fromColNp.getName() == "ralphWallCheck4" and toColNp.getName() == "allinclusive":
                        #node = NodePath("tmp")
                        #node.setHpr(self.ralph.getHpr())
                        #vec = render.getRelativeVector(node,(1,0,0))
                        #self.ralph.setPos(self.ralph.getPos()-vec)
                        #fromColNp.getParent().setZ(26)
                        self.ralphSpeed = 60
                        
                    elif toColNp.getName() == "ralphWallCheck4" and fromColNp.getName() == "allinclusive":
                        #node = NodePath("tmp")
                        #node.setHpr(self.ralph.getHpr())
                        #vec = render.getRelativeVector(node,(1,0,0))
                        #self.ralph.setPos(self.ralph.getPos()-vec)
                        #self.camera.setPos(self.ralph.getPos())
                        #self.cameraCollided = True
                        self.ralphSpeed = 60
                        

            utils.updateHealthBar(self.healthCount, self.bar)
            #utils.turnofstartbutton(self.flagstartbutton)
            #if self.flagstartbutton ==1:
            #    self.helpOn.destory()
            return task.cont
Example #13
0
class Tunnel(ShowBase):
  def __init__(self):
    ShowBase.__init__(self)

    base.disableMouse()
    self.camera.setPosHpr(0, 0, 10, 0, -90, 0)
    self.setBackgroundColor(0, 0, 0)
    
    self.fog = Fog('distanceFog')
    self.fog.setColor(0, 0, 0)
    self.fog.setExpDensity(.08)
    render.setFog(self.fog)

    self.keyMap = {'left' : 0, 'right' : 0, 'up' : 0, 'down' : 0}
    #
    self.accept('escape', sys.exit)
    self.accept('arrow_left', self.setKey, ['left', True])
    self.accept('arrow_right', self.setKey, ['right', True])
    self.accept('arrow_up', self.setKey, ['up', True])
    self.accept('arrow_down', self.setKey, ['down', True])
    self.accept('arrow_left-up', self.setKey, ['left', False])
    self.accept('arrow_right-up', self.setKey, ['right', False])
    self.accept('arrow_up-up', self.setKey, ['up', False])
    self.accept('arrow_down-up', self.setKey, ['down', False])

    self.queue = CollisionHandlerQueue()
    self.trav = CollisionTraverser('traverser')
    base.cTrav = self.trav
    #
    self.makeTunnel()
    self.makeSphere()
    self.continueTunnel()
    #
    self.crystals = []
    for _ in xrange(CRYSTALS_CNT):
      self.makeRandomCrystal(randint(1, TUNNEL_CNT - 1))
    self.collisionCnt = 0
    #
    taskMgr.add(self.moveSphere, 'moveSphere')
    taskMgr.add(self.handleCollisions, 'handleCollisions')
    #
    if DEBUG:
      self.trav.showCollisions(render)
      render.find('**/sphere_collision').show()

  def makeTunnel(self):
    self.tunnel = [None] * TUNNEL_CNT
    for x in range(TUNNEL_CNT):
      self.tunnel[x] = loader.loadModel('models/tunnel')
      if x == 0:
        self.tunnel[x].reparentTo(render)
      else:
        self.tunnel[x].reparentTo(self.tunnel[x - 1])
      self.tunnel[x].setPos(0, 0, -TUNNEL_SEGMENT_LENGTH)

  def makeSphere(self):
    self.sphere = loader.loadModel('models/alice-shapes--sphere-highpoly/sphere-highpoly.egg')
    self.sphere.reparentTo(render)
    self.sphere.setScale(0.07)
    self.sphere.setZ(2)
    #
    col_node = self.sphere.attachNewNode(CollisionNode('sphere_collision'))
    col_sphere = CollisionSphere(0, 0, 2, SPHERE_RADIUS)
    col_node.node().addSolid(col_sphere)
    self.trav.addCollider(col_node, self.queue)

  def makeRandomCrystal(self, tun):
    crystal = loader.loadModel('models/bvw-f2004--purplecrystal/purplecrystal.egg')
    crystal.reparentTo(self.tunnel[tun])
    #
    pMin, pMax = LPoint3f(), LPoint3f()
    crystal.calcTightBounds(pMin, pMax)
    col_node = crystal.attachNewNode(CollisionNode('crystal_collision'))
    col_box = CollisionBox(pMin, pMax)
    col_node.node().addSolid(col_box)
    crystal.setScale(0.1)
    if DEBUG:
      col_node.show()

    pos = ['rx', '-rx', 'ry', 'down', 'up']
    rnd = choice(pos)
    Z = randint(0, 10)
    if rnd == 'rx':
      R = randint(45, 90)
      X = uniform(-2, 6)
      crystal.setR(R)
      crystal.setX(X)
    elif rnd == '-rx':
      R = randint(45, 90)
      X = uniform(-2, 8)
      crystal.setR(-R)
      crystal.setX(-X)
    elif rnd == 'ry':
      R = randint(45, 120)
      Y = uniform(2, 6)
      crystal.setR(R)
      crystal.setY(Y)
    elif rnd == '-py':
      R = randint(45, 120)
      Y = uniform(3, 8)
      crystal.setR(-R)
      crystal.setY(-Y)
    elif rnd == 'down':
      Y = uniform(1, 6)
      P = randint(70, 120)
      crystal.setY(-Y)
      crystal.setP(P)
    elif rnd == 'up':
      Y = uniform(-1, 6)
      P = randint(-130, -60)
      crystal.setY(Y)
      crystal.setP(P)
      
    crystal.setZ(Z)
    self.crystals.append(crystal)
    
  def continueTunnel(self):
    self.tunnel = self.tunnel[1:] + self.tunnel[0:1]
    self.tunnel[0].setZ(0)
    self.tunnel[0].reparentTo(render)
    self.tunnel[0].setScale(.155, .155, .305)
    self.tunnel[3].reparentTo(self.tunnel[2])
    self.tunnel[3].setZ(-TUNNEL_SEGMENT_LENGTH)
    self.tunnel[3].setScale(1)

    for child in self.tunnel[3].getChildren():
      if child.getName() == 'purplecrystal.egg':
        self.crystals.remove(child)
        child.removeNode()
        self.makeRandomCrystal(3)

    self.tunnelMove = Sequence \
    (
      LerpFunc \
      (
        self.tunnel[0].setZ,
        duration=TUNNEL_TIME,
        fromData=0,
        toData=TUNNEL_SEGMENT_LENGTH * .305
      ),
      Func(self.continueTunnel)
    )
    self.tunnelMove.start()

  def setKey(self, key, value):
    self.keyMap[key] = value

  def moveSphere(self, task):
    dt = globalClock.getDt()
    addVec = LVector3f(0, 0, 0)
    if self.keyMap['left']:
      addVec[0] -= SPHERE_SPEED * dt
    elif self.keyMap['right']:
      addVec[0] += SPHERE_SPEED * dt
    elif self.keyMap['up']:
      addVec[1] += SPHERE_SPEED * dt
    elif self.keyMap['down']:
      addVec[1] -= SPHERE_SPEED * dt
   
    if ((self.sphere.getPos() + addVec) - LPoint3f(TUNNEL_CENTER)).length() < TUNNEL_RADIUS:
      self.sphere.setPos(self.sphere.getPos() + addVec)

    return task.cont

  def handleCollisions(self, task):
    for entry in self.queue.getEntries():
      node = entry.getFromNodePath()
      if node.getName() == 'sphere_collision':
        self.collisionCnt += 1
        print 'Oops! Collision counter: %d' % self.collisionCnt
    return task.cont
Example #14
0
class IStage(metaclass=abc.ABCMeta):
    def __init__(self):
        self.charHeading = {"up": 180, "down": 0, "left": 90, "right": 90}
        self.pusher = base.pusher
        self.heroGroundHandler = CollisionHandlerQueue()
        self.dialogBox = GUIDialog()
        self.stage = None
        self.hero = None
        self.enemyActors = []
        self.npcActors = []
        self.bossActors = []

    def initStage(self):
        if self.stage:
            self.stage.removeNode()
        this_map = base.mapData.maps[base.gameData.currentMap]
        self.stage = loader.loadModel(this_map['model'])
        if "pattern" in this_map:
            self.stage_grid = StageGrid(
                this_map['pattern'], self.stage, this_map['blockTypes'])
            self.startPos = self.stage_grid.startPosList[base.gameData.heroPos]
        else:
            self.startPos = self.stage.find(
                "**/" + base.gameData.heroPos).getPos()
        self.stage.reparentTo(render)
        self.stage.hide()

    def setup(self):
        self.initStage()
        self.initHero()
        self.initEnemy()
        self.initBoss()
        self.initNPC()

    def initHero(self):
        self.hero = loader.loadModel("charaRoot")
        self.hero.reparentTo(self.stage)
        model = base.gameData.heroModel
        self.heroArmature = Actor(
            "{}".format(model), {
                "idle": "{}-idle".format(model),
                "walk": "{}-run".format(model)
            })
        self.heroArmature.reparentTo(self.hero)
        self.hero.setPos(self.startPos)
        cNode = CollisionNode('hero')
        cNode.addSolid(CollisionSphere(0, 0, 1.5, 1))
        heroCollision = self.hero.attachNewNode(cNode)
        #########################################################
        # heroCollision.show()

        self.pusher.addCollider(
            heroCollision, self.hero, base.drive.node())
        base.cTrav.addCollider(heroCollision, self.pusher)

        heroGroundRay = CollisionRay()
        heroGroundRay.setOrigin(0, 0, 9)
        heroGroundRay.setDirection(0, 0, -1)
        heroGroundCol = CollisionNode('heroRay')
        heroGroundCol.addSolid(heroGroundRay)
        heroGroundCol.setFromCollideMask(CollideMask.bit(0))
        heroGroundCol.setIntoCollideMask(CollideMask.allOff())
        heroGroundColNp = self.hero.attachNewNode(heroGroundCol)
        #########################################################
        # heroGroundColNp.show()

        base.cTrav.addCollider(heroGroundColNp, self.heroGroundHandler)
        self.controlCamera()

    def fixActorsHPR(self):
        for e in self.enemyActors:
            if not e:
                continue
            h, p, r = e.actor.getHpr()
            e.actor.setHpr(h, 0, 0)

    def AIUpdate(self, task):
        base.AIworld.update()
        self.fixActorsHPR()
        return task.cont

    def initEnemy(self):
        this_map = base.mapData.maps[base.gameData.currentMap]
        if not "enemyList" in this_map:
            return
        enemyNumber = len(this_map["enemyList"])
        if enemyNumber <= 0:
            return
        self.enemyActors = []
        die = BetterThanDice(2)
        for enemyIndex in list(range(0, enemyNumber)):
            enemyModel = this_map["enemyList"][enemyIndex]['model']
            fa = FieldActor('enemy', enemyIndex, enemyModel,
                            self.stage, self.enemyActors, self.hero)
            if die.getValue() == 0:
                fa.request('Pursue')
            else:
                fa.request('Wander')

    def initBoss(self):
        this_map = base.mapData.maps[base.gameData.currentMap]
        if not "bossList" in this_map:
            return
        bossNumber = len(this_map["bossList"])
        if bossNumber <= 0:
            return
        self.bossActors = []
        for bossIndex in list(range(0, bossNumber)):
            if not base.gameData.flags[this_map["bossList"][bossIndex]['flag']]:
                continue
            bossModel = this_map["bossList"][bossIndex]['model']
            fa = FieldActor('boss', bossIndex, bossModel,
                            self.stage, self.bossActors, self.hero)

    def initNPC(self):
        this_map = base.mapData.maps[base.gameData.currentMap]
        if not "npcList" in this_map:
            return
        npcNumber = len(this_map["npcList"])
        if npcNumber == 0:
            return
        self.npcActors = []
        for npcIndex in list(range(0, npcNumber)):
            npcModel = this_map["npcList"][npcIndex]['model']
            fa = FieldActor('npc', npcIndex, npcModel,
                            self.stage, self.npcActors, self.hero)
            fa.request('Idle')

    def controlCamera(self):
        base.camera.setPos(self.hero.getX(), self.hero.getY() - 50, 55)
        base.camera.lookAt(self.heroArmature)

        base.sunNp.setPos(self.hero.getX()-4, self.hero.getY()-4, 50)
        base.sunNp.lookAt(self.hero)

    def moveHero(self, task):
        animName = self.heroArmature.getCurrentAnim()

        if self.dialogBox.isShowing:
            if animName != "idle":
                self.heroArmature.loop("idle")
            self.controlDialogBox()
            return task.cont

        keysPressed = sum(base.directionMap.values())

        if keysPressed == 0:
            if animName != "idle":
                self.heroArmature.loop("idle")

            if base.commandMap["confirm"]:
                pass
            elif base.commandMap["cancel"]:
                self.cancelCommand()

            base.resetButtons()
            return task.cont

        self.heroHandleFloor()
        self.heroCalculateDisplacement()
        self.heroHeading(keysPressed)
        self.controlCamera()

        if animName != "walk":
            self.heroArmature.loop("walk")

        return task.cont

    def heroCalculateDisplacement(self):

        dt = globalClock.getDt()

        xSpeed = 0.0
        ySpeed = 0.0
        speed = 25
        if base.directionMap["left"]:
            xSpeed -= speed
        elif base.directionMap["right"]:
            xSpeed += speed

        if base.directionMap["up"]:
            ySpeed += speed
        elif base.directionMap["down"]:
            ySpeed -= speed

        self.hero.setX(self.hero, xSpeed * dt)
        self.hero.setY(self.hero, ySpeed * dt)

    def heroHandleFloor(self):
        entries = list(self.heroGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName() == "floor":
            self.hero.setZ(entries[0].getSurfacePoint(render).getZ())

    def controlDialogBox(self):
        if self.dialogBox.isChoices:
            pass
        else:
            if base.commandMap["confirm"] or base.commandMap["cancel"]:
                self.dialogBox.next()
                base.resetButtons()

    def heroHeading(self, keysPressed=None):
        if not keysPressed:
            return
        heading, pitch, roll = self.heroArmature.getHpr()

        sumAngles = 0

        for key, value in base.directionMap.items():
            if value:
                sumAngles += self.charHeading[key]

        direction = -1 if base.directionMap["left"] else 1

        heading = (sumAngles * direction) / keysPressed

        self.heroArmature.setHpr(heading, pitch, roll)

    def setHeroCollision(self):
        inEvent = "{}-into-{}".format('hero', 'world')
        self.pusher.addInPattern(inEvent)
        base.accept(inEvent, self.intoEvent)

        # againEvent = "{}-again-{}".format(enemyColName, heroColName)
        # self.pusher.addAgainPattern(againEvent)
        # base.accept(againEvent, self.printAgain)

        # outEvent = "{}-out-{}".format(enemyColName, heroColName)
        # self.pusher.addOutPattern(outEvent)
        # base.accept(outEvent, self.printOut)

    def changeMap(self):
        base.callLoadingScreen()
        self.resetMap()

    def resetMap(self):
        self.setup()
        self.start()
        base.initController()

    def start(self):
        render.setLight(base.alnp)
        render.setLight(base.sunNp)

        self.controlCamera()

        self.stage.show()
        self.hero.show()
        for enemy in self.enemyActors:
            if enemy:
                enemy.request('Show')
        for boss in self.bossActors:
            if boss:
                boss.request('Show')
        for npc in self.npcActors:
            npc.request('Show')
        # change how to play different music later
        base.messenger.send("playMap")
        base.removeLoadingScreen()

    def stop(self):
        self.stage.hide()
        self.hero.hide()
        for enemy in self.enemyActors:
            if enemy:
                enemy.request('Hide')
        for boss in self.bossActors:
            if boss:
                boss.request('Hide')
        for npc in self.npcActors:
            npc.request('Hide')
        render.clearLight()

    def quit(self):
        self.stage.removeNode()
        self.dialogBox.removeNode()

    @abc.abstractmethod
    def cancelCommand(self):
        raise NotImplementedError('subclass must define this method')

    @abc.abstractmethod
    def intoEvent(self, entry):
        raise NotImplementedError('subclass must define this method')
Example #15
0
class Game(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)

        # Set the background color to black
        self.win.setClearColor(BACKGROUND_COLOR)

        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)

        # Create the main character

        playerStartPos = self.environ.find("**/start_point").getPos()
        self.player = Actor("models/player", {"run": "models/player-run", "walk": "models/player-walk"})
        self.player.reparentTo(render)
        self.player.setScale(0.2)
        self.player.setPos(playerStartPos + (0, 0, 0.5))

        # Create a floater object, which floats 2 units above player.  We
        # use this as a target for the camera to look at.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(self.player)
        self.floater.setZ(CAMERA_TARGET_HEIGHT_DELTA)

        self.first_person = False

        def key_dn(name):
            return lambda: self.setKey(name, True)

        def key_up(name):
            return lambda: self.setKey(name, False)

        def quit():
            self.destroy()

        def toggle_first():
            self.first_person = not self.first_person

        # Accept the control keys for movement and rotation
        key_map = [
            # key              command        action                   help
            # ---              -------        ------                   ----
            ("escape", "esc", lambda: quit(), "[ESC]: Quit"),
            ("arrow_left", "left", key_dn("left"), "[Left Arrow]: Rotate Left"),
            ("arrow_left-up", "left", key_up("left"), None),
            ("arrow_right", "right", key_dn("right"), "[Right Arrow]: Rotate Right"),
            ("arrow_right-up", "right", key_up("right"), None),
            ("arrow_up", "forward", key_dn("forward"), "[Up Arrow]: Run Forward"),
            ("arrow_up-up", "forward", key_up("forward"), None),
            ("arrow_down", "backward", key_dn("backward"), "[Down Arrow]: Run Backward"),
            ("arrow_down-up", "backward", key_up("backward"), None),
            ("a", "cam-left", key_dn("cam-left"), "[A]: Rotate Camera Left"),
            ("a-up", "cam-left", key_up("cam-left"), None),
            ("s", "cam-right", key_dn("cam-right"), "[S]: Rotate Camera Right"),
            ("s-up", "cam-right", key_up("cam-right"), None),
            ("f", "first-pers", lambda: toggle_first(), "[F]: Toggle first-person"),
        ]
        self.keyMap = {}
        inst = Instructions()
        for key, command, action, description in key_map:
            if command:
                self.setKey(command, False)
            self.accept(key, action)
            if description:
                inst.add(description)

        taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera
        self.disableMouse()
        self.camera.setPos(self.player.getX(), self.player.getY() + 10, 2)

        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above player's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.
        self.cTrav = CollisionTraverser()

        self.playerGroundRay = CollisionRay()
        self.playerGroundRay.setOrigin(0, 0, 9)
        self.playerGroundRay.setDirection(0, 0, -1)
        self.playerGroundCol = CollisionNode("playerRay")
        self.playerGroundCol.addSolid(self.playerGroundRay)
        self.playerGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.playerGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.playerGroundColNp = self.player.attachNewNode(self.playerGroundCol)
        self.playerGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 9)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode("camRay")
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.camGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.camGroundColNp = self.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # Uncomment this line to see the collision rays
        self.playerGroundColNp.show()
        self.camGroundColNp.show()

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        self.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((0.3, 0.3, 0.3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):

        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        if self.keyMap["cam-left"]:
            self.camera.setX(self.camera, -20 * dt)
        if self.keyMap["cam-right"]:
            self.camera.setX(self.camera, +20 * dt)

        # save player's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.player.getPos()

        # If a move-key is pressed, move player in the specified direction.

        if self.keyMap["left"]:
            self.player.setH(self.player.getH() + 300 * dt)
        if self.keyMap["right"]:
            self.player.setH(self.player.getH() - 300 * dt)
        if self.keyMap["forward"]:
            self.player.setY(self.player, -25 * dt)
        if self.keyMap["backward"]:
            self.player.setY(self.player, 25 * dt)

        # If player is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if self.keyMap["forward"] or self.keyMap["backward"] or self.keyMap["left"] or self.keyMap["right"]:
            if self.isMoving is False:
                self.player.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.player.stop()
                self.player.pose("walk", 5)
                self.isMoving = False

        # If the camera is too far from player, move it closer.
        # If the camera is too close to player, move it farther.

        if self.first_person:
            self.camera.setPos(self.player.getPos())
        else:
            camvec = self.player.getPos() - self.camera.getPos()
            camvec.setZ(0)
            camdist = camvec.length()
            camvec.normalize()
            if camdist > CAMERA_DISTANCE_MAX:
                self.camera.setPos(self.camera.getPos() + camvec * (camdist - int(CAMERA_DISTANCE_MAX)))
                camdist = CAMERA_DISTANCE_MAX
                if camdist < CAMERA_DISTANCE_MIN:
                    self.camera.setPos(self.camera.getPos() - camvec * (int(CAMERA_DISTANCE_MIN) - camdist))
                    camdist = CAMERA_DISTANCE_MIN

        # Normally, we would have to call traverse() to check for collisions.
        # However, the class ShowBase that we inherit from has a task to do
        # this for us, if we assign a CollisionTraverser to self.cTrav.
        self.cTrav.traverse(render)

        # Adjust player's Z coordinate.  If player's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = list(self.playerGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain":
            self.player.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.player.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above player, whichever is greater.

        entries = list(self.camGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain":
            self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + CAMERA_POSITION_HEIGHT_DELTA_MIN)
        if self.camera.getZ() < self.player.getZ() + CAMERA_POSITION_HEIGHT_DELTA_MAX:
            self.camera.setZ(self.player.getZ() + CAMERA_POSITION_HEIGHT_DELTA_MAX)

        # The camera should look in player's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above player's head.
        self.camera.lookAt(self.floater)

        return task.cont
Example #16
0
class mode_head():
    def __init__(self,base,Golog, folder_path = None, parent = None):
        # Set up basic attributes
        self.base = base
        self.golog = Golog
        self.bools = {'textboxes':True}
        self.buttons = dict()
        self.window_tasks = dict()
        self.bt = None
        self.mw = None
        self.listener = DirectObject()
        self.folder_path = folder_path #absolute path of golog folder '/path/to/golog/folder'
        if self.folder_path:
            self.file_path = os.path.abspath(self.folder_path + '/' + self.golog.label+ '.golog')
            autosave = True
        self.has_window = False
        self.parent = parent #for autosaving up to original golog
        self.reset = self.basic_reset
        self.garbage = [] #list of deleted math_data/graphics_data etc.


        #create a 2d rende
        self.render2d = NodePath('2d render')
        self.camera2D = self.render2d.attachNewNode(Camera('2d Camera'))
        self.camera2D.setDepthTest(False)
        self.camera2D.setDepthWrite(False)
        lens = OrthographicLens()
        lens.setFilmSize(2, 2)
        lens.setNearFar(-1000, 1000)
        self.camera2D.node().setLens(lens)


        # make a dictionary of mode_heads in the underlying golog
        if hasattr(self.golog,'mode_heads'):
            m = 0
            while m in self.golog.mode_heads.keys(): m+=1 #get smallest unused mode_head index
            self.index = m
            self.label = self.golog.label+"_mode_head_"+str(self.index)
            self.golog.mode_heads[self.index] = self

        else:
            self.golog.mode_heads = dict()
            self.index = 0
            self.label = self.golog.label+"_mode_head_"+ str(self.index)
            self.golog.mode_heads[self.index] = self
        ##########

        ### set up collision handling ###
        self.queue = CollisionHandlerQueue()

        ### set up selection tools
        self.create_list = [[],[]] #select nodes and add to create_list in order to create higher simplecies
        self.bools = {'selecter':False,'textboxes':True,'shift_clicked':False} #some bools that will be usefull
        self.dict = {'shift_pt':[None,None]}


        # set up mouse picker
        self.pickerNode = CollisionNode('mouseRay')
        self.pickerNP = self.golog.camera.attachNewNode(self.pickerNode) #attach collision node to camera
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        self.pickerNode.set_into_collide_mask(0) #so that collision rays don't collide into each other if there are two mode_heads
        self.golog.cTrav.addCollider(self.pickerNP,self.queue) #send collisions to self.queue
        # set up plane for picking
        self.planeNode = self.golog.render.attachNewNode("plane")
        self.planeNode.setTag("mode_head",self.label) # tag to say it belongs to this mode_head
        self.planeNode.setTag("mode_node", 'plane')
        self.planeFromObject = self.planeNode.attachNewNode(CollisionNode("planeColNode"))
        self.planeFromObject.node().addSolid(CollisionPlane(Plane(Vec3(0,-1,0),Point3(0,0,0))))
        self.plane = self.planeFromObject.node().getSolid(0)
        ###
        # set up preview text
        self.textNP = self.render2d.attachNewNode(TextNode('text node'))
        self.textNP.setScale(.2)
        self.textNP.setPos(-1,0,0)
        self.textNP.show()
        #set up dragging info
        self.grabbed_dict = dict()
        self.drag_dict = dict() #a mapping from selected nodes to their original positions for dragging
        self.mouse_down_loc = (0,0,0)
        self.lowest_level = 3

    def open_math_data(self,math_data):
        if math_data.type == 'golog':
            golog_dict = math_data() #calls the mathdata (which is a golog_dict)
            subgolog = golog_dict['golog']
            subfolder_path = golog_dict['folder_path']

            #### just to be safe, but probably not needed
            subgolog_folder_path = os.path.join(self.folder_path,'subgologs')
            if not os.path.exists(subgolog_folder_path): os.mkdir(subgolog_folder_path)
            ####
            folder_path = os.path.join(self.folder_path, *golog_dict['folder_path'])
            print(folder_path)
            controllable_golog = mode_head(self.base, subgolog, folder_path = folder_path, parent = self)
            window_manager.modeHeadToWindow(self.base, controllable_golog)

        if math_data.type == 'file':
            file_name, file_extension = os.path.splitext(math_data()[-1])
            # if file_extension == '.txt':
            #     tk_funcs.edit_txt(os.path.join(self.folder_path,*math_data()))
            # else:
                #prompt user to select a program
            tk_funcs.run_program('',os.path.join(self.folder_path,*math_data()))
        if math_data.type == 'latex':
            file_dict = math_data()
            tex_folder = os.path.join(os.path.abspath(self.folder_path),*file_dict['folder'])
            tex_file = os.path.join(os.path.abspath(self.folder_path),*file_dict['tex'])




            if 'pdf' in file_dict.keys():
                pdf_file = os.path.join(self.folder_path, *file_dict['pdf'])
            elif os.path.exists(tex_file.split('.tex')[0]+'.pdf'): #if there is a pdf in the folder with the same name
                file_dict['pdf'] = file_dict['tex']
                file_dict['pdf'][-1] = file_dict['pdf'][-1].split('.tex')[0]+'.pdf' #change extension to .pdf
                pdf_file = os.path.join(self.folder_path, *file_dict['pdf'])
            else: pdf_file = None


            tk_funcs.pdf_or_tex(pdf_file, tex_file)

        if math_data.type == 'weblink':
            open_new_tab(math_data())

    def update_math_data(self,simplex, math_data_type, **kwargs):


        if autosave == True: self.save()

        if 'label' in kwargs: simplex.label = kwargs['label']
        self.golog.Simplex_to_Graphics[simplex].textNP.node().setText(simplex.label)
        self.golog.text_preview_set(self.bools['textboxes'])

        if simplex.math_data.type != 'None':
            answer = tk_funcs.are_you_sure('are you sure you want to delete the current math_data?')
            if answer == 'yes':
                self.delete_math_data(simplex)
            else: return
        if math_data_type == 'None':
            simplex.math_data = hcat.Math_Data(type = 'None')

        if math_data_type == 'golog':

            #create a path for all subgologs, if it doesn't already exist
            subgolog_folder_path = os.path.join(self.folder_path,'subgologs')
            if not os.path.exists(subgolog_folder_path): os.mkdir(subgolog_folder_path)




            new_golog = golog.golog(self.base, label = kwargs['label']) #create a new golog

            #create a unique folder path list in subgolog_folder_path
            unique_path = tk_funcs.unique_path(subgolog_folder_path,[kwargs['label']])
            new_folder_path = ['subgologs', *unique_path]
            os.mkdir(os.path.join(self.folder_path , *new_folder_path)) #make the directory as above
            #create a new golog save at new_folder_path/label.golog
            new_save_location = os.path.join(self.folder_path, *new_folder_path, kwargs['label']+'.golog')

            #new_save_location should be a subfolder of subgologs
            gexport(new_golog, new_save_location)

            #math data is a dictionary of the physical golog and it's relative save path list
            golog_dict = {'golog':new_golog, 'folder_path':new_folder_path}
            simplex.math_data = hcat.Math_Data(math_data = golog_dict, type = 'golog')

        if math_data_type == 'file':
            if not os.path.exists(os.path.join(self.folder_path,'files')): os.mkdir(os.path.join(self.folder_path,'files'))
            file_folder_path = ['files']

            file_location = tk_funcs.ask_file_location()
            if not file_location: return #if user cancels
            file_name = os.path.split(file_location)[1] #file name with extension
            file_path = tk_funcs.unique_path(os.path.join(self.folder_path),[*file_folder_path, file_name]) #get a unique file path starting from the file_folder
            copyfile(file_location, os.path.join(self.folder_path,*file_path))
            simplex.math_data = hcat.Math_Data(math_data = file_path, type = 'file')
            #? add handler for if user exits text editor
            #? make asynchronous

        if math_data_type == 'latex':
            #ensure latex folder exists
            if not os.path.exists(os.path.join(self.folder_path,'latex')): os.mkdir(os.path.join(self.folder_path,'latex'))

            # create a uniquely named folder in self.folder_path/latex/ based on simplex.label
            tex_folder_path = tk_funcs.unique_path(root = self.folder_path, path = ['latex',simplex.label])
            os.mkdir(os.path.join(self.folder_path, *tex_folder_path))
            #create a tex file in tex folder
            tex_file_path = [*tex_folder_path, simplex.label+'.tex']
            # ask if want new or to load one
            location = tk_funcs.load_tex(self.folder_path)
            # if new, returns True and copies template tex file
            # if load, returns a path and copies the path into tex_file_path
            true_path = os.path.join(self.folder_path,*tex_file_path)
            if location == True: copyfile(os.path.abspath('./misc_data/config_files/template.tex'), true_path)

                #
                # open(   true_path  , 'w').close()
            if isinstance(location, str): copyfile(location, true_path)

            # make a file dictionary with just tex file in it
            file_dict = {'tex':tex_file_path, 'folder':tex_folder_path}
            simplex.math_data = hcat.Math_Data(math_data = file_dict, type = 'latex')

        if math_data_type == 'weblink':
            weblink = tk_funcs.ask_weblink()
            simplex.math_data = hcat.Math_Data(math_data = weblink, type = 'weblink')


        if math_data_type == 'text':
            #create a text file
            if not os.path.exists(os.path.join(self.folder_path,'files')): os.mkdir(os.path.join(self.folder_path,'files'))
            file_folder_path = ['files']
            file_path = tk_funcs.unique_path(root = self.folder_path, path = ['files',simplex.label+'.txt' ])
            with open(os.path.join(self.folder_path, *file_path),'w') as file: pass
            #create a math_data for it
            simplex.math_data = hcat.Math_Data(math_data = file_path, type = 'file')



        #save golog
        if autosave == True: self.save()
        return simplex.math_data

    def delete_math_data(self,simplex,**kwargs):
        simplex.math_data.delete(self.folder_path)
        simplex.math_data = hcat.Math_Data(type = 'None')

    def setup_window(self, windict):
        self.windict = windict
        for button in self.buttons.keys():
            self.listener.accept(self.windict['bt'].prefix+button, self.buttons[button], extraArgs = [self.windict['mw']])
        for window_task in self.window_tasks.keys():
            base.taskMgr.add(self.window_tasks[window_task], window_task, extraArgs = [self.windict['mw']], appendTask = True)
        self.has_window = True

    def save(self, *ask):
        #if has a parent, save the parent. If not, save itself
        if not self.parent: #if doesn't have a parent mode_head, save parent
        #if we pass something to ask it will ask (this includes mousewatchers)
            if ask:
                save_location = tk_funcs.ask_file_location(initial_dir = self.folder_path)
                if not save_location: return #if user cancels
                print('saving to:\n'+save_location)
                gexport(self.golog,  self.folder_path)
            else:
                gexport(self.golog,  self.file_path)

        else: self.parent.save()# if parent has no mode_head, save itself

    #basic reset function which shuts off the listener and removes button bindings. Should only be called if no "reset" function exists
    def basic_reset(self,*args):
        self.buttons = dict()
        self.window_tasks = dict()
        self.listener.ignoreAll()

    #function to call before deleting the mode_head, for example when closing a window
    def clean(self):
        self.reset()

        #close window
        if self.has_window == True:
            if hasattr(mode_head,'windict'):
                if 'win' in mode_head.windict.keys():
                    self.base.closeWindow(mode_head.windict['win'], keepCamera = True, removeWindow = True)
            self.has_window = False
        del self.golog.mode_heads[self.index]
        del self.reset

    # function to return the only the relevant collision data from the mouseRay
    def get_relevant_entries(self, mw):
        # get list of entries by distance
        if not mw.node().hasMouse(): return
        mpos = mw.node().getMouse()
        self.pickerRay.setFromLens(self.golog.camNode,mpos.getX(),mpos.getY()) #mouse ray goes from camera through the 'lens plane' at position of mouse
        self.golog.cTrav.traverse(self.golog.render)
        self.queue.sortEntries()

        # get the first relevant node traversed by mouseRay
        #### ignore everything with a mode_head tag that is not defined by this mode_head
        for e in self.queue.getEntries():
            if e.getIntoNodePath().getParent().hasTag("mode_head"):
                if e.getIntoNodePath().getParent().getTag("mode_head") == self.label:
                    return (e.getIntoNodePath().getParent(), e.getIntoNodePath().getParent().getTag("mode_node"),e.getSurfacePoint(e.getIntoNodePath()))
                    break
            else:
                entry = e
                break

        #return node create_list in the golog
        entryNP = entry.getIntoNodePath().getParent()
        if entryNP.hasTag('level'): return (entryNP, entryNP.getTag('level'),entryNP.getPos())

    #function to 'pick up' a node by adding it to the dragged dictionary
    def pickup(self, mw):
        if not mw.node().hasMouse(): return
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
        


        ### get position on plane for mouseloc
        mpos = mw.node().getMouse()
        self.pickerRay.setFromLens(self.golog.camNode,mpos.getX(),mpos.getY()) #mouse ray goes from camera through the 'lens plane' at position of mouse
        self.golog.cTrav.traverse(self.golog.render)
        self.queue.sortEntries()
        for e in self.queue.getEntries():
            if e.getIntoNodePath().getParent().hasTag("mode_head"):
                if e.getIntoNodePath().getParent().getTag("mode_head") == self.label:
                    if e.getIntoNodePath().getParent().getTag("mode_node") == 'plane':
                        self.mouse_down_loc = e.getSurfacePoint(e.getIntoNodePath())
                        break


        #if selected node is in the drag_dict, use it to set a mouse location
        # if entryNP in self.drag_dict.keys(): self.mouse_down_loc = entryNP.getPos()

        if node_type in ['0','1']:
            self.grabbed_dict = {'graphics': self.golog.NP_to_Graphics[entryNP],'dragged':False,
                                                        'orig_pos': entryNP.getPos()}
        if node_type == 'plane':
            for node in self.create_list[0]: node.setColorScale(1,1,1,1) #turn white
            self.create_list = [[],[]]
            for node in self.drag_dict.keys():  node.setColorScale(1,1,1,1)
            self.drag_dict = dict() #drag dict is used for multi-dragging
            a = self.plane.distToPlane(self.golog.camera.getPos())/(2*self.golog.camera.node().getLens().getNear())# ratio for camera movement
            self.grabbed_dict = {'graphics':self.golog.camera, 'dragged':False, 'orig_pos': self.golog.camera.getPos(), 'mpos': LPoint3f(a*mpos.getX(),a*0,a*mpos.getY())}
            self.lowest_level = 3



    #function to 'put down' a node, returns true if it's dragged something
    def putdown(self, mw):
        for node in self.drag_dict.keys():
            self.drag_dict[node] = self.golog.NP_to_Graphics[node].graphics_kwargs['pos']
            self.lowest_level = min(self.lowest_level, int(node.getTag('level')))

        if 'dragged' in self.grabbed_dict.keys():
            if self.grabbed_dict['dragged'] == True:
                self.grabbed_dict = dict()
                return True
            self.grabbed_dict = dict()
    #function to select a node and add a 1-simplex between 2 create_list 0-simplecies
    def select_for_creation(self, mw):
        if not mw.node().hasMouse(): return
        #remove selected
        for node in self.drag_dict.keys():
            node.setColorScale(1,1,1,1)
        self.drag_dict = dict()
        self.lowest_level = 3

        ### selection ###
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
        if node_type == '0':# and set(create_list[1:]) = {[]}:
            if entryNP not in self.create_list[0]:
                #?  don't just append, re-sort
                self.create_list[0].append(entryNP)
            entryNP.setColorScale(1,0,0,0) #turn red

        if len(self.create_list[0]) == 2:
            # NP -> graphics -> simplex
            faces = tuple([self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[faceNP]] for faceNP in self.create_list[0][-1:-3:-1]])
            asked_list = tk_funcs.ask_math_data('1-Simplex')
            if not asked_list: #[label, math_data_type,]
                return
            simplex = self.golog.add(faces, label = asked_list[0]) #reversed create_list objects and creates a 1 - simplex from them
            self.update_math_data(simplex, asked_list[1], label = asked_list[0])
            for node in self.create_list[0]: node.setColorScale(1,1,1,1)
            self.create_list[0] = [] #reset create_list

    #open math_data of simplex under mouse
    def mouse_open(self, mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)

        # if spaced on a 0 simplex, open it's math data, or create it
        if node_type in ['0','1']:
            simplex = self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
            if not simplex.math_data():
                asked_list = tk_funcs.ask_math_data(simplex.label)
                if not asked_list:
                    return
                self.update_math_data(simplex, math_data_type = asked_list[1], label = asked_list[0])
                #? make asynchronous


            else:
                self.open_math_data(simplex.math_data)

    # delete a simplex, prompt to delete the math_data and (recursively) it's supported simplecies
    def delete(self,mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
        if node_type in ['0','1']:
            #warning about deleting supported simplecies

            graphics = self.golog.NP_to_Graphics[entryNP]
            simplex = self.golog.Graphics_to_Simplex[graphics]

            if simplex.supports:
                answer = tk_funcs.are_you_sure(simplex.label+' still supports other simplecies. Are you sure you wish to delete?')
                if answer != 'yes': return

            self.delete_math_data(simplex)
            graphics._remove()

    #update the math_data of a simplex under the mouse
    def mouse_update(self, mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
        if node_type in ['0','1']:
            simplex = self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
            asked_list = tk_funcs.ask_math_data(simplex.label)
            if not asked_list:
                return
            self.update_math_data(simplex, math_data_type = asked_list[1], label = asked_list[0])

    #create a simplex given a mouse position
    def create(self, mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)

        if node_type == 'plane':
            for node in self.create_list[0]: node.setColorScale(1,1,1,1) #turn white
            self.create_list = [[],[]]
            asked_list = tk_funcs.ask_math_data('0-Simplex')
            if not asked_list:
                return #if canceled, do not create a simplex
            simplex = self.golog.add(0, pos = entry_pos, label = asked_list[0]) #create a simplex
            self.update_math_data(simplex, math_data_type = asked_list[1], label = asked_list[0])

    #function which checks the drag dictionary and drags stuff
    def drag(self, mw):
        if self.grabbed_dict:
            #get mouse_loc
            mpos = mw.node().getMouse()
            self.pickerRay.setFromLens(self.golog.camNode,mpos.getX(),mpos.getY()) #mouse ray goes from camera through the 'lens plane' at position of mouse
            self.golog.cTrav.traverse(self.golog.render)
            self.queue.sortEntries()
            mouseloc = None
            for e in self.queue.getEntries():
                if e.getIntoNodePath().getParent().getTag("mode_node") == 'plane':
                    mouseloc = e.getSurfacePoint(e.getIntoNodePath())
                    break
            if not mouseloc:return

            self.bools['dragging'] = True


             # if there is something in the drag dict (for multiselect)
            if self.drag_dict:
                self.grabbed_dict['dragged'] = True
                #only drag lowest dim simplecies
                for node in self.drag_dict.keys():
                    if int(node.getTag('level')) == self.lowest_level: self.golog.NP_to_Graphics[node].update({'pos':self.drag_dict[node]+mouseloc-self.mouse_down_loc})

            #if nothing is selected, drag the thing below you
            elif self.grabbed_dict['graphics'] != self.golog.camera: 
                #radius of drag selection
                offset = mouseloc - self.grabbed_dict['graphics'].parent_pos_convolution()
                delta = offset - self.grabbed_dict['orig_pos']
                norm = delta.getX()**2 +delta.getY()**2 +delta.getZ()**2
                if self.grabbed_dict['dragged'] == True or norm > 1:
                    self.grabbed_dict['dragged'] = True
                #if offset magnitude is greater than 1 or dragged == true, actually drag it
                if self.grabbed_dict['dragged'] == True: self.grabbed_dict['graphics'].update({'pos':offset})

            elif self.grabbed_dict['graphics'] == self.golog.camera: 
                        a = self.plane.distToPlane(self.golog.camera.getPos())/(2*self.golog.camera.node().getLens().getNear())# ratio for camera movement
                        self.golog.camera.setPos(self.grabbed_dict['orig_pos']-(a*mpos.getX(),0,a*mpos.getY())+self.grabbed_dict['mpos'])

           
                    


    #send preview of math_data of simplex under the mouse
    def preview(self, mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)

        if node_type == '0':
            simplex =  self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
        elif node_type == '1':
            #? again consider what needs to be shown with 1-simplecies
            simplex =  self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
        else: return

        # set preview up
        if self.has_window:
            if simplex.math_data.type == 'golog':
                self.windict['preview_dr'].setCamera(simplex.math_data()['golog'].camera)
            else:
                self.windict['preview_dr'].setCamera(self.camera2D)
                self.textNP.node().setText("label:\n" +simplex.label+"\n\n math data type:\n" + simplex.math_data.type)
        return

    def pprint(self,mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)

        if node_type == '0':
            simplex =  self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
        elif node_type == '1':
            #? again consider what needs to be shown with 1-simplecies
            simplex =  self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
        else: return

        simplex.pprint()


    #tool for selecting multiple simplecies
    def multi_select(self,mw):
        if isinstance(mw, NodePath):
            entryNP = mw
            node_type = entryNP.getTag('level')
        else: return

        #reset select and create
        if node_type in ['0','1']:
            if entryNP in self.drag_dict.keys():
                del self.drag_dict[entryNP]
                entryNP.setColorScale(1,1,1,1)
                self.lowest_level = min([*[int(node.getTag('level')) for node in self.drag_dict.keys()],3])
            else:
                self.drag_dict[entryNP] = self.golog.NP_to_Graphics[entryNP].graphics_kwargs['pos']
                entryNP.setColorScale(.5,.5,0,1)
                self.lowest_level = min(self.lowest_level, int(entryNP.getTag('level')))

    def shift_box(self,mw):
        if None in self.dict['shift_pt']:
            self.dict['shift_pt'] = [None,None]
            return
        pt_1 = self.dict['shift_pt'][0]
        pt_2 = self.dict['shift_pt'][1]
        if sum([x**2 for x in list(pt_2-pt_1)]) <= 1:
            (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
            self.multi_select(entryNP)

        #create vectors
        N = self.planeFromObject.node().getSolid(0).getNormal()
        x = [(pt_2-pt_1).getX(),0,0]
        z = [0,0,(pt_2-pt_1).getZ()]
        campos = list(self.golog.camera.getPos())
        for simplex in self.golog.sSet.rawSimps:
            node = self.golog.Simplex_to_Graphics[simplex].node_list[0]
            P = list(node.getPos())
            if t_int(pt_1,x,z,campos,P): self.multi_select(node)

        self.dict['shift_pt'] = [None,None]


    def consolidate(self, selected = False,sel_simp = None):
        #ask for label, or cancel
        G = self.golog

        # if a collection isn't provided, use the (multi-select) drag dictionary
        if not selected: selected = [G.Graphics_to_Simplex[G.NP_to_Graphics[node]] for node in self.drag_dict.keys()]
        if not selected: return #return if there was nothing passed, and nothing in the drag_dict
        for simp in selected:
            for face in simp.faces:
                if face not in selected: selected.append(face)

        # #? select a simplex to consolidate into
        # sel_simp = None
        # for simp in selected: 
        #     if simp.math_data.type == 'None':
                
        #         sel_simp = simp

        #make a golog from selected
        new_golog = golog.golog(self.base, label ='test')

        def add(simplex):
            for face in simplex.faces:
                add(face)
            new_golog.add(simplex, pos = G.Simplex_to_Graphics[simplex].graphics_kwargs['pos'])
        for simplex in selected: add(simplex)
        

        #consolidate into 1 simplex
        if sel_simp:
            #consolidate into sel_simp
            subgolog_folder_path = os.path.join(self.folder_path,'subgologs')
            unique_path = tk_funcs.unique_path(subgolog_folder_path,[sel_simp.label])
            new_folder_path = ['subgologs', *unique_path]
            
            sel_simp.math_data = hcat.Math_Data(math_data = {'golog':new_golog, 'folder_path':new_folder_path}, type = 'golog')
            
            #? remove simplexes and place at selected simplex location
            return sel_simp


        #create an entirely new simplex to put the golog into
        else:
            #? ask for label / cancel
            label = "test"
            subgolog_folder_path = os.path.join(self.folder_path,'subgologs')
            unique_path = tk_funcs.unique_path(subgolog_folder_path,[label])
            new_folder_path = ['subgologs', *unique_path]

            #create a simplex with average position of things in golog
            avg = LPoint3f(*[sum([G.Simplex_to_Graphics[simplex].graphics_kwargs['pos'][i]/len(new_golog.sSet.simplecies[()])  for simplex in new_golog.sSet.simplecies[()]]) for i in range(3)])
            s = self.golog.add(0, label ='test', math_data = hcat.Math_Data(math_data = {'golog':new_golog, 'folder_path':new_folder_path}, type = 'golog'), pos = LPoint3f(avg))

            return s

    ########## BEGIN DEFINING MODES ##########

    #selection and creation mode
    def selection_and_creation(self, windict):
        def mouse1(mw):
            if not mw: return
            self.bools['shift_clicked'] = False
            self.pickup(mw)

        def shift_mouse1(mw):
            if not mw: return
            #on click, begin a rectagle dragging function
            (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
            self.dict['shift_pt'][0] = entry_pos
            self.bools['shift_clicked'] = True

        def mouse1_up(mw):
            dropped_bool = self.putdown(mw)
            if self.bools['shift_clicked']:
                (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
                self.dict['shift_pt'][1] = entry_pos
                self.shift_box(mw)
                self.bools['shift_clicked'] = False

            elif dropped_bool:
                pass
            else:
                self.select_for_creation(mw)




        def space(mw):
            if not mw: return
            self.mouse_open(mw)

        def u(mw):
            if not mw: return
            #?  do a change not just update
            self.mouse_update(mw)

        def c(mw):
            self.consolidate()
        def p(mw):
            if not mw: return
            self.pprint(mw)

        def mouse3(mw):
            if not mw: return
            self.create(mw)

        def backspace(mw):
            if not mw: return
            self.delete(mw)

        def mouse_watch_task(mw,task):
            if not mw: return task.cont
            if not mw.node().hasMouse(): return task.cont
            self.drag(mw)
            self.preview(mw)
            return task.cont

        def wheel_up(mw):
            if not mw:return
            a = self.plane.distToPlane(self.golog.camera.getPos())/(2*self.golog.camera.node().getLens().getNear())# ratio for camera movement
            self.golog.camera.setPos( self.golog.camera.getPos() + (0,10,0) ) #fix for offset by storing a global camera - plane ratio

        def wheel_down(mw):
            if not mw:return
            self.golog.camera.setPos( self.golog.camera.getPos() - (0,10,0) )

        def reset(*args):
            self.buttons = dict()
            self.window_task = dict()
            self.reset = self.basic_reset
        self.reset = reset

        self.buttons = {'mouse1':mouse1, 'mouse1-up':mouse1_up, 'mouse3':mouse3,'c':c,
        'space':space, 'escape':self.reset, 's':self.save, 'u':u,'backspace':backspace,
        'shift-mouse1':shift_mouse1,'p':p,'wheel_up':wheel_up, "wheel_down":wheel_down}
        self.window_tasks = {'mouse_watch_task':mouse_watch_task}
        self.setup_window(windict)
Example #17
0
class KeyboardController(DirectObject):
    def __init__(self, base):
        DirectObject.__init__(self)
        self.base = base
        self.lastUpdate = 0.0

        # Parameters
        self.wheelBaseOffset = 3.4
        self.wheelSideOffset = 3.1
        self.speedMax = 50.0
        self.steerAngleMax = 20.0
        self.numSensors = 5
        self.sensorHeight = 2.0

        # Collisions
        self.collisionHandler = CollisionHandlerQueue()

        # Load car model
        self.car = self.base.loader.loadModel("models/carBody")
        self.car.reparentTo(self.base.render)

        self.wheelFrontLeft = self.base.loader.loadModel("models/carWheel")
        self.wheelFrontLeft.reparentTo(self.car)
        self.wheelFrontLeft.setX(self.wheelBaseOffset)
        self.wheelFrontLeft.setY(self.wheelSideOffset)

        self.wheelFrontRight = self.base.loader.loadModel("models/carWheel")
        self.wheelFrontRight.reparentTo(self.car)
        self.wheelFrontRight.setX(self.wheelBaseOffset)
        self.wheelFrontRight.setY(-self.wheelSideOffset)

        self.wheelBackLeft = self.base.loader.loadModel("models/carWheel")
        self.wheelBackLeft.reparentTo(self.car)
        self.wheelBackLeft.setX(-self.wheelBaseOffset)
        self.wheelBackLeft.setY(self.wheelSideOffset)

        self.wheelBackRight = self.base.loader.loadModel("models/carWheel")
        self.wheelBackRight.reparentTo(self.car)
        self.wheelBackRight.setX(-self.wheelBaseOffset)
        self.wheelBackRight.setY(-self.wheelSideOffset)

        # Car properties
        self.steerAngle = 0.0
        self.speed = 0.0
        self.wheelFront = Vec3(1.0, 0.0, 0.0) * self.wheelBaseOffset
        self.wheelBack = Vec3(-1.0, 0.0, 0.0) * self.wheelBaseOffset
        self.initSensors(self.numSensors, self.sensorHeight)

        # Controls
        self.arrowUpDown = False
        self.arrowLeftDown = False
        self.arrowRightDown = False
        self.accept("arrow_up", self.onUpArrow, [True])
        self.accept("arrow_up-up", self.onUpArrow, [False])
        self.accept("arrow_left", self.onLeftArrow, [True])
        self.accept("arrow_left-up", self.onLeftArrow, [False])
        self.accept("arrow_right", self.onRightArrow, [True])
        self.accept("arrow_right-up", self.onRightArrow, [False])
        self.base.taskMgr.add(self.updateCar, "UpdateCarTask")

        # DEBUG
        self.drawAxis(10)
        self.drawWheelBase()

    def initSensors(self, n, h):
        origin = Point3(0.0, 0.0, h)
        angles = [math.pi * t / (n - 1) for t in range(n)]
        sensors = [Vec3(math.sin(ang), math.cos(ang), h) for ang in angles]

        # Create collision nodes for sensors
        sensorNode = CollisionNode('sensor')
        sensorRay = CollisionRay(origin, Vec3(1.0, 0.0, 0.0))
        sensorNode.addSolid(sensorRay)

        # Add collision node to car and handler
        sensorNodePath = self.car.attachNewNode(sensorNode)
        self.base.cTrav.addCollider(sensorNodePath, self.collisionHandler)
        self.base.taskMgr.add(self.checkCollisions, "CheckCollisionsTask")

    def checkCollisions(self, task):
        for entry in self.collisionHandler.getEntries():
            pass

        return task.cont

    def getNodePath(self):
        return self.car

    def onUpArrow(self, down):
        self.arrowUpDown = down

    def onLeftArrow(self, down):
        self.arrowLeftDown = down

    def onRightArrow(self, down):
        self.arrowRightDown = down

    def degToRad(self, deg):
        return deg * (math.pi / 180.0)

    def radToDeg(self, rad):
        return rad * (180.0 / math.pi)

    def updateCar(self, task):
        # Register controls
        if self.arrowUpDown:
            self.speed = self.speedMax
        else:
            self.speed = 0.0
        if self.arrowLeftDown and not self.arrowRightDown:
            self.steerAngle = self.steerAngleMax
        if self.arrowRightDown and not self.arrowLeftDown:
            self.steerAngle = -self.steerAngleMax
        if not self.arrowLeftDown and not self.arrowRightDown:
            self.steerAngle = 0.0

        # Update car pose
        dt = task.time - self.lastUpdate
        self.lastUpdate = task.time

        wheelFrontUpdate = self.wheelFront + Vec3(
            math.cos(self.degToRad(self.steerAngle)),
            math.sin(self.degToRad(self.steerAngle)), 0.0) * self.speed * dt
        wheelBackUpdate = self.wheelBack + Vec3(1.0, 0.0,
                                                0.0) * self.speed * dt

        positionLocalUpdate = (wheelFrontUpdate + wheelBackUpdate) / 2.0
        headingLocalUpdate = math.atan2(
            wheelFrontUpdate.getY() - wheelBackUpdate.getY(),
            wheelFrontUpdate.getX() - wheelBackUpdate.getX())

        self.car.setPos(self.car, positionLocalUpdate)
        self.car.setH(self.car, self.radToDeg(headingLocalUpdate))
        self.wheelFrontLeft.setH(self.steerAngle)
        self.wheelFrontRight.setH(self.steerAngle)

        return task.cont

    def drawAxis(self, scale):
        axisSegs = LineSegs("axis")
        axisSegs.setThickness(5)
        axisSegs.setColor(1.0, 0.0, 0.0)
        axisSegs.moveTo(Point3(0.0, 0.0, 0.0))
        axisSegs.drawTo(Point3(1.0, 0.0, 0.0) * scale)

        axisSegs.setColor(0.0, 1.0, 0.0)
        axisSegs.moveTo(Point3(0.0, 0.0, 0.0))
        axisSegs.drawTo(Point3(0.0, 1.0, 0.0) * scale)

        axisSegs.setColor(0.0, 0.0, 1.0)
        axisSegs.moveTo(Point3(0.0, 0.0, 0.0))
        axisSegs.drawTo(Point3(0.0, 0.0, 1.0) * scale)

        axisNode = axisSegs.create()
        axisNodePath = self.car.attachNewNode(axisNode)
        axisNodePath.setZ(axisNodePath, 1.0)
        return axisNodePath

    def drawWheelBase(self):
        wheelSegs = LineSegs("wheelBase")
        wheelSegs.setThickness(5)
        wheelSegs.moveTo(self.wheelFront + Vec3(0.0, 5.0, 1.44))
        wheelSegs.drawTo(self.wheelFront + Vec3(0.0, -5.0, 1.44))

        wheelSegs.moveTo(self.wheelBack + Vec3(0.0, 5.0, 1.44))
        wheelSegs.drawTo(self.wheelBack + Vec3(0.0, -5.0, 1.44))

        wheelNode = wheelSegs.create()
        wheelNodePath = self.car.attachNewNode(wheelNode)
        return wheelNodePath
class RoamingRalphDemo(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)
        self.orbCollisionHandler = CollisionHandlerQueue()
        self.cTrav = CollisionTraverser()
        self.cTrav.setRespectPrevTransform(True)

        #hbPath = NodePath()

        utilsKristina2.setUpKeys(self)
        utilsKristina2.loadModels(self)
        utilsKristina2.setUpLighting(self)
        utilsKristina2.setUpFloatingSpheres(self)
        utilsKristina2.setUpRalphsShot(self)
        utilsKristina2.setUpCamera(self)
        utilsKristina2.setUpCollisionSpheres(self)
        self.healthTxt = utilsKristina2.addInstructions(.06,"Health: 100")
        self.orbTxt = utilsKristina2.addInstructions(.18,"Orbs: 0")

        self.vec = LVector3(0,1,0)#vector for pawns shot

        # Create a frame
        #frame = DirectFrame(text = "main", scale = 0.001)
        # Add button
        #bar = DirectWaitBar(text = "", value = 50, pos = (0,.4,.4))
        #bar.reparent(render)

        # Game state variables
        self.isMoving = False
        self.jumping = False
        self.vz = 0
        self.numOrbs = 0
        self.healthCount = 100

        #self.shotList = []




        #self.sphere = CollisionBox((self.ralph.getX() + -10,self.ralph.getY(),self.ralph.getZ()),10,10,10)
        self.sphere = CollisionSphere(0,-5,4,3)
        self.sphere3 = CollisionSphere(0,5,5,3)
        self.sphere4 = CollisionSphere(-4,0,5,2)
        self.sphere5 = CollisionSphere(4,0,5,2)
        self.sphere2 = CollisionSphere(0,0,3,2)
        self.cnodePath = self.ralph.attachNewNode((CollisionNode("ralphColNode")))
        self.cnodePath2 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck")))
        self.cnodePath3 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck2")))
        self.cnodePath4 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck3")))
        self.cnodePath5 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck4")))
        self.cnodePath.node().addSolid(self.sphere2)
        self.cnodePath2.node().addSolid(self.sphere)
        self.cnodePath3.node().addSolid(self.sphere3)
        self.cnodePath4.node().addSolid(self.sphere4)
        self.cnodePath5.node().addSolid(self.sphere5)
        #self.cnodePath.node().addSolid(self.sphere2)
        self.cnodePath.show()
        #self.cnodePath2.show()
        #self.cnodePath3.show()
        #self.cnodePath4.show()
        #self.cnodePath5.show()
        self.cTrav.addCollider(self.cnodePath2, self.orbCollisionHandler)
        self.cTrav.addCollider(self.cnodePath3, self.orbCollisionHandler)
        self.cTrav.addCollider(self.cnodePath4, self.orbCollisionHandler)
        self.cTrav.addCollider(self.cnodePath5, self.orbCollisionHandler)


        self.pusher = CollisionHandlerPusher()
        self.pusher.addCollider(self.cnodePath, self.ralph)

        #self.cTrav.addCollider(self.cnodePath, self.ralphCollisionHandler)
        self.cTrav.addCollider(self.cnodePath, self.pusher)


        self.chrisLastShotTime = globalClock.getFrameTime()
        self.chrisTimer = globalClock.getDt()

        #def __init__(self, pos,showbase, colPathName, dir, length):
        self.chrisList = [utilsKristina2.chris((15,0,0.5),self,"chrisColPath0","X",6), utilsKristina2.chris((18,29,0.5),self,"chrisColPath1","X",6),
                          utilsKristina2.chris((-6,67,0.5),self,"chrisColPath2","X",6), utilsKristina2.chris((-41,72,0.5),self,"chrisColPath7","X",6)]
                          #,utilsKristina2.chris((-42,106,0.5),self,"chrisColPath3","X",6)]#, utilsKristina2.chris((-62,108,0.5),self,"chrisColPath4","X",6),
                          #utilsKristina2.chris((-74,70,0.5),self,"chrisColPath5","y",6)]
        #def _init_(self,showbase,pos,color,speed,radius):
        self.orbList = [utilsKristina2.orb(self,(0,0,2),(0,0,1,1),20,4)]

        self.donutList = [utilsKristina2.donut(self,(0,0,2),40,3)]

        self.cameraCollided = False
        self.ralphSpeed = 60
        self.ralphHit = False
        self.ralphRedTime = 0
        self.ralphLife=True

        taskMgr.add(self.move, "moveTask")
        taskMgr.add(self.moveChris,"moveChrisTask")

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value


    def startEnemyThread(self):
        showbase = self
        class enemyThread(threading.Thread):
            def run(self):
                dt = globalClock.getDt()
                for chris in showbase.chrisList:
                    chris.moveChris(dt,showbase,showbase.chrisList)

    def moveChris(self,task):
        dt = globalClock.getDt()
        for chris in self.chrisList:
            chris.moveChris(dt,self,self.chrisList)
        return task.cont

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):



        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()
        #utilsKristina2.moveChris(self,dt)
        #self.chris2.moveChris(dt,self)
        #self.startEnemyThread()


        if globalClock.getFrameTime()- self.ralphRedTime > .3 and self.ralphHit == True:
                self.ralph.clearColor()
                self.ralphHit = False

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        if self.keyMap["cam-left"]:
            self.camera.setZ(self.camera, -20 * dt)
        if self.keyMap["cam-right"]:
            self.camera.setZ(self.camera, +20 * dt)

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if self.keyMap["left"]:
            self.ralph.setH(self.ralph.getH() + 75 * dt)
            #self.camera.setX(self.camera, +15.5 * dt)
        if self.keyMap["right"]:
            self.ralph.setH(self.ralph.getH() - 75 * dt)
            #self.camera.setX(self.camera, -15.5 * dt)
        if self.keyMap["forward"]:
            self.ralph.setFluidY(self.ralph, -1*self.ralphSpeed * dt)
            #self.camera.setY(self.camera, -35 * dt)
        if self.keyMap["back"]:
            self.ralph.setFluidY(self.ralph, self.ralphSpeed * dt)
            #self.camera.setY(self.camera, 35 * dt)
        if self.keyMap["space"]:
            if self.jumping is False:
            #self.ralph.setZ(self.ralph.getZ() + 100 * dt)
                self.jumping = True
                self.vz = 8

        if self.keyMap["c"] or self.keyMap["enter"]:
            if self.keyMap["c"]:
                self.keyMap["c"]=False
            if self.keyMap["enter"]:
                self.keyMap["enter"] = False
            self.shotList[self.shotCount].lpivot.setPos(self.ralph.getPos())
            self.shotList[self.shotCount].lpivot.setZ(self.ralph.getZ() + .5)
            self.shotList[self.shotCount].lpivot.setX(self.ralph.getX() - .25)
            print self.ralph.getPos()

            #self.shotList.append(rShot)
            #self.lightpivot3.setPos(self.ralph.getPos())
            #self.lightpivot3.setZ(self.ralph.getZ() + .5)
            #self.lightpivot3.setX(self.ralph.getX() - .25)
            #self.myShot.setHpr(self.ralph.getHpr())
            #parent to ralph
            #node = NodePath("tmp")
            #node.setHpr(self.ralph.getHpr())
            #vec = render.getRelativeVector(node,(0,-1,0))
            #self.myShotVec = vec

            node = NodePath("tmp")
            node.setHpr(self.ralph.getHpr())
            vec = render.getRelativeVector(node,(0,-1,0))
            self.shotList[self.shotCount].vec = vec
            self.shotCount = (self.shotCount + 1) % 10


        for rs in self.shotList:
            rs.lpivot.setPos(rs.lpivot.getPos() + rs.vec * dt * 25 )
            #if shot is too far stop updating



        if self.jumping is True:
            self.vz = self.vz - 16* dt
            self.ralph.setZ(self.ralph.getZ() + self.vz * dt )
            if self.ralph.getZ() < 0:
                self.ralph.setZ(0)
                self.jumping = False
        else:
            if self.ralph.getZ() < 0.25:
                self.ralph.setZ(0.25)
            elif self.ralph.getZ() > 0.25:
                self.ralph.setZ(self.ralph.getZ() -7 * dt)

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.
        if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"] or self.keyMap["space"] or self.keyMap["forward"] or self.keyMap["back"]:
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True

        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        # update pawns shot or set up new shot after it reaches a certain distance
        node = NodePath("tmp")
        node.setHpr(self.pawn.getHpr())
        vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))
        self.shot.setPos(self.shot.getPos() + self.vec * dt * 10 )
        if self.shot.getY() < -15 or self.shot.getY() > 30 or self.shot.getX() < 5 or self.shot.getX() > 15:
            self.shot.setPos(self.pawn.getPos() + (0,0,0))
            self.vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))
            self.vec = render.getRelativeVector(node,(random.random() * random.randrange(-1,2),random.random() + 1,0))

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.
        #self.camera.lookAt(self.floater)
        camvec = self.ralph.getPos() - self.camera.getPos()
        #camvec = Vec3(0,camvec.getY(),0)
        camdist = camvec.length()
        x = self.camera.getZ()
        camvec.normalize()
        #if camdist > 6.0:
        #    self.camera.setPos(self.camera.getPos() + camvec * (camdist - 6))
        #if camdist < 6.0:
        #    self.camera.setPos(self.camera.getPos() - camvec * (6 - camdist))

        # Normally, we would have to call traverse() to check for collisions.
        # However, the class ShowBase that we inherit from has a task to do
        # this for us, if we assign a CollisionTraverser to self.cTrav.
        #self.cTrav.traverse(render)

        # Adjust camera so it stays at same height
        if self.cameraCollided == False:
            if self.camera.getZ() < self.ralph.getZ() + 1 or self.camera.getZ() > self.ralph.getZ() + 1:
                self.camera.setZ(self.ralph.getZ() + 1)

        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.
        self.camera.lookAt(self.floater)


        entries = list(self.orbCollisionHandler.getEntries())
        if(len(entries) > 0):
            #self.lightpivot.reparentTo(NodePath())
            orbCollected = False
            self.cameraCollided = False
            self.ralphSpeed = 65
            for entry in self.orbCollisionHandler.getEntries():
                #print(entry)
                fromColNp = entry.getFromNodePath()
                toColNp = entry.getIntoNodePath()
                if fromColNp.getName() == "orbColPath" and toColNp.getName() == "ralphColNode":
                    if orbCollected == False:
                        fromColNp.getParent().reparentTo(NodePath())
                        self.orbTxt.destroy()
                        self.numOrbs += 1
                        str1 = "Orbs: " + str(self.numOrbs)
                        self.orbTxt = utilsKristina2.addInstructions(.18, str1)
                        orbCollected = True
                elif toColNp.getName() == "orbColPath" and fromColNp.getName() == "ralphColNode":
                    if orbCollected == False:
                        toColNp.getParent().reparentTo(NodePath())
                        self.orbTxt.destroy()
                        self.numOrbs += 1
                        str1 = "Orbs: " + str(self.numOrbs)
                        self.orbTxt = utilsKristina2.addInstructions(.18, str1)
                        orbCollected = True
                elif toColNp.getName() == "ralphOrbColPath" and (fromColNp.getName()[:-1] == "chrisColPath" or fromColNp.getName()[:-2] == "chrisColPath"):
                    toColNp.getParent().setZ(20)
                    for chriss in self.chrisList:
                        if chriss.chrisColName == fromColNp.getName():
                            chris = chriss
                            break

                    chris.chrisHealth = chris.chrisHealth - 1
                    chris.chris.setColor(1,0,0,1)
                    chris.chrisHit = True
                    chris.chrisRedTime = globalClock.getFrameTime()
                    #print chris.chrisRedTime
                    if chris.chrisHealth < 0:
                        fromColNp.getParent().removeNode()
                        chris.chrisAlive = False
                        chris.chrisShot.setZ(26)
                elif (toColNp.getName()[:-1] == "chrisColPath" or toColNp.getName()[:-2] == "chrisColPath") and fromColNp.getName() == "ralphOrbColPath":
                    fromColNp.getParent().setZ(20)
                    for chriss in self.chrisList:
                        if chriss.chrisColName == toColNp.getName():
                            chris = chriss
                            break

                    chris.chrisHealth = chris.chrisHealth - 1
                    chris.chris.setColor(1,0,0,1)
                    chris.chrisHit = True
                    chris.chrisRedTime = globalClock.getFrameTime()
                    #print chris.chrisRedTime
                    if chris.chrisHealth < 0:
                        toColNp.getParent().removeNode()
                        chris.chrisAlive = False
                        chris.chrisShot.setZ(26)
                elif toColNp.getName() == "enemyOrbColPath" and fromColNp.getName() == "ralphColNode":
                    toColNp.getParent().setZ(26)
                    self.healthTxt.destroy()
                    self.healthCount -= 3
                    str1 = "Health: " + str(self.healthCount)
                    self.healthTxt = utilsKristina2.addInstructions(.06, str1)
                    self.ralphHit = True
                    self.ralph.setColor((1,0,0,1))
                    self.ralphRedTime = globalClock.getFrameTime()
                    if self.healthCount <=0:
                        sys.exit()
                elif toColNp.getName() == "ralphColNode" and fromColNp.getName() == "enemyOrbColPath":
                    fromColNp.getParent().setZ(26)
                    self.healthTxt.destroy()
                    self.healthCount -= 3
                    str1 = "Health: " + str(self.healthCount)
                    self.healthTxt = utilsKristina2.addInstructions(.06, str1)
                    self.ralphHit = True
                    self.ralph.setColor((1,0,0,1))
                    self.ralphRedTime = globalClock.getFrameTime()
                    if self.healthCount <=0:
                        sys.exit()
                elif fromColNp.getName() == "ralphOrbColPath" and toColNp.getName() == "allinclusive":
                    fromColNp.getParent().setZ(50)
                elif toColNp.getName() == "ralphOrbColPath" and fromColNp.getName() == "allinclusive":
                    toColNp.getParent().setZ(50)
                elif fromColNp.getName() == "enemyOrbWallCheck" and toColNp.getName() == "allinclusive":
                    fromColNp.getParent().setZ(50)
                    #print toColNp.getName()
                elif toColNp.getName() == "enemyOrbWallCheck" and fromColNp.getName() == "allinclusive":
                    toColNp.getParent().setZ(50)
                    #print fromColNp.getName()

                elif fromColNp.getName() == "ralphWallCheck" and toColNp.getName() == "allinclusive":
                    #node = NodePath("tmp")
                    #node.setHpr(self.ralph.getHpr())
                    #vec = render.getRelativeVector(node,(0,-1,0))
                    #self.ralph.setPos(self.ralph.getPos()-vec)
                    #fromColNp.getParent().setZ(26)
                    self.ralphSpeed = 25
                elif toColNp.getName() == "ralphWallCheck" and fromColNp.getName() == "allinclusive":
                    #node = NodePath("tmp")
                    #node.setHpr(self.ralph.getHpr())
                    #vec = render.getRelativeVector(node,(0,-1,0))
                    #self.ralph.setPos(self.ralph.getPos()-vec)
                    #print "wtf"
                    #toColNp.getParent().setZ(26)
                    self.ralphSpeed = 25
                elif fromColNp.getName() == "ralphWallCheck2" and toColNp.getName() == "allinclusive":
                    #node = NodePath("tmp")
                    #node.setHpr(self.ralph.getHpr())
                    #vec = render.getRelativeVector(node,(0,1,0))
                    #self.ralph.setPos(self.ralph.getPos()-vec)
                    #fromColNp.getParent().setZ(26)
                    self.ralphSpeed = 25
                elif toColNp.getName() == "ralphWallCheck2" and fromColNp.getName() == "allinclusive":
                    #node = NodePath("tmp")
                    #node.setHpr(self.ralph.getHpr())
                    #vec = render.getRelativeVector(node,(0,1,0))
                    #self.ralph.setPos(self.ralph.getPos()-vec)
                    #self.camera.setPos(self.ralph.getPos())
                    #self.cameraCollided = True
                    self.ralphSpeed = 25
                elif fromColNp.getName() == "ralphWallCheck3" and toColNp.getName() == "allinclusive":
                    #node = NodePath("tmp")
                    #node.setHpr(self.ralph.getHpr())
                    #vec = render.getRelativeVector(node,(-1,0,0))
                    #self.ralph.setPos(self.ralph.getPos()-vec)
                    #fromColNp.getParent().setZ(26)
                    self.ralphSpeed = 25
                    print "3"
                elif toColNp.getName() == "ralphWallCheck3" and fromColNp.getName() == "allinclusive":
                    #node = NodePath("tmp")
                    #node.setHpr(self.ralph.getHpr())
                    #vec = render.getRelativeVector(node,(-1,0,0))
                    #self.ralph.setPos(self.ralph.getPos()-vec)
                    #self.camera.setPos(self.ralph.getPos())
                    #self.cameraCollided = True
                    self.ralphSpeed = 25
                    print "3"
                elif fromColNp.getName() == "ralphWallCheck4" and toColNp.getName() == "allinclusive":
                    #node = NodePath("tmp")
                    #node.setHpr(self.ralph.getHpr())
                    #vec = render.getRelativeVector(node,(1,0,0))
                    #self.ralph.setPos(self.ralph.getPos()-vec)
                    #fromColNp.getParent().setZ(26)
                    self.ralphSpeed = 25
                    print "4"
                elif toColNp.getName() == "ralphWallCheck4" and fromColNp.getName() == "allinclusive":
                    #node = NodePath("tmp")
                    #node.setHpr(self.ralph.getHpr())
                    #vec = render.getRelativeVector(node,(1,0,0))
                    #self.ralph.setPos(self.ralph.getPos()-vec)
                    #self.camera.setPos(self.ralph.getPos())
                    #self.cameraCollided = True
                    self.ralphSpeed = 25
                    print "4"





        return task.cont
class RoamingRalphDemo(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)
	#self.setupCD()

        # Set the background color to black
       # self.win.setClearColor((0.6, 0.6, 1.0, 1.0))
#	self.fog = Fog('myFog')
#	self.fog.setColor(0, 0, 0)
#	self.fog.setExpDensity(.05)
#	render.setFog(self.fog)	
       # This is used to store which keys are currently pressed.
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0, "c":0, "back":0, "space":0}

        # Post the instructions
        #self.title = addTitle(
         #   "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.06, "[ESC]: Quit")
        self.inst2 = addInstructions(0.12, "[Left Arrow]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.18, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.24, "[Up Arrow]: Run Ralph Forward")
        #self.inst6 = addInstructions(0.30, "[A]: Rotate Camera Left")
        #self.inst7 = addInstructions(0.36, "[S]: Rotate Camera Right")


        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        #self.environ.reparentTo(render)

        self.room = loader.loadModel("models/room2.egg")
        self.room.reparentTo(render)
        #self.room.setScale(.1)
        self.room.setPos(0,0,-5)
        self.room.setShaderAuto()
	#self.room.writeBamFile("myRoom1.bam")
	#self.room.setColor(1,.3,.3,1)

	self.room2 = loader.loadModel("models/abstractroom2")
        self.room2.reparentTo(render)
        self.room2.setScale(.1)
        self.room2.setPos(-12,0,0)

        # Create the main character, Ralph

        #ralphStartPos = LVecBase3F(0,0,0) #self.room.find("**/start_point").getPos()

        self.ralph = Actor("models/ralph",
                           {"run": "models/ralph-run",
                            "walk": "models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(0,0,0)
	#cs = CollisionSphere(0, 0, 0, 1)
	#cnodePath = self.ralph.attachNewNode(CollisionNode('cnode'))
	#cnodePath.node().addSolid(cs)
	#cnodePath.node().setPos(0,0,0)
	#cnodePath.show()	
	
	self.gianteye = loader.loadModel("models/gianteye")
	self.gianteye.reparentTo(render)
	self.gianteye.setScale(.1)
	self.gianteye.setPos(10,10,0)	
	
	#self.bluefinal = loader.loadModel("models/chrysalis")
	#self.bluefinal.reparentTo(render)
	#self.bluefinal.setScale(.1)
	#self.bluefinal.setPos(7,7,0)	
	
	#self.blue = loader.loadModel("models/blue1")
	#self.blue.reparentTo(render)
	#self.blue.setScale(.1)
	#self.blue.setPos(10,5,0)
	
	self.chik = loader.loadModel("models/chik")
	self.chik.reparentTo(render)
	self.chik.setScale(.1)
	self.chik.setPos(3,13,0)	

        self.pawn = loader.loadModel("pawn")
        self.pawn.reparentTo(render)
        self.pawn.setPos(0,0,0)

        self.shot = loader.loadModel("models/icosphere.egg")
        self.shot.reparentTo(render)
        self.shot.setScale(.5)
        self.shot.setPos(0,0,1)
        self.shot.setColor(1,.3,.3,1)

        self.myShot = loader.loadModel("models/icosphere.egg")
        #self.myShot.reparentTo(render)
        self.myShot.setScale(.1)
        self.myShot.setPos(0,0,1)
        self.myShotVec = LVector3(0,0,0)

        self.lightpivot3 = render.attachNewNode("lightpivot3")
        self.lightpivot3.setPos(0, 0, 0)
        self.lightpivot3.hprInterval(10, LPoint3(0, 0, 0)).loop()
        plight3 = PointLight('plight2')
        plight3.setColor((0, .3,0, 1))
        plight3.setAttenuation(LVector3(0.7, 0.05, 0))
        plnp3 = self.lightpivot3.attachNewNode(plight3)
        plnp3.setPos(0, 0, 0)
        self.room2.setLight(plnp3)
        self.room.setLight(plnp3)
        sphere3 = loader.loadModel("models/icosphere")
        sphere3.reparentTo(plnp3)
        sphere3.setScale(0.1)
        sphere3.setColor((0,1,0,1))

        # Create a floater object, which floats 2 units above ralph.  We
        # use this as a target for the camera to look at.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(self.ralph)
        self.floater.setZ(8.0)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("arrow_down", self.setKey, ["back", True])
        self.accept("a", self.setKey, ["cam-left", True])
        self.accept("s", self.setKey, ["cam-right", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("arrow_down-up", self.setKey, ["back", False])
        self.accept("a-up", self.setKey, ["cam-left", False])
        self.accept("s-up", self.setKey, ["cam-right", False])

        self.accept("space", self.setKey, ["space", True])
        self.accept("space-up", self.setKey, ["space", False])

        self.accept("c",self.setKey,["c",True])
        self.accept("c-up",self.setKey,["c",False])

        taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False
        self.jumping = False
        self.vz = 0

        # Set up the camera
        self.disableMouse()
        self.camera.setPos(self.ralph.getX(), self.ralph.getY() + 7, 3)
        self.camLens.setFov(60)

        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above ralph's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.

        def setupCollision(self):
	    cs = CollisionSphere(0,0,2,1)
	    cnodePath = self.ralph.attachNewNode(CollisionNode('cnode'))
	    cnodePath.node().addSolid(cs)
	    cnodePath.show()
	    #for o in self.OBS:
		#ct = CollisionTube(0,0,0, 0,0,1, 0.5)
		#cn = o.attachNewNode(CollisionNode('ocnode'))
		#cn.node().addSolid(ct)
		#cn.show()
	    eyecs = CollisionSphere(0,0,4,5)
	    cnodePath = self.gianteye.attachNewNode(CollisionNode('cnode'))
	    cnodePath.node().addSolid(eyecs)
	    cnodePath.show()	 
	    eyecs = CollisionSphere(0,0,4,2)
	    cnodePath = self.chik.attachNewNode(CollisionNode('cnode'))
	    cnodePath.node().addSolid(eyecs)
	    cnodePath.show()	    
    
	    pusher = CollisionHandlerPusher()
	    pusher.addCollider(cnodePath, self.player)
	    self.cTrav = CollisionTraverser()
	    self.cTrav.add_collider(cnodePath,pusher)
	    self.cTrav.showCollisions(render)
	self.walls = self.room2.find("**/wall_collide")
	#self.walls.node().setIntoCollideMask(BitMask32.bit(0))

        self.cTrav = CollisionTraverser()
        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 9)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.ralphGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()

        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)	

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 9)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.camGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.camGroundColNp = self.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()

        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        self.sphere = CollisionSphere(0,0,4,2)
        self.sphere2 = CollisionSphere(0,0,2,2)
        self.cnodePath = self.ralph.attachNewNode((CollisionNode('cnode')))
        self.cnodePath.node().addSolid(self.sphere)
        self.cnodePath.node().addSolid(self.sphere2)
        self.cnodePath.show()
        self.pusher = CollisionHandlerPusher()
        self.pusher.addCollider(self.cnodePath, self.ralph)
        self.cTrav.add_collider(self.cnodePath, self.pusher)
	
	self.eyecs = CollisionSphere(0,0,22,25)
	self.cnodePath1 = self.gianteye.attachNewNode(CollisionNode('cnode'))
	self.cnodePath1.node().addSolid(self.eyecs)
	self.cnodePath1.show()	
	self.pusher1 = CollisionHandlerPusher()
	self.pusher1.addCollider(self.cnodePath1, self.gianteye)
	self.cTrav.add_collider(self.cnodePath1, self.pusher1)	
	self.cTrav.showCollisions(render)
	
	self.eyeGroundRay = CollisionRay()
        self.eyeGroundRay.setOrigin(0, 0, 9)
        self.eyeGroundRay.setDirection(0, 0, -1)
        self.eyeGroundCol = CollisionNode('eyeRay')
        self.eyeGroundCol.addSolid(self.eyeGroundRay)
        self.eyeGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.eyeGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.eyeGroundColNp = self.gianteye.attachNewNode(self.eyeGroundCol)
        self.eyeGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.eyeGroundColNp, self.eyeGroundHandler)		

	self.chikcs = CollisionSphere(0,0,11,20)
	self.cnodePath2 = self.chik.attachNewNode(CollisionNode('cnode'))
	self.cnodePath2.node().addSolid(self.chikcs)
	self.cnodePath2.show()
	self.pusher2 = CollisionHandlerPusher()
	self.pusher2.addCollider(self.cnodePath, self.chik)
	self.cTrav.add_collider(self.cnodePath, self.pusher2)	
	self.cTrav.showCollisions(render)	
	
	self.chikGroundRay = CollisionRay()
        self.chikGroundRay.setOrigin(0, 0, 9)
        self.chikGroundRay.setDirection(0, 0, -1)
        self.chikGroundCol = CollisionNode('chikRay')
        self.chikGroundCol.addSolid(self.chikGroundRay)
        self.chikGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.chikGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.chikGroundColNp = self.chik.attachNewNode(self.chikGroundCol)
        self.chikGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.chikGroundColNp, self.chikGroundHandler)	
	

        # Uncomment this line to see the collision rays
        self.ralphGroundColNp.show()
        self.camGroundColNp.show()
	#self.ralphroom1ColNp.show()

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #self.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.3, .3, .3, .4))
        ambientLight2 = AmbientLight("ambientLight2")
        ambientLight2.setColor((1, 1, 1, 10))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((0, 0, -2))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        #self.environ.setLight(self.environ.attachNewNode(ambientLight2))
        render.setLight(render.attachNewNode(directionalLight))

        # Add a light to the scene.
        self.lightpivot = render.attachNewNode("lightpivot")
        self.lightpivot.setPos(0, 0, 1.6)
        self.lightpivot.hprInterval(20, LPoint3(360, 0, 0)).loop()
        plight = PointLight('plight')
        plight.setColor((.7, .3, 0, 1))
        plight.setAttenuation(LVector3(0.7, 0.05, 0))
        plnp = self.lightpivot.attachNewNode(plight)
        plnp.setPos(5, 0, 0)
        self.room.setLight(plnp)
        sphere = loader.loadModel("models/icosphere")
        sphere.reparentTo(plnp)
        sphere.setScale(0.1)
        sphere.setColor((1,1,0,1))

        self.lightpivot2 = render.attachNewNode("lightpivot")
        self.lightpivot2.setPos(-16, 0, 1.6)
        self.lightpivot2.hprInterval(20, LPoint3(360, 0, 0)).loop()
        plight2 = PointLight('plight2')
        plight2.setColor((0, .4,.8, 1))
        plight2.setAttenuation(LVector3(0.7, 0.05, 0))
        plnp2 = self.lightpivot2.attachNewNode(plight2)
        plnp2.setPos(5, 0, 0)
        self.room2.setLight(plnp2)
        sphere2 = loader.loadModel("models/icosphere")
        sphere2.reparentTo(plnp2)
        sphere2.setScale(0.2)
        sphere2.setColor((0,0,1,1))

        self.vec = LVector3(0,1,0) 
	
    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):

        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        if self.keyMap["cam-left"]:
            self.camera.setZ(self.camera, -20 * dt)
        if self.keyMap["cam-right"]:
            self.camera.setZ(self.camera, +20 * dt)

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if self.keyMap["left"]:
            self.ralph.setH(self.ralph.getH() + 150 * dt)
            #self.floater.setH(self.floater.getH() + 300 * dt)
            self.camera.setX(self.camera, +15.5 * dt)
        if self.keyMap["right"]:
            self.ralph.setH(self.ralph.getH() - 150 * dt)
            self.camera.setX(self.camera, -15.5 * dt)
        if self.keyMap["forward"]:
            self.ralph.setY(self.ralph, -35 * dt)
        if self.keyMap["back"]:
            self.ralph.setY(self.ralph, +35 * dt)
        if self.keyMap["c"]:
            if self.jumping is False:
            #self.ralph.setH(self.ralph.getH() + 300 * dt)
            #self.ralph.setZ(self.ralph.getZ() + 100 * dt)
                self.jumping = True
                self.vz = 7

        if self.keyMap["space"]:
            self.lightpivot3.setPos(self.ralph.getPos())
            self.lightpivot3.setZ(self.ralph.getZ() + .5)
            self.lightpivot3.setX(self.ralph.getX() - .25)
            #self.myShot.setHpr(self.ralph.getHpr())
            #parent
            node = NodePath("tmp")
            node.setHpr(self.ralph.getHpr())
            vec = render.getRelativeVector(node,(0,-1,0))
            self.myShotVec = vec

        self.lightpivot3.setPos(self.lightpivot3.getPos() + self.myShotVec * dt * 15 )

        if self.jumping is True:
            self.vz = self.vz - 16* dt
            self.ralph.setZ(self.ralph.getZ() + self.vz * dt )
            entries = list(self.ralphGroundHandler.getEntries())
            entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())
            if len(entries) > 0 :
                if self.ralph.getZ() < 0:#entries[0].getSurfacePoint(render).getZ():
                    #self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
                    self.ralph.setZ(0)
                    self.jumping = False
        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"] or self.keyMap["c"] or self.keyMap["forward"] or self.keyMap["back"]:
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True


        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        node = NodePath("tmp")
        node.setHpr(self.ralph.getHpr())
        vec = render.getRelativeVector(node,(1,0,0))

        #self.ralph.setPos(self.ralph.getPos() + vec * dt * 20)

        node = NodePath("tmp")
        #self.pawn.getH()
        node.setHpr(self.pawn.getHpr())
        vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))
        self.shot.setPos(self.shot.getPos() + self.vec * dt * 10 )
        if self.shot.getY() < -15 or self.shot.getY() > 15 or self.shot.getX() < -15 or self.shot.getX() > 15:
            self.shot.setPos(self.pawn.getPos() + (0,0,0))
            self.vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))
            self.vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0))

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - self.camera.getPos()
        #camvec.setZ(self.camera.getZ())
        camdist = camvec.length()
        x = self.camera.getZ()
        camvec.normalize()
        if camdist > 6.0:
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 6))
            camdist = 10.0
            #self.camera.setZ(self.camera, x)
        if camdist < 6.0:
            self.camera.setPos(self.camera.getPos() - camvec * (6 - camdist))
            camdist = 5.0
            #self.camera.setZ(self.camera, x)

        # Normally, we would have to call traverse() to check for collisions.
        # However, the class ShowBase that we inherit from has a task to do
        # this for us, if we assign a CollisionTraverser to self.cTrav.
        #self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = list(self.ralphGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())
        if self.jumping == False:
            if len(entries) > 0:# and entries[0].getIntoNode().getName() == "terrain":
                #self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
                pass
            else:
                self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.

        entries = list(self.camGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        #if len(entries) > 0 and entries[0].getIntoNode().getName() == "ground":
            #self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.5)
        if self.camera.getZ() < self.ralph.getZ() + 1 or self.camera.getZ() > self.ralph.getZ() + 1:
            self.camera.setZ(self.ralph.getZ() + 1)

        #self.camera.setZ(self.ralph.getZ() + 1.5)
        #self.camera.setP(self.camera, 130)

        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.
        self.camera.lookAt(self.floater)

        return task.cont
Example #20
0
class Player:

    STATE_IDLE = "Idle"
    STATE_WALK = "Walk"
    STATE_RUN = "Run"
    STATE_JUMP = "Jump"
    STATE_RUNJUMP = "RunJump"
    STATE_FALL = "Fall"
    STATE_DUCK = "Duck"
    STATE_UN_DUCK = "UnDuck"
    STATE_FLOAT = "Float"
    STATE_SWIM = "Swim"
    SUB_STATE_GRAB = "Grab"

    JUMP_ACCEL = 3.5
    FALL_ACCEL = -9.81

    TERRAIN_NONE = 0
    TERRAIN_GROUND = 1
    TERRAIN_WATER = 2
    TERRAIN_AIR = 3

    DUCK_FRAME_COUNT = 0
    DUCK_FRAME_MID = 0

    SUNK_CUTOFF = -0.9

    def __init__(self, base):
        self.base = base
        self.keyState = {
            "WalkFw": False,
            "WalkBw": False,
            "Run": False,
            "RotateL": False,
            "RotateR": False,
            "Jump": False,
            "Duck": False
        }
        self.isKeyDown = self.base.mouseWatcherNode.isButtonDown
        self.state = Player.STATE_IDLE
        self.sub_state = None
        self.walkDir = 0
        self.rotationDir = 0
        self.zVelocity = 0
        self.zOffset = None
        self.jumpHeight = None
        self.terrainZone = Player.TERRAIN_NONE
        self.terrainSurfZ = None
        self.waterDepth = 0
        self.collidedObjects = list()
        # actor
        anims = {
            "idle": "models/player-idle",
            "walk": "models/player-walk",
            "run": "models/player-run",
            "jump": "models/player-jump",
            "duck": "models/player-duck",
            "float": "models/player-float",
            "swim": "models/player-swim",
            "grab": "models/player-grab"
        }
        self.actor = Actor("models/player", anims)
        self.actor.reparentTo(self.base.render)
        self.actor.setH(200)
        log.debug("actor tight bounds is %s" %
                  str(self.actor.getTightBounds()))
        # animation info
        Player.DUCK_FRAME_COUNT = self.actor.getNumFrames("duck")
        Player.DUCK_FRAME_MID = int(Player.DUCK_FRAME_COUNT / 2)
        # camara point
        self.camNode = NodePath("camNode")
        self.camNode.reparentTo(self.actor)
        self.camNode.setPos(0, 0, 1)
        # collision
        #   ray
        collRay = CollisionRay(0, 0, 1.5, 0, 0, -1)
        collRayN = CollisionNode("playerCollRay")
        collRayN.addSolid(collRay)
        collRayN.setFromCollideMask(1)
        collRayN.setIntoCollideMask(CollideMask.allOff())
        collRayNP = self.actor.attachNewNode(collRayN)
        self.collQRay = CollisionHandlerQueue()
        self.base.cTrav.addCollider(collRayNP, self.collQRay)
        #   sphere mask 2
        collSphere2 = CollisionSphere(0, 0, 0.5, 0.25)
        collSphere2N = CollisionNode("playerCollSphere2")
        collSphere2N.addSolid(collSphere2)
        collSphere2N.setFromCollideMask(2)
        collSphere2N.setIntoCollideMask(CollideMask.allOff())
        self.collSphere2NP = self.actor.attachNewNode(collSphere2N)
        self.collPSphere = CollisionHandlerPusher()
        self.collPSphere.addCollider(self.collSphere2NP, self.actor)
        self.base.cTrav.addCollider(self.collSphere2NP, self.collPSphere)
        # key events
        self.base.accept("i", self.dump_info)
        # task
        self.base.taskMgr.add(self.update, "playerUpdateTask")

    def defineKeys(self):
        for k in self.keyState.keys():
            self.keyState[k] = False
        if self.isKeyDown(KeyboardButton.up()):
            self.keyState["WalkFw"] = True
        if self.isKeyDown(KeyboardButton.down()):
            self.keyState["WalkBw"] = True
        if self.isKeyDown(KeyboardButton.left()):
            self.keyState["RotateL"] = True
        if self.isKeyDown(KeyboardButton.right()):
            self.keyState["RotateR"] = True
        if self.isKeyDown(KeyboardButton.shift()):
            self.keyState["Run"] = True
        if self.isKeyDown(KeyboardButton.space()):
            self.keyState["Jump"] = True
        if self.isKeyDown(KeyboardButton.asciiKey("d")):
            self.keyState["Duck"] = True

    def defineState(self):
        #
        newState = self.state
        # keys states
        ks = self.keyState
        # state force
        if self.zOffset > 0.2 and self.state != Player.STATE_FALL:
            newState = Player.STATE_FALL
        # from Idle -> Walk, Jump
        if self.state == Player.STATE_IDLE:
            # Walk
            if ks["WalkFw"] or ks["WalkBw"] or ks["RotateL"] or ks["RotateR"]:
                newState = Player.STATE_WALK
            elif ks["Jump"]:
                newState = Player.STATE_JUMP
            elif ks["Duck"]:
                newState = Player.STATE_DUCK
        # from Walk, Run -> Walk, Run, Idle; from Run -> Jump
        elif self.state == Player.STATE_WALK or self.state == Player.STATE_RUN:
            if ks["Run"] and self.state != Player.STATE_RUN and self.terrainZone != Player.TERRAIN_WATER:
                newState = Player.STATE_RUN
            elif not ks["Run"] and self.state == Player.STATE_RUN:
                newState = Player.STATE_WALK
            if ks["WalkFw"]:
                self.walkDir = -1
            elif ks["WalkBw"]:
                self.walkDir = 1
            elif not ks["WalkFw"] and not ks["WalkBw"]:
                self.walkDir = 0
            if ks["RotateL"]:
                self.rotationDir = 1
            elif ks["RotateR"]:
                self.rotationDir = -1
            elif not ks["RotateL"] and not ks["RotateR"]:
                self.rotationDir = 0
            if ks["Jump"]:
                newState = Player.STATE_RUNJUMP
            if self.walkDir == 0 and self.rotationDir == 0:
                newState = Player.STATE_IDLE
        # from Jump -> Fall
        elif self.state == Player.STATE_JUMP or self.state == Player.STATE_RUNJUMP:
            if self.zVelocity > 0:
                newState = Player.STATE_FALL
        # from Fall -> Idle
        elif self.state == Player.STATE_FALL:
            if self.zOffset <= 0:
                newState = Player.STATE_IDLE
                self.jumpHeight = None
                self.zVelocity = 0
                self.walkDir = 0
        # from Duck -> UnDuck
        elif self.state == Player.STATE_DUCK:
            if not ks["Duck"]:
                newState = Player.STATE_UN_DUCK
        # from UnDuck -> Idle
        elif self.state == Player.STATE_UN_DUCK:
            if not self.actor.getCurrentAnim() == "duck":
                newState = Player.STATE_IDLE
        return newState

    def processState(self, dt):
        # terrain sdjustment
        if self.zOffset <= 0.2 and not self.state == Player.STATE_FALL:
            self.actor.setZ(self.terrainSurfZ)
        # idle
        if self.state == Player.STATE_IDLE:
            self.collSphere2NP.setZ(0)
        # walk
        if self.walkDir != 0:
            if self.zVelocity == 0:
                speed = 3.6 if self.state == Player.STATE_RUN else 2.4
            else:
                speed = 3.2
            if self.terrainZone == Player.TERRAIN_WATER:
                speed *= 0.5
            self.actor.setY(self.actor, speed * self.walkDir * dt)
        if self.rotationDir != 0:
            self.actor.setH(self.actor.getH() + 3.5 * self.rotationDir)
        # jump
        if self.state == Player.STATE_JUMP or self.state == Player.STATE_RUNJUMP:
            self.zVelocity = Player.JUMP_ACCEL
            log.debug("jump start at v=%f" % self.zVelocity)
            if self.state == Player.STATE_RUNJUMP:
                self.walkDir = -1
        # fall
        if self.state == Player.STATE_FALL:
            dZ = self.zVelocity * dt
            dV = Player.FALL_ACCEL * dt
            curZ = self.actor.getZ()
            newZ = curZ + dZ
            if self.jumpHeight == None and newZ < curZ:
                self.jumpHeight = self.zOffset
                log.debug("jump height=%f" % self.jumpHeight)
            log.debug(
                "falling... dt=%(dt)f getZ=%(getZ)f v=%(v)f dZ=%(dZ)f newZ=%(newZ)f dV=%(dV)f zOffset=%(zOff)f"
                % {
                    "dt": dt,
                    "getZ": self.actor.getZ(),
                    "v": self.zVelocity,
                    "dZ": dZ,
                    "newZ": newZ,
                    "dV": dV,
                    "zOff": self.zOffset
                })
            if newZ < self.terrainSurfZ: newZ = self.terrainSurfZ
            self.actor.setZ(newZ)
            self.zVelocity += dV
        # duck
        if self.state == Player.STATE_DUCK:
            if self.actor.getCurrentAnim() == "duck":
                collSphrZ = (self.actor.getCurrentFrame("duck") /
                             Player.DUCK_FRAME_MID) * 0.25
                self.collSphere2NP.setZ(-collSphrZ)

    def processTerrainRelation(
            self):  # -> [terrainZone, terrainSurfZ, zOffset, waterDepth]
        collEntries = self.collQRay.getEntries()
        newZone = None
        #
        if len(collEntries) == 0:
            #log.error("out of terrain, pos=%s"%str(self.actor.getPos()))
            newZone = Player.TERRAIN_NONE
            if newZone != self.terrainZone:
                self.onTerrainZoneChanged(Player.TERRAIN_NONE)
            self.terrainZone = newZone
            return Player.TERRAIN_NONE, 0, 0, 0
        #
        newZone = Player.TERRAIN_NONE
        gndZ, wtrZ = -1000, -1000
        waterDepth = 0
        for entry in collEntries:
            eName = entry.getIntoNodePath().getName()
            eZ = entry.getSurfacePoint(self.base.render).getZ()
            if eName.startswith("Water"):
                wtrZ = eZ
                if wtrZ > gndZ:
                    newZone = Player.TERRAIN_WATER
            else:
                if eZ > gndZ: gndZ = eZ
                if gndZ > wtrZ:
                    newZone = Player.TERRAIN_GROUND
        if newZone == Player.TERRAIN_WATER:
            waterDepth = gndZ - wtrZ
            #log.debug("water depth is %f"%waterDepth)
        zOffset = self.actor.getZ() - gndZ
        return newZone, gndZ, zOffset, waterDepth

    def onTerrainZoneChanged(self, zone):
        log.debug("terrain zone chaged to: %i" % zone)

    def onStateChanged(self, newState):
        curState = self.state
        log.debug("state change %s -> %s" % (str(curState), str(newState)))
        #self.actor.stop()
        if newState == Player.STATE_IDLE:
            self.actor.loop("idle")
        elif newState == Player.STATE_WALK:
            self.actor.setPlayRate(4.0, "walk")
            self.actor.loop("walk")
        elif newState == Player.STATE_RUN:
            self.actor.loop("run")
        elif newState == Player.STATE_JUMP or newState == Player.STATE_RUNJUMP:
            self.actor.setPlayRate(1.4, "jump")
            self.actor.play("jump", fromFrame=20, toFrame=59)
        elif newState == Player.STATE_DUCK:
            self.actor.play("duck", fromFrame=0, toFrame=Player.DUCK_FRAME_MID)
        elif newState == Player.STATE_UN_DUCK:
            initFrame = Player.DUCK_FRAME_MID
            if self.actor.getCurrentAnim() == "duck":
                initFrame = Player.DUCK_FRAME_COUNT - self.actor.getCurrentFrame(
                    "duck")
            self.actor.stop()
            self.actor.play("duck",
                            fromFrame=initFrame,
                            toFrame=Player.DUCK_FRAME_COUNT)

    def updateCollidedObjectsList(self):
        pass

    def update(self, task):
        # clock
        dt = self.base.taskMgr.globalClock.getDt()
        # keys
        self.defineKeys()
        # terrain relation
        newZone, self.terrainSurfZ, self.zOffset, self.waterDepth = self.processTerrainRelation(
        )
        if newZone != self.terrainZone:
            self.terrainZone = newZone
            self.onTerrainZoneChanged(self.terrainZone)
        # obstacles relation
        self.updateCollidedObjectsList()
        # state
        newState = self.defineState()
        if self.state != newState:
            self.onStateChanged(newState)
            self.state = newState
        self.processState(dt)
        # move
        return task.cont

    def dump_info(self):
        info = "position: %s\n" % str(self.actor.getPos())
        info += "hpr: %s\n" % str(self.actor.getHpr())
        info += "state: %s; sub_state: %s\n" % (str(
            self.state), str(self.sub_state))
        info += "terrainZone: %s\n" % str(self.terrainZone)
        info += "terrainSurfZ: %s\n" % str(self.terrainSurfZ)
        info += "zOffset: %s\n" % str(self.zOffset)
        log.info("*INFO:\n%s" % info)
Example #21
0
class Demo(ShowBase):

   # stereo = cv2.StereoBM_create(numDisparities=16, blockSize=15)

    def __init__(self, img_size=512, screen_off=True, target_area_radius=5, initial_area_radius=10, keyboard_input=False, random_reset_around_target=False, test=False):
        logging.info('random_reset_around_target :%s',
                     random_reset_around_target)
        self.random_reset_around_target = random_reset_around_target
        self.keyboard_input = keyboard_input
        # Configure the parallax mapping settings (these are just the defaults)
        self.img_size = img_size
        self.initial_area_radius = initial_area_radius
        self.target_area_radius = target_area_radius
        loadPrcFileData("", "side-by-side-stereo 1")
        if test:
            loadPrcFileData("", "load-display p3tinydisplay")
        loadPrcFileData("", "transform-cache false")
        loadPrcFileData("", "audio-library-name null")  # Prevent ALSA errors
        loadPrcFileData("", "win-size %d %d" % (2 * img_size, img_size))
        loadPrcFileData("", "parallax-mapping-samples 3\n"
                            "parallax-mapping-scale 0.1")

        if screen_off:
            # Spawn an offscreen buffer
            loadPrcFileData("", "window-type offscreen")
        # Initialize the ShowBase class from which we inherit, which will
        # create a window and set up everything we need for rendering into it.
        ShowBase.__init__(self)

        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0}

        # Load the 'abstract room' model.  This is a model of an
        # empty room containing a pillar, a pyramid, and a bunch
        # of exaggeratedly bumpy textures.

        self.room = loader.loadModel("models/abstractroom")
        self.room.reparentTo(render)

        # Create the main character, Ralph

        ghost = BulletGhostNode('Ghost')
        ghostNP = render.attachNewNode(ghost)
      #  self.agent = Actor("models/agent",
      #                     {"run": "models/agent-run",
      #                      "walk": "models/agent-walk"})
        self.agent = ghostNP
        self.agent.reparentTo(render)
#        self.agent.setScale(.2)
        target = BulletGhostNode('target')
        self.navigation_target = render.attachNewNode(target)
        self.navigation_target.reparentTo(render)

        # knghit=Knight((0,0,0),(0.3,.3,.3,1))
        self.pieces = [Piece(self.room) for _ in range(200)]
        ##################################################
        cnodePath = self.room.attachNewNode(CollisionNode('room'))
        plane = CollisionPlane(Plane(Vec3(1, 0, 0), Point3(-60, 0, 0)))  # left
        cnodePath.node().addSolid(plane)
        plane = CollisionPlane(
            Plane(Vec3(-1, 0, 0), Point3(60, 0, 0)))  # right
        cnodePath.node().addSolid(plane)
        plane = CollisionPlane(Plane(Vec3(0, 1, 0), Point3(0, -60, 0)))  # back
        cnodePath.node().addSolid(plane)
        plane = CollisionPlane(
            Plane(Vec3(0, -1, 0), Point3(0, 60, 0)))  # front
        cnodePath.node().addSolid(plane)

        sphere = CollisionSphere(-25, -25, 0, 12.5)
        # tube = CollisionTube(-25, -25,0 , -25, -25, 1, 12.5)
        cnodePath.node().addSolid(sphere)

        box = CollisionBox(Point3(5, 5, 0), Point3(45, 45, 10))
        cnodePath.node().addSolid(box)

      #  cnodePath.show()

        # Make the mouse invisible, turn off normal mouse controls
        self.disableMouse()
        # props = WindowProperties()
        # props.setCursorHidden(True)
        # self.win.requestProperties(props)
        # self.camLens.setFov(60)
        self.camLens.setFov(80)

        # Set the current viewing target
        self.focus = LVector3(55, -55, 20)
        self.heading = 180
        self.pitch = 0
        self.mousex = 0
        self.mousey = 0
        self.last = 0
        self.mousebtn = [0, 0, 0]

        # Start the camera control task:
        # taskMgr.add(self.controlCamera, "camera-task")
        # self.accept("escape", sys.exit, [0])
        # self.accept("enter", self.toggleShader)
        # self.accept("j", self.rotateLight, [-1])
        # self.accept("k", self.rotateLight, [1])
        # self.accept("arrow_left", self.rotateCam, [-1])
        # self.accept("arrow_right", self.rotateCam, [1])

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("a", self.setKey, ["cam-left", True])
        self.accept("s", self.setKey, ["cam-right", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("a-up", self.setKey, ["cam-left", False])
        self.accept("s-up", self.setKey, ["cam-right", False])
        # Add a light to the scene.
        self.lightpivot = render.attachNewNode("lightpivot")
        self.lightpivot.setPos(0, 0, 25)
        self.lightpivot.hprInterval(10, LPoint3(360, 0, 0)).loop()
        plight = PointLight('plight')
        plight.setColor((5, 5, 5, 1))
        plight.setAttenuation(LVector3(0.7, 0.05, 0))
        plnp = self.lightpivot.attachNewNode(plight)
        plnp.setPos(45, 0, 0)
        self.room.setLight(plnp)

        # Add an ambient light
        alight = AmbientLight('alight')
        alight.setColor((0.2, 0.2, 0.2, 1))
        alnp = render.attachNewNode(alight)
        self.room.setLight(alnp)

        # Create a sphere to denote the light
        sphere = loader.loadModel("models/icosphere")
        sphere.reparentTo(plnp)

#         self.cameraModel = self.agent

#        self.win2 = self.openWindow()
#        self.win2.removeAllDisplayRegions()
#        self.dr2 = self.win2.makeDisplayRegion()
#        camNode = Camera('cam')
#        camNP = NodePath(camNode)
#        camNP.reparentTo(self.cameraModel)
#        camNP.setZ(150)
#        camNP.lookAt(self.cameraModel)
#        self.dr2.setCamera(camNP)
#        self.cam2 = camNP  # Camera('cam')p

        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above agent's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.
        self.cTrav = CollisionTraverser()

        cs = CollisionSphere(0, 0, 0, 0.2)
        cnodePath = self.agent.attachNewNode(CollisionNode('agent'))
        cnodePath.node().addSolid(cs)

      #  cnodePath.show()
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(cnodePath, self.ralphGroundHandler)

        cnodePath = self.navigation_target.attachNewNode(
            CollisionNode('target'))
        cnodePath.node().addSolid(CollisionSphere(0, 0, 0, 2))
        self.cTrav.addCollider(cnodePath, self.ralphGroundHandler)

        # Tell Panda that it should generate shaders performing per-pixel
        # lighting for the room.
        self.room.setShaderAuto()

        self.shaderenable = 1

        # tex = self.win.getScreenshot()
        # tex.setFormat(Texture.FDepthComponent)

        tex = Texture()
        self.depthmap = tex
        tex.setFormat(Texture.FDepthComponent)
        altBuffer = self.win.makeTextureBuffer(
            "hello", img_size, img_size, tex, True)
        self.altBuffer = altBuffer
        altCam = self.makeCamera(altBuffer)
        altCam.reparentTo(self.agent)  # altRender)
        altCam.setZ(0.4)
        l = altCam.node().getLens()
        l.setFov(80)
        l.setNear(.1)

        camera.reparentTo(self.agent)
        camera.setZ(0.4)
        l = self.camLens
        # l.setFov(80)
        l.setNear(.1)
        # end init

    def setKey(self, key, value):
        self.keyMap[key] = value

    def step(self, action=(0, 0, 0)):
        h, p, forward = action
        self.agent.setH(self.agent, h)
        self.agent.setP(self.agent, p)
        self.agent.setY(self.agent, forward)
        relative_target_position = self.__get_relative_target_position()
        if not None == self.relative_target_position:
            speed = abs(relative_target_position) - \
                abs(self.relative_target_position)
            assert abs(speed) < 0.02 * 25 * 0.2 * 1.001 * 4
        self.relative_target_position = relative_target_position

        return len(self.get_collision_list()) > 0
        dt = 0.02  # 控制跳帧,这个问题在转移到现实的时候需要考虑,摄影机如果能提供固定的拍摄频率就最好了,
        if len(self.pieces) > 0:
            for _ in range(5):
                rng.choice(self.pieces).step(dt)

    def get_collision_list(self):
        if self.keyboard_input == False:
            f = taskMgr.getAllTasks()[-1].getFunction()
            f(None)
            f = taskMgr.getAllTasks()[2].getFunction()
            f(None)
        else:
            taskMgr.step()
        return (self.ralphGroundHandler.getEntries())
    relative_target_position = None

    def __get_relative_target_position(self):
        from_hpr = self.agent.getHpr()
        h = from_hpr[0] * math.pi / 180

        from_pos = self.agent.getPos()
        from_pos = from_pos[0] + from_pos[1] * 1j

        target_pos = self.navigation_target.getPos()
        target_pos = target_pos[0] + target_pos[1] * 1j

        relative_pos = target_pos - from_pos
        rpos = relative_pos * np.exp(-h * 1j)
        return rpos

    def get_agent_position(self):
        return self.agent.getPos()

    def get_obstacle_positions(self):
        return [piece.knight.getPos() for piece in self.pieces]

    def get_obstacle_radius(self):
        return [piece.radius for piece in self.pieces]

    def get_target_position(self):
        return self.navigation_target.getPos()

    def resetGame(self):

        self.renderFrame()
        img = self.getScreen()

        for p in self.pieces:
            p.putaway()

        self.agent.setPos((20, 20, 1000))
        size = 60

        while True:
            x, y = rng.uniform(-size, size, 2)  # rng.rand() *
            self.navigation_target.setPos((x, y, 0))
            l = self.get_collision_list()
            if len(l) < 1:
                break
        # print(i)
        target_pos = self.navigation_target.getPos()
        target_pos = target_pos[0] + target_pos[1] * 1j

        while True:
            if not self.random_reset_around_target:  # :
                x, y = rng.uniform(-size, size, 2)  # rng.rand
            else:
                while True:
                    pos = (10 + size * math.pi * rng.rand()) * \
                        np.exp(rng.rand() * math.pi * 1j)
                    pos += target_pos
                    if -size < pos.real < size and -size < pos.imag < size:
                        x, y = pos.real, pos.imag
                        break
            self.agent.setPos((x, y, 0))
            l = self.get_collision_list()
            if len(l) < 1:
                break

        self.agent.setH(rng.uniform(0, 360))
        self.relative_target_position = self.__get_relative_target_position()

        for p in self.pieces:
            p.reset(avoids=[(self.agent.getPos(), self.initial_area_radius),
                            (self.navigation_target.getPos(), self.target_area_radius)])
        # print(i)

    def renderFrame(self):
        base.graphicsEngine.renderFrame()

    def getScreen(self):
        #    base.graphicsEngine.renderFrame()
        # self.screenshot(namePrefix=self._screenshot)
        tex = self.win.getScreenshot()
        r = tex.getRamImage()
        l = np.asarray(r)
        x = tex.getXSize()
        y = tex.getYSize()
      #  print((x,y,len(l)))
        assert x * y * 4 == len(l)
        if x * y * 3 == len(l):
            l = l.reshape((y, x, 3))
        elif x * y * 4 == len(l):
            l = l.reshape((y, x, 4))
        elif x * y == len(l):
            l = l.reshape((y, x))
        else:
            a = 1 / 0
        l = np.flipud(l)
        return l

    def getDepthMap(self, p):
        # print(p.dtype)
        # p=p[:,:,:2]
        # img =p# cv2.imread(p, 0)
        img = np.mean(p, axis=2, dtype='uint8')
      #  print(img.shape)
      #  img=p[:,:,3]
      #  print(img.shape)
        # os.remove(p)
        img1 = img[:, :self.img_size]
        img2 = img[:, self.img_size:]
        disparity = self.stereo.compute(img1, img2)

        if rng.rand() < 0.1:
            p = '/dev/shm/z_depthsample%d.jpg'
            p2 = '/dev/shm/z_depthsample%d_.jpg'
            for i in range(50):
                if not os.path.exists(p % i):
                    scipy.misc.imsave(p % i, disparity)
                    scipy.misc.imsave(p2 % i, np.asarray(
                        [img1, img2, disparity]))
                    break

        return disparity, img1, img2

    def getRawImage(self, p):
        img = p  # scipy.misc.imread(p)
        # os.remove(p)
        img1 = img[:, :self.img_size]
        img = np.mean(img1, axis=2)
        return img

    def getRawImageStereo(self, img):
        img = np.mean(img, axis=2)
        img1 = img[:, :self.img_size]
        img2 = img[:, self.img_size:]
        return np.asarray([img1, img2])

    def getDepthMapT(self):
        tex = self.depthmap
        # tex = self.altBuffer.getTexture()
        r = tex.getRamImage()
        s = r.getData()
        i = np.fromstring(s, dtype='float32')
        i = i.reshape((self.img_size, self.img_size))
        i = np.flipud(i)
        return i

    def get1Ddepth(self, dmap):
        i = int(self.img_size * 0.525)  # horizon
        return dmap[i]
Example #22
0
class CollisionChecker(object):
    """
    A fast collision checker that allows maximum 32 collision pairs
    author: weiwei
    date: 20201214osaka
    """
    def __init__(self, name="auto"):
        self.ctrav = CollisionTraverser()
        self.chan = CollisionHandlerQueue()
        self.np = NodePath(name)
        self.bitmask_list = [BitMask32(2**n) for n in range(31)]
        self._bitmask_ext = BitMask32(
            2**31)  # 31 is prepared for cd with external non-active objects
        self.all_cdelements = [
        ]  # a list of cdlnks or cdobjs for quick accessing the cd elements (cdlnks/cdobjs)

    def add_cdlnks(self, jlcobj, lnk_idlist):
        """
        The collision node of the given links will be attached to self.np, but their collision bitmask will be cleared
        When the a robot_s is treated as an obstacle by another robot_s, the IntoCollideMask of its all_cdelements will be
        set to BitMask32(2**31), so that the other robot_s can compare its active_cdelements with the all_cdelements.
        :param jlcobj:
        :param lnk_idlist:
        :return:
        author: weiwei
        date: 20201216toyonaka
        """
        for id in lnk_idlist:
            if jlcobj.lnks[id]['cdprimit_childid'] == -1:  # first time add
                cdnp = jlcobj.lnks[id]['collision_model'].copy_cdnp_to(
                    self.np, clearmask=True)
                self.ctrav.addCollider(cdnp, self.chan)
                self.all_cdelements.append(jlcobj.lnks[id])
                jlcobj.lnks[id]['cdprimit_childid'] = len(
                    self.all_cdelements) - 1
            else:
                raise ValueError("The link is already added!")

    def set_active_cdlnks(self, activelist):
        """
        The specified collision links will be used for collision detection with external obstacles
        :param activelist: essentially a from list like [jlchain.lnk0, jlchain.lnk1...]
                           the correspondent tolist will be set online in cd functions
                           TODO use all elements in self.all_cdnlks if None
        :return:
        author: weiwei
        date: 20201216toyonaka
        """
        for cdlnk in activelist:
            if cdlnk['cdprimit_childid'] == -1:
                raise ValueError(
                    "The link needs to be added to collider using the add_cdlnks function first!"
                )
            cdnp = self.np.getChild(cdlnk['cdprimit_childid'])
            cdnp.node().setFromCollideMask(self._bitmask_ext)

    def set_cdpair(self, fromlist, intolist):
        """
        The given collision pair will be used for self collision detection
        :param fromlist: [[bool, cdprimit_cache], ...]
        :param intolist: [[bool, cdprimit_cache], ...]
        :return:
        author: weiwei
        date: 20201215
        """
        if len(self.bitmask_list) == 0:
            raise ValueError("Too many collision pairs! Maximum: 29")
        allocated_bitmask = self.bitmask_list.pop()
        for cdlnk in fromlist:
            if cdlnk['cdprimit_childid'] == -1:
                raise ValueError(
                    "The link needs to be added to collider using the addjlcobj function first!"
                )
            cdnp = self.np.getChild(cdlnk['cdprimit_childid'])
            current_from_cdmask = cdnp.node().getFromCollideMask()
            new_from_cdmask = current_from_cdmask | allocated_bitmask
            cdnp.node().setFromCollideMask(new_from_cdmask)
        for cdlnk in intolist:
            if cdlnk['cdprimit_childid'] == -1:
                raise ValueError(
                    "The link needs to be added to collider using the addjlcobj function first!"
                )
            cdnp = self.np.getChild(cdlnk['cdprimit_childid'])
            current_into_cdmask = cdnp.node().getIntoCollideMask()
            new_into_cdmask = current_into_cdmask | allocated_bitmask
            cdnp.node().setIntoCollideMask(new_into_cdmask)

    def add_cdobj(self, objcm, rel_pos, rel_rotmat, into_list):
        """
        :return: cdobj_info, a dictionary that mimics a joint link; Besides that, there is an additional 'into_list'
                 key to hold into_list to easily toggle off the bitmasks.
        """
        cdobj_info = {}
        cdobj_info['collision_model'] = objcm  # for reversed lookup
        cdobj_info['gl_pos'] = objcm.get_pos()
        cdobj_info['gl_rotmat'] = objcm.get_rotmat()
        cdobj_info['rel_pos'] = rel_pos
        cdobj_info['rel_rotmat'] = rel_rotmat
        cdobj_info['into_list'] = into_list
        cdnp = objcm.copy_cdnp_to(self.np, clearmask=True)
        cdnp.node().setFromCollideMask(self._bitmask_ext)  # set active
        self.ctrav.addCollider(cdnp, self.chan)
        self.all_cdelements.append(cdobj_info)
        cdobj_info['cdprimit_childid'] = len(self.all_cdelements) - 1
        self.set_cdpair([cdobj_info], into_list)
        return cdobj_info

    def delete_cdobj(self, cdobj_info):
        """
        :param cdobj_info: an lnk-like object generated by self.add_objinhnd
        :param objcm:
        :return:
        """
        self.all_cdelements.remove(cdobj_info)
        cdnp_to_delete = self.np.getChild(cdobj_info['cdprimit_childid'])
        self.ctrav.removeCollider(cdnp_to_delete)
        this_cdmask = cdnp_to_delete.node().getFromCollideMask()
        for cdlnk in cdobj_info['into_list']:
            cdnp = self.np.getChild(cdlnk['cdprimit_childid'])
            current_into_cdmask = cdnp.node().getIntoCollideMask()
            new_into_cdmask = current_into_cdmask & ~this_cdmask
            cdnp.node().setIntoCollideMask(new_into_cdmask)
        cdnp_to_delete.detachNode()
        self.bitmask_list.append(this_cdmask)

    def is_collided(self,
                    obstacle_list=[],
                    otherrobot_list=[],
                    toggle_contact_points=False):
        """
        :param obstacle_list: staticgeometricmodel
        :param otherrobot_list:
        :return:
        """
        for cdelement in self.all_cdelements:
            pos = cdelement['gl_pos']
            rotmat = cdelement['gl_rotmat']
            cdnp = self.np.getChild(cdelement['cdprimit_childid'])
            cdnp.setPosQuat(da.npv3_to_pdv3(pos), da.npmat3_to_pdquat(rotmat))
            # print(da.npv3mat3_to_pdmat4(pos, rotmat))
            # print("From", cdnp.node().getFromCollideMask())
            # print("Into", cdnp.node().getIntoCollideMask())
        # print("xxxx colliders xxxx")
        # for collider in self.ctrav.getColliders():
        #     print(collider.getMat())
        #     print("From", collider.node().getFromCollideMask())
        #     print("Into", collider.node().getIntoCollideMask())
        # attach obstacles
        obstacle_parent_list = []
        for obstacle in obstacle_list:
            obstacle_parent_list.append(obstacle.objpdnp.getParent())
            obstacle.objpdnp.reparentTo(self.np)
        # attach other robots
        for robot in otherrobot_list:
            for cdnp in robot.cc.np.getChildren():
                current_into_cdmask = cdnp.node().getIntoCollideMask()
                new_into_cdmask = current_into_cdmask | self._bitmask_ext
                cdnp.node().setIntoCollideMask(new_into_cdmask)
            robot.cc.np.reparentTo(self.np)
        # collision check
        self.ctrav.traverse(self.np)
        # clear obstacles
        for i, obstacle in enumerate(obstacle_list):
            obstacle.objpdnp.reparentTo(obstacle_parent_list[i])
        # clear other robots
        for robot in otherrobot_list:
            for cdnp in robot.cc.np.getChildren():
                current_into_cdmask = cdnp.node().getIntoCollideMask()
                new_into_cdmask = current_into_cdmask & ~self._bitmask_ext
                cdnp.node().setIntoCollideMask(new_into_cdmask)
            robot.cc.np.detachNode()
        if self.chan.getNumEntries() > 0:
            collision_result = True
        else:
            collision_result = False
        if toggle_contact_points:
            contact_points = [
                da.pdv3_to_npv3(cd_entry.getSurfacePoint(base.render))
                for cd_entry in self.chan.getEntries()
            ]
            return collision_result, contact_points
        else:
            return collision_result

    def show_cdprimit(self):
        """
        Copy the current nodepath to base.render to show collision states
        TODO: maintain a list to allow unshow
        :return:
        author: weiwei
        date: 20220404
        """
        # print("call show_cdprimit")
        snp_cpy = self.np.copyTo(base.render)
        for cdelement in self.all_cdelements:
            pos = cdelement['gl_pos']
            rotmat = cdelement['gl_rotmat']
            cdnp = snp_cpy.getChild(cdelement['cdprimit_childid'])
            cdnp.setPosQuat(da.npv3_to_pdv3(pos), da.npmat3_to_pdquat(rotmat))
            cdnp.show()

    def disable(self):
        """
        clear pairs and nodepath
        :return:
        """
        for cdelement in self.all_cdelements:
            cdelement['cdprimit_childid'] = -1
        self.all_cdelements = []
        for child in self.np.getChildren():
            child.removeNode()
        self.bitmask_list = list(range(31))
Example #23
0
class Game(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)

        # Set the background color to black
        self.win.setClearColor(BACKGROUND_COLOR)

        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)

        # Create the main character

        playerStartPos = self.environ.find("**/start_point").getPos()
        self.player = Actor("models/player",
                           {"run": "models/player-run",
                            "walk": "models/player-walk"})
        self.player.reparentTo(render)
        self.player.setScale(.2)
        self.player.setPos(playerStartPos + (0, 0, 0.5))

        # Create a floater object, which floats 2 units above player.  We
        # use this as a target for the camera to look at.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(self.player)
        self.floater.setZ(CAMERA_TARGET_HEIGHT_DELTA)

        self.first_person = False

        def key_dn(name):
            return lambda: self.setKey(name, True)
        def key_up(name):
            return lambda: self.setKey(name, False)
        def quit():
            self.destroy()
        def toggle_first():
            self.first_person = not self.first_person
        # Accept the control keys for movement and rotation
        key_map = [
            # key              command        action                   help
            # ---              -------        ------                   ----
            ("escape",         "esc",         lambda: quit(),          '[ESC]: Quit'),
            ("arrow_left",     'left',        key_dn("left"),          "[Left Arrow]: Rotate Left"),
            ("arrow_left-up",  'left',        key_up("left"),          None),
            ("arrow_right",    'right',       key_dn("right"),         "[Right Arrow]: Rotate Right"),
            ("arrow_right-up", 'right',       key_up("right"),         None),
            ("arrow_up",       'forward',     key_dn("forward"),       "[Up Arrow]: Run Forward"),
            ("arrow_up-up",    'forward',     key_up("forward"),       None),
            ("arrow_down",     'backward',    key_dn("backward"),      "[Down Arrow]: Run Backward"),
            ("arrow_down-up",  'backward',    key_up("backward"),      None),
            ("a",              'cam-left',    key_dn("cam-left"),      "[A]: Rotate Camera Left"),
            ("a-up",           'cam-left',    key_up("cam-left"),      None),
            ("s",              'cam-right',   key_dn("cam-right"),     "[S]: Rotate Camera Right"),
            ("s-up",           'cam-right',   key_up("cam-right"),     None),
            ('f',              'first-pers',  lambda: toggle_first(),  '[F]: Toggle first-person'),
            ]
        self.keyMap = {}
        inst = Instructions()
        for key, command, action, description in key_map:
            if command:
                self.setKey(command, False)
            self.accept(key, action)
            if description:
                inst.add(description)

        taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera
        self.disableMouse()
        self.camera.setPos(self.player.getX(), self.player.getY() + 10, 2)

        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above player's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.
        self.cTrav = CollisionTraverser()

        self.playerGroundRay = CollisionRay()
        self.playerGroundRay.setOrigin(0, 0, 9)
        self.playerGroundRay.setDirection(0, 0, -1)
        self.playerGroundCol = CollisionNode('playerRay')
        self.playerGroundCol.addSolid(self.playerGroundRay)
        self.playerGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.playerGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.playerGroundColNp = self.player.attachNewNode(self.playerGroundCol)
        self.playerGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 9)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.camGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.camGroundColNp = self.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # Uncomment this line to see the collision rays
        self.playerGroundColNp.show()
        self.camGroundColNp.show()

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        self.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):

        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        if self.keyMap["cam-left"]:
            self.camera.setX(self.camera, -20 * dt)
        if self.keyMap["cam-right"]:
            self.camera.setX(self.camera, +20 * dt)

        # save player's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.player.getPos()

        # If a move-key is pressed, move player in the specified direction.

        if self.keyMap["left"]:
            self.player.setH(self.player.getH() + 300 * dt)
        if self.keyMap["right"]:
            self.player.setH(self.player.getH() - 300 * dt)
        if self.keyMap["forward"]:
            self.player.setY(self.player, -25 * dt)
        if self.keyMap["backward"]:
            self.player.setY(self.player, 25 * dt)

        # If player is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if self.keyMap["forward"] or self.keyMap["backward"] or self.keyMap["left"] or self.keyMap["right"]:
            if self.isMoving is False:
                self.player.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.player.stop()
                self.player.pose("walk", 5)
                self.isMoving = False

        # If the camera is too far from player, move it closer.
        # If the camera is too close to player, move it farther.

        if self.first_person:
            self.camera.setPos(self.player.getPos())
        else:
            camvec = self.player.getPos() - self.camera.getPos()
            camvec.setZ(0)
            camdist = camvec.length()
            camvec.normalize()
            if camdist > CAMERA_DISTANCE_MAX:
                self.camera.setPos(self.camera.getPos() + camvec * (camdist - int(CAMERA_DISTANCE_MAX)))
                camdist = CAMERA_DISTANCE_MAX
                if camdist < CAMERA_DISTANCE_MIN:
                    self.camera.setPos(self.camera.getPos() - camvec * (int(CAMERA_DISTANCE_MIN) - camdist))
                    camdist = CAMERA_DISTANCE_MIN

        # Normally, we would have to call traverse() to check for collisions.
        # However, the class ShowBase that we inherit from has a task to do
        # this for us, if we assign a CollisionTraverser to self.cTrav.
        self.cTrav.traverse(render)

        # Adjust player's Z coordinate.  If player's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = list(self.playerGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain":
            self.player.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.player.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above player, whichever is greater.

        entries = list(self.camGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain":
            self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + CAMERA_POSITION_HEIGHT_DELTA_MIN)
        if self.camera.getZ() < self.player.getZ() + CAMERA_POSITION_HEIGHT_DELTA_MAX:
            self.camera.setZ(self.player.getZ() + CAMERA_POSITION_HEIGHT_DELTA_MAX)

        # The camera should look in player's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above player's head.
        self.camera.lookAt(self.floater)

        return task.cont
Example #24
0
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 RoamingDroneDemo(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        # initalize the window
        base.disableMouse()
        self.win.setClearColor((0, 0, 0, 1))
        props = WindowProperties()
        props.setCursorHidden(True)
        props.setSize(1700,1000)
        base.win.requestProperties(props)

        # store keys
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "drift-left": 0,
             "drift-right": 0, "up": 0, "down": 0, "restart": 0, "firstPerson": 0}
        #instructions
        self.instruction2 = addInstructions(0.12, "[Left Arrow]: Rotate Left")
        self.instruction3 = addInstructions(0.18, "[Right Arrow]: Rotate Right")
        self.instruction4 = addInstructions(0.24, "[Up Arrow]: Fly Forward")
        self.instruction5 = addInstructions(0.30, "[A, D]: Move Camera")
        self.instruction6 = addInstructions(0.36, "[W, S]: Fly Lift/ Descent")
        self.instruction7 = addInstructions(0.42, "[F]: Toggle First Person/ Third Person")
        self.instruction8 = addInstructions(0.48, "[R]: Restart")

        # Set up the playground
        # models/toon/phase_15/hood/toontown_central.bam
        # models/world
        # CS_Map/myCSMAP.egg
        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)

        # Create drone and initalize drone position
        self.Drone = Actor("models/mydrone.egg")
        self.Drone.reparentTo(render)

        # resize and reposition the drone
        self.Drone.setScale(.1)
        self.Drone.setPos(5,5,5)
        # initial position is saved for restarting the game
        self.DroneStartPos = self.Drone.getPos()


        # User Controls
        self.accept('escape', __import__('sys').exit, [0])
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("a", self.setKey, ["drift-left", True])
        self.accept("d", self.setKey, ["drift-right", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("a-up", self.setKey, ["drift-left", False])
        self.accept("d-up", self.setKey, ["drift-right", False])
        self.accept("w", self.setKey, ["up", True])
        self.accept("w-up", self.setKey, ["up", False])
        self.accept("s", self.setKey, ["down", True])
        self.accept("s-up", self.setKey, ["down", False])
        self.accept("r", self.setKey, ["restart", True])
        self.accept("r-up", self.setKey, ["restart", False])
        self.accept("f", self.setKey, ["firstPerson", True])
        self.accept("f-up", self.setKey, ["firstPerson", False])

        taskMgr.add(self.move, "moveTask")

        # Disable Mouse
        self.disableMouse()

        # Camera settings
        self.cameraDistance = 5
        self.cameraPitch = -10

        # create the collision box for the drone 
        # this collision box will be used for collision detection
        self.droneBox = CollisionBox((0,0,2.5), 3, 3, 0.7)
        self.cnodePath = self.Drone.attachNewNode(CollisionNode('cnode'))
        self.cnodePath.node().addSolid(self.droneBox)

        # collision detection set up
        self.cTrav = CollisionTraverser()
        self.queue = CollisionHandlerQueue()
        self.cTrav.addCollider(self.cnodePath, self.queue)
        self.cTrav.traverse(render)


        ##################################
        #self.cTrav.showCollisions(render)
        #self.DroneGroundColNp.show()
        #self.camGroundColNp.show()
        ##################################

        # Lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((1, 1, 1, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

        # Crashed Text
        self.crashed = OnscreenText()
        self.firstPerson = False

        # HPR setting
        self.angle = 0
        self.angleChange = 0.8
        self.maxAngle = 20


    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    # Deal with user interface and collision detection

    def move(self, task):

        self.crashed.destroy()
        self.crashed = OnscreenText(text="Crashed!!!" if len(self.queue.getEntries()) != 0 else "", pos = (-0.5, 0.02), 
                                scale = 0.07, mayChange = True, fg = (255,255,255,1))

        # Get the time that elapsed since last frame.  
        dt = globalClock.getDt()

        # Drone is movable only when it's not crashed
        if len(self.queue.getEntries()) == 0:

            # tilting while drift left and right
            if self.keyMap["drift-left"]:
                self.Drone.setY(self.Drone, 40 * dt)
                # tilt left when drift left
                if self. angle > -self.maxAngle:
                    self.angle -= self.angleChange
                self.Drone.setP(self.angle)
            elif self.keyMap["drift-right"]:
                self.Drone.setY(self.Drone, -40 * dt)
                # tilt right when drift right
                if self. angle < self.maxAngle:
                    self.angle += self.angleChange
                self.Drone.setP(self.angle)
            # gradually stablize itself while drift-keys are not pressed
            else:
                if self.angle >=self.angleChange:
                    self.angle -= self.angleChange
                elif self.angle <=-self.angleChange:
                    self.angle +=self.angleChange
                self.Drone.setP(self.angle)

            # turn left
            if self.keyMap["left"]:
                self.Drone.setH(self.Drone.getH() + 150 * dt)
            # turn right
            if self.keyMap["right"]:
                self.Drone.setH(self.Drone.getH() - 150 * dt)
            # go forward
            if self.keyMap["forward"]:
                self.Drone.setX(self.Drone, 200 * dt)
            # lift up
            if self.keyMap["up"]:
                self.Drone.setZ(self.Drone, 40 * dt)
            # go down
            if self.keyMap["down"]:
                self.Drone.setZ(self.Drone, -80 * dt)


        # restart game / reset position
        if self.keyMap["restart"]:
            self.Drone.setPos(self.DroneStartPos + (0, 0, 5))
            self.collisionCount = False
            self.crashed.destroy()

        if self.keyMap["firstPerson"]:
            self.firstPerson = not self.firstPerson

        ######################
        #self.cnodePath.show()
        ######################


        # set the position and HPR of the camera according to the position of the drone
        if self.firstPerson:
            base.camera.setH(self.Drone.getH()-90)
            base.camera.setP(self.Drone.getR())
            base.camera.setR(self.Drone.getP())
            base.camera.setPos(self.Drone.getPos())

        else:
            base.camera.setHpr(self.Drone.getHpr()+(180,0,0))
            h,p,r = self.Drone.getHpr()
            base.camera.setPos(self.Drone.getPos() + (math.cos(math.pi * h / 180) * -self.cameraDistance, \
                math.sin(math.pi * h / 180) * -self.cameraDistance, 0.5))

            viewTarget = Point3(self.Drone.getPos() + (0,0,0))

            base.camera.lookAt(viewTarget)

        #print(self.camera.getPos())
        return task.cont
class MyApp(ShowBase):
    def insertTile(self, node, submap_center, xel: Xel.Xel, tile_z, terrain):
        dx, dy = submap_center
        (q, r) = xel.exa.x, xel.exa.e
        v_center = VBase2(s3 * q, v3s * 2 * (q / 2 + r))

        tile_color = "rock"  #TODO
        #if abs(q) == Map.radius or abs(r) == Map.radius or abs(xel.exa.a) == Map.radius:
        #    tile_color = "yellow"
        #else:  #temporary
        if terrain == "water":
            tile_z = 0
        tile_color = terrain

        return self.model.loadExaTile(node, v_center[0] + dx, v_center[1] + dy,
                                      tile_z, tile_color)

    def drawTriangle(self, node, submap_center, submap_xel, triangle_index,
                     nodes_ZTH, open_simplex):
        global god
        center_map = submap_xel
        for d in range(1, Map.radius +
                       1):  # distance from center moving along triangle side t
            center_map = center_map.link[dirs[triangle_index]]
            tmp_map = center_map
            for n in range(
                    0, d
            ):  # each cell from triangle_index triangle edge (included) to next triangle edge (excluded)
                if d == Map.radius and n == 0:
                    cell_z = nodes_ZTH[0][triangle_index]
                    cell_t = nodes_ZTH[1][triangle_index]
                    cell_h = nodes_ZTH[2][triangle_index]
                else:
                    interna = ((nodes_ZTH[0][6], nodes_ZTH[0][triangle_index],
                                nodes_ZTH[0][(triangle_index + 1) % 6]),
                               (nodes_ZTH[1][6], nodes_ZTH[1][triangle_index],
                                nodes_ZTH[1][(triangle_index + 1) % 6]),
                               (nodes_ZTH[2][6], nodes_ZTH[2][triangle_index],
                                nodes_ZTH[2][(triangle_index + 1) % 6]))
                    res = ExaRandom.interpolate(
                        self, interna, Map.radius,
                        (tmp_map.exa.e, tmp_map.exa.x, tmp_map.exa.a))

                    (cell_z, cell_t, cell_h) = res
                cell_z += open_simplex.noise2d(tmp_map.exa.x,
                                               tmp_map.exa.e) / 5

                esterna = god.creation(
                    submap_center,
                    (tmp_map.exa.e, tmp_map.exa.x, tmp_map.exa.a), cell_t,
                    cell_h)  #animale, vegetale, terreno

                #load models

                dx, dy = submap_center
                (q, r) = tmp_map.exa.x, tmp_map.exa.e
                v_center = VBase2(s3 * q, v3s * 2 * (q / 2 + r))

                if esterna[0] != None:
                    self.model.loadAnimal(node, v_center[0] + dx,
                                          v_center[1] + dy, cell_z,
                                          esterna[0].nome)
                if esterna[1] != None:
                    self.model.loadPlant(node, v_center[0] - side + dx,
                                         v_center[1] + dy, cell_z,
                                         esterna[1].nome)

                if esterna[2] != None:
                    terrain_name = esterna[2].nome
                else:
                    terrain_name = "rock"

                self.insertTile(node, submap_center, tmp_map, cell_z,
                                terrain_name)

                tmp_map = tmp_map.link[dirs[(triangle_index + 2) % 6]]

    def drawSubmap(self, submap):
        l_map = Map.l_map  # TODO: chose if letting this way or pass l_map as parameter

        open_s = OpenSimplex(submap.noise_seed)

        #Center
        global god
        esterna = god.creation(submap.centerXY, (0, 0, 0), submap.array_T[6],
                               submap.array_H[6])  #animale, vegetale, terreno

        if esterna[2] != None:
            terrain_name = esterna[2].nome
        else:
            terrain_name = "rock"

        self.insertTile(submap.node, submap.centerXY, l_map, submap.array_Z[6],
                        terrain_name)

        ### Graphic map construction, triangle-by-triangle way
        center_map = l_map
        for t in range(6):  # scan each triangle
            interna = (submap.array_Z, submap.array_T, submap.array_H)
            self.drawTriangle(submap.node, submap.centerXY, center_map, t,
                              interna, open_s)
        ###
        return submap

    def drawMap(self, submap):
        global current_submap
        global stored_submaps_list
        global rendered_submaps

        new_seven_centers = []
        for d, v in coords.items():
            temp_c = ((v[0] + submap.centerXY[0]), (v[1] + submap.centerXY[1]))
            #print("-----------------------",v, submap.centerXY, temp_c) #BUGGONE
            new_seven_centers.append(temp_c)
        new_seven_centers.append(submap.centerXY)

        if len(rendered_submaps) == 0:  # Starting case
            submap.node = SubmapNode("0")
            submap.node.reparentTo(self.render)
            center = self.drawSubmap(submap)
            rendered_submaps.append(center)
            tmp_rendered_submaps = [None, None, None, None, None, None, center]
        else:
            tmp_rendered_submaps = [None, None, None, None, None, None, None]

        useful_values = []

        for i in range(7):
            draw = True  #check if a sub_map in new_seven_centers has to be drawn.
            #print all rendenew_seven_centersred maps
            """print("Rendered:")
            for s in rendered_submaps:
                print(s, end='')
            print("")"""
            c = new_seven_centers[i]
            for s in rendered_submaps:
                #diff = (abs(c[0] - s.centerXY[0]), abs(c[1] - s.centerXY[1]))
                print("_--------------", c, s)
                print(
                    "DIFF= ",
                    math.isclose(c[0], s.centerXY[0], abs_tol=0.1)
                    and math.isclose(c[1], s.centerXY[1], abs_tol=0.1))
                if math.isclose(c[0], s.centerXY[0],
                                abs_tol=0.1) and math.isclose(
                                    c[1], s.centerXY[1], abs_tol=0.1):
                    draw = False  #if a map in new_seven_centers is already in rendered_submaps set draw to false
                    tmp_rendered_submaps[i] = s
                    # prova
                    useful_values.append(s)
                    break
            if draw == True:  #if draw is still True, then draw the map in new_seven_centers
                if c in stored_submaps_list.keys():
                    s_map = stored_submaps_list[c]
                else:
                    s_map = ExaRandom().create_submap(c)
                    stored_submaps_list[c] = s_map
                s_map.node = SubmapNode("1")
                s_map.node.reparentTo(self.render)
                tmp_rendered_submaps[i] = self.drawSubmap(s_map)
                #rendered_submaps.append(self.drawSubmap(self.render, s_map))
                print(c, "drawn\n")
            else:
                print(c, "NOT drawn\n")
        # identify no-longer loaded submaps and clear their nodes
        for s in rendered_submaps:
            if s not in tmp_rendered_submaps:
                self.clear_node(s.node)
                s.node.removeNode()  # needs to be tested (TODO)
                s.node = None  # if previous line doesn't remove it automatically

        rendered_submaps = tmp_rendered_submaps
        current_submap = submap
        print("Rendered:")
        for s in rendered_submaps:
            print(s, end='')
        print("")

    def clear_node(self, nodepath):
        if not nodepath.isEmpty():
            for model in nodepath.getChildren():
                model.removeNode()

    def clear_all_nodes(self):
        self.clear_node(rendered_submaps[random.randint(
            0, 5)].node)  # temporary madness
        #for n in all_nodes:
        #    self.clear_node(n)
        #    n.remove_node()

    def print_all_nodes(self):
        string = ""
        for n in all_nodes:
            string += str(n) + "; "
        print(string)

    def __init__(self):
        ShowBase.__init__(self)

        # Load Lights
        self.light = LoadLight.Light
        self.light.setupLight(self)

        # Load Environment
        self.model = LoadModel.Model()
        self.model.initialize(self)

        Map.init()
        map_center = (0, 0)
        subprova = Submap.Submap(map_center)
        global stored_submaps_list
        global current_submap
        stored_submaps_list[map_center] = subprova
        current_submap = subprova
        print("stored in init:", stored_submaps_list)
        self.drawMap(subprova)
        """
        self.model.loadAnimal(5,6,0, "bear")
        self.model.loadAnimal(12,-6,0, "cow")
        self.model.loadAnimal(7,-9,0, "panther")
        self.model.loadAnimal(-17,5,0, "rabbit")
        self.model.loadAnimal(-7,5,0, "wolf")
        
        self.model.loadPlant(8,-2,0, "fir")
        self.model.loadPlant(-3,-2,0, "grass")
        self.model.loadPlant(-4,2,0, "oak")
        self.model.loadPlant(-1,17,0, "berry_bush")
        """

        # Text on screen
        self.text_char_pos = None
        self.text_submap = None
        self.text_lock = None

        # Create the main character
        self.char = self.model.loadCharacter(0, 0, 0)

        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above char's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.
        self.cTrav = CollisionTraverser()

        self.charGroundRay = CollisionRay()
        self.charGroundRay.setOrigin(0, 0, 9)
        self.charGroundRay.setDirection(0, 0, -1)
        self.charGroundCol = CollisionNode('charRay')
        self.charGroundCol.addSolid(self.charGroundRay)
        self.charGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.charGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.charGroundColNp = self.char.attachNewNode(self.charGroundCol)
        self.charGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.charGroundColNp, self.charGroundHandler)

        # Uncomment this line to see the collision rays
        #self.charGroundColNp.show()

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #self.cTrav.showCollisions(render)

        # This is used to store which keys are currently pressed.
        self.keyMap = {
            "restart": 0,
            "left": 0,
            "right": 0,
            "forward": 0,
            "backward": 0,
            "cam-q": 0,
            "cam-w": 0,
            "cam-e": 0,
            "cam-d": 0,
            "cam-s": 0,
            "cam-a": 0
        }

        # Post the instructions
        self.title = addTitle("Isometric HexaMap test")
        self.inst1 = addInstructions(0.06, "[ESC]: Quit")
        self.inst2 = addInstructions(0.12, "[Arrow Keys]: Move char")
        self.inst3 = addInstructions(
            0.18, "[Q,W,E,D,S,A]: Change camera's angle of view")
        #self.inst8 = addInstructions(0.48, "[R]: Restart")

        # Accept the control keys for movement and rotation
        self.accept("escape", sys.exit)
        self.accept("n", self.print_all_nodes)
        self.accept("k", self.clear_all_nodes)
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("arrow_down", self.setKey, ["backward", True])
        self.accept("q", self.setKey, ["cam-q", True])
        self.accept("w", self.setKey, ["cam-w", True])
        self.accept("e", self.setKey, ["cam-e", True])
        self.accept("d", self.setKey, ["cam-d", True])
        self.accept("s", self.setKey, ["cam-s", True])
        self.accept("a", self.setKey, ["cam-a", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("arrow_down-up", self.setKey, ["backward", False])
        self.accept("q-up", self.setKey, ["cam-q", False])
        self.accept("w-up", self.setKey, ["cam-w", False])
        self.accept("e-up", self.setKey, ["cam-e", False])
        self.accept("d-up", self.setKey, ["cam-d", False])
        self.accept("s-up", self.setKey, ["cam-s", False])
        self.accept("a-up", self.setKey, ["cam-a", False])
        # self.accept("restart", self.char.setPos(0,0,0))

        self.taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera with isometric perspective
        self.disableMouse()
        lens = OrthographicLens()
        lens.setFilmSize(20, 11.25)
        lens.setNear(-20)
        self.cam.node().setLens(lens)
        self.camera.setPos(self.char.getPos() +
                           (math.sin(cam_angle[cam_view]) * cam_dist,
                            -math.cos(cam_angle[cam_view]) * cam_dist, cam_dz))
        self.camera.lookAt(self.char)

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    def move(self, task):
        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.
        global cam_view
        temp_cam = cam_view
        if self.keyMap["cam-q"]:
            cam_view = 'q'
        if self.keyMap["cam-w"]:
            cam_view = 'w'
        if self.keyMap["cam-e"]:
            cam_view = 'e'
        if self.keyMap["cam-d"]:
            cam_view = 'd'
        if self.keyMap["cam-s"]:
            cam_view = 's'
        if self.keyMap["cam-a"]:
            cam_view = 'a'

        global cam_rotating
        final_angle = int(round((cam_angle[cam_view] * RAD_DEG))) % 360
        current_angle = int(round(self.camera.getH())) % 360

        # Camera rotation task is triggered when a different angle of view is selected.
        # The direction of rotation is chosen by comparing the two angles
        # and changing the sign of the camera rotation angle: cam_delta_angle
        if final_angle != current_angle:
            if not self.taskMgr.hasTaskNamed("SpinCameraTask"):
                global cam_delta_angle
                diff = final_angle - current_angle
                cam_delta_angle = math.copysign(cam_delta_angle, diff)
                if diff > 180:
                    cam_delta_angle = math.copysign(cam_delta_angle, -1)
                elif diff < -180:
                    cam_delta_angle = math.copysign(cam_delta_angle, 1)
                self.taskMgr.doMethodLater(cam_task_time, self.spinCameraTask,
                                           "SpinCameraTask")
            cam_rotating = True

        if not cam_rotating:
            # save char's initial position so that we can restore it,
            # in case he falls off the map or runs into something.
            startpos = self.char.getPos()
            # If a move-key is pressed, turn and move char in the relative direction.
            # The pressure of multiple keys at the same time is handled by the v_rot vector
            # Movements in 2D plane depend on camera's position & orientation
            v_rot = VBase3(0, 0, 0)

            if self.keyMap["forward"]:
                v_rot += (0, 1, 0)
            if self.keyMap["backward"]:
                v_rot += (0, -1, 0)
            if self.keyMap["left"]:
                v_rot += (-v3, 0, 0)
            if self.keyMap["right"]:
                v_rot += (v3, 0, 0)

            if v_rot.normalize():
                self.char.lookAt(self.char.getPos() + v_rot)
                self.char.setH(self.char.getH() + self.camera.getH())
                self.char.setY(self.char, step * dt)

            # Normally, we would have to call traverse() to check for collisions.
            # However, the class ShowBase that we inherit from has a task to do
            # this for us, if we assign a CollisionTraverser to self.cTrav.
            self.cTrav.traverse(render)

            # Adjust char's Z coordinate.  If char's ray hit terrain,
            # update his Z. If it hit anything else, or didn't hit anything, put
            # him back where he was last frame.
            entries = list(self.charGroundHandler.getEntries())
            entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())
            if (len(entries) > 0
                    and entries[0].getIntoNode().getName() == "ExaTile"
                    and entries[0].getSurfacePoint(render).getZ() -
                    self.char.getZ() <= CHAR_MAX_ZGAP):
                self.char.setZ(entries[0].getSurfacePoint(render).getZ())
            else:
                self.char.setPos(startpos)

            # Put on screen the lock's value
            #if self.text_lock != None:
            #    self.text_lock.destroy()
            #self.text_lock = addInfo(0.15, "Lock: "+str(Map.new_dir_lock))

            #QUIIIIIII+
            global pix_pos_tmp
            pix_pos = self.char.getPos()

            exa_pos = None

            #if (math.isclose(abs(pix_pos[0])%(apo+0.05), apo, rel_tol=0.05) or math.isclose(abs(pix_pos[1])%(apo+0.05), apo,rel_tol=0.05)):

            exa_pos = -1 / 3 * pix_pos[0] + math.sqrt(
                3) / 3 * pix_pos[1], 2 / 3 * pix_pos[0]

            pix_pos = VBase3(round(exa_pos[0]), round(exa_pos[1]), 0)
            pix_pos += VBase3(0, 0, round(-pix_pos[0] - pix_pos[1]))

            pix_pos_diff = VBase3(abs(pix_pos[0] - exa_pos[0]),
                                  abs(pix_pos[1] - exa_pos[1]),
                                  abs(pix_pos[2] - (-exa_pos[0] - exa_pos[1])))

            if pix_pos_diff[0] > pix_pos_diff[1] and pix_pos_diff[
                    0] > pix_pos_diff[2]:
                pix_pos[0] = -pix_pos[1] - pix_pos[2]
            elif pix_pos_diff[1] > pix_pos_diff[2]:
                pix_pos[1] = -pix_pos[0] - pix_pos[2]
            else:
                pix_pos[2] = -pix_pos[0] - pix_pos[1]

            if pix_pos_tmp != pix_pos:
                direc = pix_pos - pix_pos_tmp
                directions = {
                    VBase3(1, -1, 0): 'q',
                    VBase3(1, 0, -1): 'w',
                    VBase3(0, 1, -1): 'e',
                    VBase3(-1, 1, 0): 'd',
                    VBase3(-1, 0, 1): 's',
                    VBase3(0, -1, 1): 'a'
                }
                Map.menu(directions.get(direc))
                print(Map.position)
                #print(self.char.getPos())
                if self.text_char_pos != None:
                    self.text_char_pos.destroy()
                self.text_char_pos = addInfo(
                    0, "Char position: (" + str(round(self.char.getX(), 2)) +
                    " , " + str(round(self.char.getY(), 2)) + ")")

                #Map.new_dir_lock=False
                # New submap check
                if Map.new_dir != None:
                    global current_submap
                    global new_submap
                    #Map.new_dir_lock=True
                    d = Map.new_dir
                    Map.new_dir = None
                    new_center = (current_submap.centerXY[0] + coords[d][0],
                                  current_submap.centerXY[1] + coords[d][1])
                    for c, s in stored_submaps_list.items():
                        if math.isclose(c[0], new_center[0],
                                        abs_tol=0.1) and math.isclose(
                                            c[1], new_center[1], abs_tol=0.1):
                            new_submap = s
                            break
                    self.drawMap(
                        new_submap
                    )  # TODO: maybe we can give direction as parameter
                    global rendered_submaps
                    print("Rendered.length = " + str(len(rendered_submaps)))

            pix_pos_tmp = pix_pos

            #Map.position= l_map.findXel()

            #print(Exa.Exa(pix_pos[0], pix_pos[1], -pix_pos[2]))

            # Camera position handling: it depends on char's position
            self.camera.setX(self.char.getX() +
                             math.sin(current_angle * DEG_RAD) * cam_dist)
            self.camera.setY(self.char.getY() -
                             math.cos(current_angle * DEG_RAD) * cam_dist)
            self.camera.setZ(self.char.getZ() + cam_dz)

            self.camera.lookAt(self.char)

        else:  # cam is rotating
            if final_angle == current_angle:
                print("CAM IN PLACE!")
                self.taskMgr.remove("SpinCameraTask")
                cam_rotating = False
        #print("curr: ", self.camera.getH())
        #print("dest: ", cam_angle[cam_view]*RAD_DEG)
        return task.cont

    # Task to animate the camera when user changes the angle of view.
    # Make the camera rotate counterclockwise around the character in x,y plane
    def spinCameraTask(self, task):
        angle_deg = int(round(self.camera.getH())) + cam_delta_angle
        angle_rad = angle_deg * DEG_RAD
        delta_v = VBase3(self.char.getX() + cam_dist * math.sin(angle_rad),
                         self.char.getY() - cam_dist * math.cos(angle_rad),
                         self.camera.getZ())
        self.camera.setPos(delta_v)
        self.camera.lookAt(self.char)
        return task.done

    def restartGame(self):
        pass
Example #27
0
class Picker(Viewer):
    """ View and click objects in a scene."""

    def __init__(self):
        # Parent init.
        super(Picker, self).__init__()
        self.disableMouse()
        # Picker stuff.
        self.contact_margin = Vec3(0.01, 0.01, 0.01)
        self.parser = None
        self.marked = None
        self.attached_pairs = set()
        self.contacts = None
        self.contact_points = None
        self.contact_bottoms = None
        self.compound_components = []
        self.compound_objects = []
        self.joints = JointManager()
        self.wire_attrib = RenderModeAttrib.make(
            RenderModeAttrib.MWireframe, 4.)
        self.attachment_colors = (Vec4(0.1, 0.1, 1., 1.),
                                  Vec4(0.1, 0.8, 0.1, 1.),
                                  Vec4(1., 0.1, 1., 1.),
                                  Vec4(1., 0.5, 0.1, 1.),
                                  Vec4(1., 1., 1., 1.))
        self.max_attach = 999
        self.permanent_events += ["mouse1"]
        # Make cursor dot.
        self.cursor = self._build_cursor("cross")
        s = 0.08
        self.cursor.setScale(s, s, s)
        self.cursor.setColor(1, 1, 1, 1)
        self.cursor.reparentTo(self.aspect2d)
        self.taskMgr.add(self.draw_cursor2d, "draw_cursor2d")
        self.permanent_tasks.append("draw_cursor2d")

    def init_ssos(self, *args, **kwargs):
        super(Picker, self).init_ssos(*args, **kwargs)

    def init_physics(self, *args, **kwargs):
        super(Picker, self).init_physics(*args, **kwargs)
        self.joints.bbase = self.bbase

    def init_picker(self):
        # Collision traverser
        self.traverser = CollisionTraverser("traverser")
        # Collision handler
        self.handler = CollisionHandlerQueue()
        # Initialize and set up picker ray node and NodePath
        self.picker = CollisionNode("mouse_ray")
        self.pickerNP = self.camera.attachNewNode(self.picker)
        self.picker.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.picker_ray = CollisionRay()
        self.picker.addSolid(self.picker_ray)
        self.traverser.addCollider(self.pickerNP, self.handler)
        mark_color = (1, 1, 1, 0.3)
        self.base_mark = self.create_mark(color=mark_color)
        connector_color = (1, 1, 1, 1)
        self.base_connector = self.create_connector(color=connector_color)

    def _build_cursor(self, shape="sphere"):
        if shape == "sphere":
            cursor = self._load("sphere.bam")
        elif shape == "cross":
            cursor = LineNodePath()
            lines = [[Point3(-0.5, 0, 0), Point3(0.5, 0, 0)],
                     [Point3(0, 0, -0.5), Point3(0, 0, 0.5)]]
            cursor.drawLines(lines)
            cursor.setThickness(1)
            cursor.create()
            # cursor = NodePath("cross")
            # S = {"cylinderX.bam": ((0., 0., 0.), (1., 0.1, 0.1)),
            #      "cylinderY.bam": ((0., 0., 0.), (0.1, 1., 0.1)),
            #      "cylinderZ.bam": ((0., 0., 0.), (0.1, 0.1, 1.))}
            # for k, v in S.iteritems():
            #     m = self._load(k)
            #     m.setName(k)
            #     m.setPos(*v[0])
            #     m.setScale(*v[1])
            #     m.reparentTo(cursor)
        #BP()
        return cursor

    def create_mark(self, color):
        """ Makes a graphical mark object."""
        # Make a graphical box.
        props = dict(name="mark", color=color, model="box-round.egg")
        obj = GSO(props=props)
        return obj

    def create_connector(self, color):
        """ Makes a graphical connector object."""
        # Make a graphical box.
        props = dict(name="connector", color=color, model="connector.egg")
        obj = GSO(props=props)
        return obj

    def start_picker(self, pickables):
        # Set pickable objs.
        for i, obj in enumerate(pickables):
            obj.setTag("pickable", str(i))
        # Add mouse events.
        self.accept("mouse1", self.clicked, extraArgs=[1])
        # Start contact detector.
        detector = ContactDetector(self.bbase.world, self.scene,
                                   margin=self.contact_margin)
        self.contacts = detector.contacts
        self.contact_bodies = detector.bodies
        self.contact_points = detector.points
        parser = Parser(self.contacts, self.contact_bodies)
        self.contact_bottoms = parser.bottom_bodies
        self.connectors = {}

    def stop_picker(self):
        self.removeTask("mouse1")

    def goto_sso(self, *args, **kwargs):
        self.clear_attachments()
        self.stop_picker()
        super(Picker, self).goto_sso(*args, **kwargs)
        self.remove_physics()
        # Start picker.
        pickables = self.sso.descendants(type_=PSO)
        self.start_picker(pickables)
        self.attach_physics()

    def get_picked_obj(self):
        mpos = self.mouseWatcherNode.getMouse()
        self.picker_ray.setFromLens(self.cam.node(), mpos.getX(), mpos.getY())
        self.traverser.traverse(self.render)
        if self.handler.getNumEntries() > 0:
            # This is so we get the closest object
            self.handler.sortEntries()
            entries = self.handler.getEntries()
            for entry in entries:
                picked_obj = entry.getIntoNodePath().findNetTag("pickable")
                if not picked_obj.isEmpty():
                    break
            if picked_obj.isEmpty():
                picked_obj = None
        else:
            picked_obj = None
        return picked_obj

    def clicked(self, button):
        """ Mouse click handler."""
        if self.mouseWatcherNode.hasMouse():
            # Get picked object
            picked_obj = self.get_picked_obj()
            if picked_obj is not None:
                if self.marked is None:
                    # New mark activated.
                    self.marked = picked_obj
                    self.show_marked(picked_obj, True)
                    event = "mark"
                elif picked_obj == self.marked:
                    # Existing mark deactivated.
                    self.show_marked(picked_obj, False)
                    self.marked = None
                    event = "unmark"
                else:
                    # New attachment or detachment.
                    pair = tuple(sorted((self.marked, picked_obj)))
                    ij = tuple(sorted((self.contact_bodies.index(pair[0]),
                                       self.contact_bodies.index(pair[1]))))
                    if ij in self.contacts:
                        f_add = (ij, pair) not in self.attached_pairs
                        if (not f_add or len(self.attached_pairs) <
                            self.max_attach):
                            self.store_attachment(ij, pair, f_add)
                            self.show_marked(self.marked, False)
                            self.marked = None
                            event = "attach" if f_add else "detach"
                        else:
                            print("Max attachments already reached.")
                            event = "max-attach"
                    else:
                        event = "non-contact"
            else:
                event = "non-pick"
            return picked_obj, event

    def store_attachment(self, ij, pair, f_add):
        """ Stores the attached objects, and draws them."""
        if f_add:
            self.attached_pairs.add((ij, pair))
            self.show_attachment(ij, True)
            self.attach_pair(pair, True)
        else:
            try:
                self.attached_pairs.remove((ij, pair))
            except KeyError:
                pass
            else:
                self.attach_pair(pair, False)
                self.show_attachment(ij, False)

    def clear_attachments(self):
        """ Clear all attachments."""
        if self.marked:
            self.show_marked(self.marked, False)
            self.marked = None
            self.mark = None
        for ij, pair in self.attached_pairs:
            self.attach_pair(pair, False)
            self.show_attachment(ij, False)
        self.attached_pairs = set()
        #
        self.reset_compounds()
        self.contacts = None
        self.contact_bodies = None
        self.contact_points = None
        self.contact_bottoms = None

    def _make_mark(self, node, extent, name):
        """ Makes a mark GSO."""
        mark = self.base_mark.copy()
        mat = node.getMat(self.scene)
        mark.apply_prop(dict(name=name), other=self.scene)
        mark.setMat(self.scene, mat)
        mark.setScale(self.scene, mark.getScale(self.scene) + extent)
        mark.wrtReparentTo(node)
        return mark

    def show_marked(self, node, f_on):
        """ Turns on/off marked graphic."""
        if f_on:
            extent = Vec3(0.15, 0.15, 0.15)
            name = "mark"
            self.mark = self._make_mark(node, extent, name)
            self.mark.init_tree(tags=("model",))
            # Exclude object from casting shadows
            self.mark.hide(self.shadow_mask)
            self.mark.setTransparency(TransparencyAttrib.MAlpha)
            self.mark.setDepthWrite(False)
            self.mark.setBin("fixed", 0, priority=5)
        else:
            self.mark.removeNode()

    def _make_connector(self, parent, points, extent, name):
        """ Makes connector object."""
        connector = self.base_connector.copy()
        scale = Vec3(*(np.ptp(points, axis=0)))
        scale_extended = scale + extent
        pos = Point3(*(np.min(points, axis=0) + scale / 2.))
        connector.apply_prop(dict(name=name, scale=scale_extended, pos=pos),
                             other=self.scene)
        connector.wrtReparentTo(parent)
        return connector

    def show_attachment(self, ij, f_on):
        """ Turns on/off attachment graphic."""
        if f_on:
            parent = self.contact_bottoms[ij]
            points = self.contact_points[ij]
            extent = Vec3(0.15, 0.15, 0.15)
            name = "connector_%d-%d" % ij
            self.connectors[ij] = self._make_connector(parent, points,
                                                       extent, name)
            self.connectors[ij].init_tree(tags=("model",))
        else:
            self.connectors.pop(ij).removeNode()

    # def attach_pair(self, pair, f_on):
    #     """ Adds/removes physical attachment between a pair of nodes."""
    #     key = tuple(sorted(p.node() for p in pair))
    #     # key = frozenset(pair)
    #     if f_on:
    #         # Create the joint and add it.
    #         self.joints[key] = self.joints.make_fixed(*pair)
    #     else:
    #         # Remove it.
    #         del self.joints[key]

    def attach_physics(self):
        # Attach `self.scene` to the physics world.
        try:
            exclude = zip(*self.compound_components)[0]
        except IndexError:
            exclude = []
        bnodes = [bnode for bnode in self.scene.descendants(type_=PSO)
                  if bnode not in exclude]
        for bnode in bnodes:
            bnode.init_resources(tags=("shape",))
            bnode.setCollideMask(BitMask32.allOn())
            bnode.node().setDeactivationEnabled(False)
        self.bbase.attach(bnodes)

    def reset_compounds(self):
        for n, p in self.compound_components:
            n.wrtReparentTo(p)
        self.compound_components = []
        for cnode in self.compound_objects:
            cnode.destroy_resources()
            cnode.removeNode()
        self.compound_objects = []

    def make_attachment_graph(self):
        if not self.contact_bodies:
            return None
        n = len(self.contact_bodies)
        mtx = np.zeros((n, n), dtype="i")
        for (i, j), _ in self.attached_pairs:
            # i = self.contact_bodies.index(pair[0])
            # j = self.contact_bodies.index(pair[1])
            mtx[i, j] = 1
            # mtx[j, i] = 1
        graph = nx.from_numpy_matrix(mtx)
        return graph

    def attach_pair(self, pair, f_on):
        """ Adds/removes physical attachment between a pair of nodes."""
        # Get the connected subgroups.
        graph = self.make_attachment_graph()
        sgs = [sg for sg in nx.connected_components(graph) if len(sg) > 1]
        self.reset_compounds()
        # Iterate over subgroups, creating compound shapes.
        for sg in sgs:
            nodes = [self.contact_bodies[i] for i in sg]
            parents = [c.getParent() for c in nodes]
            self.compound_components.extend(zip(nodes, parents))
            cname = "+".join([str(i) for i in sorted(sg)])
            cnode = CPSO(cname)
            cnode.reparentTo(self.scene)
            cnode.add(nodes)
            cnode.init_tree(tags=("shape",))
            cnode.destroy_component_shapes()
            self.compound_objects.append(cnode)
Example #28
0
class RaceDrone(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        # initalize the window
        base.disableMouse()
        self.win.setClearColor((0, 0, 0, 1))
        props = WindowProperties()
        props.setCursorHidden(True)
        props.setSize(1700,1000)
        base.win.requestProperties(props)

        # store keys
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "backward": 0, 
            "drift-left": 0, "drift-right": 0, "up": 0, "down": 0,
            "restart": 0, "firstPerson": 0, "gravity": 0}

        #instructions
        self.ins2 = addInstructions(0.12, "[Left/Right Arrow]: Rotate Left/Right")
        self.ins3 = addInstructions(0.18, "[Up/Down Arrow]: Fly Forward/Backward")
        self.ins4 = addInstructions(0.24, "[A, D]: Move Camera")
        self.ins5 = addInstructions(0.30, "[W, S]: Lift / Descent")
        self.ins6 = addInstructions(0.36, "[F]: Toggle First Person/ Third Person")
        self.ins7 = addInstructions(0.42, "[G]: Toggle Gravity")
        self.ins8 = addInstructions(0.48, "[R]: Restart")

        # Set up the playground
        # other maps:
        # models/toon/phase_15/hood/toontown_central.bam
        # models/world
        # CS_Map/myCSMAP.egg
        # Race/RaceTrack/FullTrack.blend

        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)
        self.mapScale = 1

        """
        self.environ = loader.loadModel("The City/The City.obj")
        self.environ.reparentTo(render)
        myTexture = loader.loadTexture("The City/Maps/cty1.jpg")
        self.environ.setTexture(myTexture)
        self.environ.setHpr(0,90,0)
        self.environ.setScale(.1)
        """

        # Create drone and initalize drone position
        self.Drone = Actor("models/mydrone.egg")
        self.Drone.reparentTo(render)

        # resize and reposition the drone
        self.Drone.setScale(.1)
        self.Drone.setPos(5,5,8)
        self.Drone.setH(180)
        # initial position is saved for restarting the game
        self.DroneStartPos = self.Drone.getPos()


        # User Controls
        self.accept('escape', __import__('sys').exit, [0])
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("arrow_down", self.setKey, ["backward", True])
        self.accept("a", self.setKey, ["drift-left", True])
        self.accept("d", self.setKey, ["drift-right", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("arrow_down-up", self.setKey, ["backward", False])
        self.accept("a-up", self.setKey, ["drift-left", False])
        self.accept("d-up", self.setKey, ["drift-right", False])
        self.accept("w", self.setKey, ["up", True])
        self.accept("w-up", self.setKey, ["up", False])
        self.accept("s", self.setKey, ["down", True])
        self.accept("s-up", self.setKey, ["down", False])
        self.accept("r", self.setKey, ["restart", True])
        self.accept("r-up", self.setKey, ["restart", False])
        self.accept("f", self.setKey, ["firstPerson", True])
        self.accept("f-up", self.setKey, ["firstPerson", False])
        self.accept("g", self.setKey, ["gravity", True])
        self.accept("g-up", self.setKey, ["gravity", False])

        taskMgr.add(self.move, "moveTask")

        # Disable Mouse
        self.disableMouse()

        # Camera settings
        self.cameraDistance = 5
        self.cameraPitch = -10

        # create the collision box for the drone 
        # this collision box will be used for collision detection
        self.droneBox = CollisionBox((0,0,2.5), 3, 3, 0.7)
        self.cnodePath = self.Drone.attachNewNode(CollisionNode('cnode'))
        self.cnodePath.node().addSolid(self.droneBox)

        # collision detection set up
        self.cTrav = CollisionTraverser()
        self.queue = CollisionHandlerQueue()
        self.cTrav.addCollider(self.cnodePath, self.queue)
        self.cTrav.traverse(render)


        # Lighting portion are modified from an example provided by Panda3d – Roaming Ralph 
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((1, 1, 1, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

        # Crashed Text
        self.crashed = OnscreenText()
        self.firstPerson = False

        # HPR setting
        self.angle = 0
        self.angleChange = 0.5
        self.maxAngle = 15

        # Speed Control
        self.FBSpeed = self.mapScale * 6
        self.LRSpeed = self.mapScale * 4
        self.turnSpeed = 80
        self.liftSpeed = self.mapScale * 80
        self.downSpeed = self.mapScale * 80


        # AI set up
        self.AI = True
        if self.AI:
            self.droneAI = Actor("models/mydrone.egg")
            self.droneAI.reparentTo(render)
            self.droneAI.setScale(.1)
            self.droneAI.setPos(5,5,5)
            self.AI_actions = open("AI/RoamingRalph/AI_easy.txt", "r").readlines()

        #######################
        # additional features #
        #######################

        # acceleration
        self.FBacceleration = 0
        self.LRacceleration = 0
        self.accelMax = 40
        self.accelIncrement = 2

        # gravity 
        self.gravity = True
        self.gravity_value = 15 * self.mapScale


    # Record user inputs
    def setKey(self, key, value):
        self.keyMap[key] = value


    # Main Function (Deal with user interface and collision detection)
    def move(self, task):

        #debug
        #print(self.queue.getEntries())
        #print(self.drone.getPos())
        #print(self.FBacceleration, self.LRacceleration)

        # crash message
        self.crashed.destroy()
        self.crashed = OnscreenText(text="Crashed!!!" if len(self.queue.getEntries()) != 0 else "", pos = (-0.5, 0.02), 
                                scale = 0.07, mayChange = True, fg = (255,255,255,1))

        # Get the time that elapsed since last frame.  
        dt = globalClock.getDt()


        # control the movement of AI
        if self.AI:
            if self.AI_actions != []:
                curAction = self.AI_actions[0].split(" ")
                self.droneAI.setX(float(curAction[0]))
                self.droneAI.setY(float(curAction[1]))
                self.droneAI.setZ(float(curAction[2]))
                self.droneAI.setH(float(curAction[3]))
                self.droneAI.setP(float(curAction[4]))
                self.droneAI.setR(float(curAction[5]))
                self.AI_actions.pop(0)

        # Drone is movable only when it's not crashed
        if len(self.queue.getEntries()) == 0:

            # initial height
            curHeight = self.Drone.getZ()

            # move by acceleration
            if self.FBacceleration != 0:
                self.Drone.setX(self.Drone, self.FBSpeed * self.FBacceleration * dt)
                self.FBacceleration += 1 if self.FBacceleration < 0 else -1
            if self.LRacceleration != 0:
                self.Drone.setY(self.Drone, self.LRSpeed * self.LRacceleration * dt)
                self.LRacceleration += 1 if self.LRacceleration < 0 else -1
                self.Drone.setZ(curHeight)

            # tilting while drift left and right
            if self.keyMap["drift-left"]:
                #self.Drone.setY(self.Drone, self.LRSpeed * dt)
                # tilt left when drift left
                if self. angle > -self.maxAngle:
                    self.angle -= self.angleChange
                self.Drone.setP(self.angle)
                if self.LRacceleration < self.accelMax:
                    self.LRacceleration += self.accelIncrement
            elif self.keyMap["drift-right"]:
                #self.Drone.setY(self.Drone, -self.LRSpeed * dt)
                # tilt right when drift right
                if self. angle < self.maxAngle:
                    self.angle += self.angleChange
                self.Drone.setP(self.angle)
                if self.LRacceleration > -self.accelMax:
                    self.LRacceleration -= self.accelIncrement
            # gradually stablize itself while drift-keys are not pressed
            else:
                if self.angle >=self.angleChange:
                    self.angle -= self.angleChange
                elif self.angle <=-self.angleChange:
                    self.angle +=self.angleChange
                self.Drone.setP(self.angle)

            # turn left
            if self.keyMap["left"]:
                self.Drone.setH(self.Drone.getH() + self.turnSpeed * dt)
            # turn right
            if self.keyMap["right"]:
                self.Drone.setH(self.Drone.getH() - self.turnSpeed * dt)

            # go forward
            if self.keyMap["forward"]:
                #self.Drone.setX(self.Drone, self.FBSpeed * dt)
                if self.FBacceleration < self.accelMax:
                    self.FBacceleration += self.accelIncrement
            elif self.keyMap["backward"]:
                #self.Drone.setX(self.Drone, -self.FBSpeed * dt)
                if self.FBacceleration > -self.accelMax:
                    self.FBacceleration -= self.accelIncrement

            # lift up
            if self.keyMap["up"]:
                self.Drone.setZ(self.Drone, self.liftSpeed * dt)
            # go down
            if self.keyMap["down"]:
                self.Drone.setZ(self.Drone, -self.downSpeed * dt)

            # gravity
            if self.gravity:
                self.Drone.setZ(self.Drone, -self.gravity_value * dt)


        # restart game / reset position
        if self.keyMap["restart"]:
            self.Drone.setPos(self.DroneStartPos + (0, 0, 5))
            self.collisionCount = False
            self.crashed.destroy()
            self.Drone.setH(180)

        # First Person View / Third Person View Toggle 
        if self.keyMap["firstPerson"]:
            self.firstPerson = not self.firstPerson

        # Gravity Toggle
        if self.keyMap["gravity"]:
            self.gravity = not self.gravity

        # uncomment the following code to see the collision box
        ########################
        #self.cnodePath.show() #
        ########################


        # set the position and HPR of the camera according to the position of the drone
        # First Person View
        if self.firstPerson:
            base.camera.setH(self.Drone.getH()-90)
            base.camera.setP(self.Drone.getR())
            base.camera.setR(self.Drone.getP())
            base.camera.setPos(self.Drone.getPos())
        # Third Person View
        else:
            base.camera.setHpr(self.Drone.getHpr()+(180,0,0))
            h,p,r = self.Drone.getHpr()
            base.camera.setPos(self.Drone.getPos() + (math.cos(math.pi * h / 180) * -self.cameraDistance, \
                math.sin(math.pi * h / 180) * -self.cameraDistance, 0.5))

            viewTarget = Point3(self.Drone.getPos() + (0,0,0)) # the look-at point can be changed

            base.camera.lookAt(viewTarget)

        return task.cont
Example #29
0
class Mouse():
    def __init__(self):
        self.enabled = False
        self.locked = False
        self.position = Vec3(0, 0, 0)
        self.delta = Vec3(0, 0, 0)
        self.prev_x = 0
        self.prev_y = 0
        self.velocity = Vec3(0, 0, 0)
        self.prev_click_time = time.time()
        self.double_click_distance = .5

        self.hovered_entity = None
        self.left = False
        self.right = False
        self.middle = False
        self.delta_drag = Vec3(0, 0, 0)

        self.i = 0
        self.update_rate = 10
        self._mouse_watcher = None
        self._picker = CollisionTraverser()  # Make a traverser
        self._pq = CollisionHandlerQueue()  # Make a handler
        self._pickerNode = CollisionNode('mouseRay')
        self._pickerNP = camera.attach_new_node(self._pickerNode)
        self._pickerRay = CollisionRay()  # Make our ray
        self._pickerNode.addSolid(self._pickerRay)
        self._picker.addCollider(self._pickerNP, self._pq)
        self.raycast = True
        self.collision = None
        self.enabled = True

    @property
    def x(self):
        if not self._mouse_watcher.has_mouse():
            return 0
        return self._mouse_watcher.getMouseX(
        ) / 2 * window.aspect_ratio  # same space as ui stuff

    @property
    def y(self):
        if not self._mouse_watcher.has_mouse():
            return 0
        return self._mouse_watcher.getMouseY() / 2

    def __setattr__(self, name, value):

        if name == 'visible':
            window.set_cursor_hidden(not value)
            application.base.win.requestProperties(window)

        if name == 'locked':
            try:
                object.__setattr__(self, name, value)
                window.set_cursor_hidden(value)
                application.base.win.requestProperties(window)
            except:
                pass

        try:
            super().__setattr__(name, value)
            # return
        except:
            pass

    def input(self, key):
        if not self.enabled:
            return

        if key.endswith('mouse down'):
            self.start_x = self.x
            self.start_y = self.y

        elif key.endswith('mouse up'):
            self.delta_drag = Vec3(self.x - self.start_x,
                                   self.y - self.start_y, 0)

        if key == 'left mouse down':
            self.left = True
            if self.hovered_entity:
                if hasattr(self.hovered_entity, 'on_click'):
                    self.hovered_entity.on_click()
                for s in self.hovered_entity.scripts:
                    if hasattr(s, 'on_click'):
                        s.on_click()
            # double click
            if time.time(
            ) - self.prev_click_time <= self.double_click_distance:
                base.input('double click')

                if self.hovered_entity:
                    if hasattr(self.hovered_entity, 'on_double_click'):
                        self.hovered_entity.on_double_click()
                    for s in self.hovered_entity.scripts:
                        if hasattr(s, 'on_double_click'):
                            s.on_double_click()

            self.prev_click_time = time.time()

        if key == 'left mouse up':
            self.left = False
        if key == 'right mouse down':
            self.right = True
        if key == 'right mouse up':
            self.right = False
        if key == 'middle mouse down':
            self.middle = True
        if key == 'middle mouse up':
            self.middle = False

    def update(self):
        if not self.enabled or not self._mouse_watcher.has_mouse():
            self.velocity = Vec3(0, 0, 0)
            return

        self.position = Vec3(self.x, self.y, 0)
        self.moving = self.x + self.y != self.prev_x + self.prev_y

        if self.moving:
            if self.locked:
                self.velocity = self.position
                application.base.win.move_pointer(0, int(window.size[0] / 2),
                                                  int(window.size[1] / 2))
            else:
                self.velocity = Vec3(self.x - self.prev_x,
                                     (self.y - self.prev_y) /
                                     window.aspect_ratio, 0)
        else:
            self.velocity = Vec3(0, 0, 0)

        if self.left or self.right or self.middle:
            self.delta = Vec3(self.x - self.start_x, self.y - self.start_y, 0)

        self.prev_x = self.x
        self.prev_y = self.y

        self.i += 1
        if self.i < self.update_rate:
            return
        # collide with ui
        self._pickerNP.reparent_to(scene.ui_camera)
        self._pickerRay.set_from_lens(camera._ui_lens_node,
                                      self.x * 2 / window.aspect_ratio,
                                      self.y * 2)
        self._picker.traverse(camera.ui)
        if self._pq.get_num_entries() > 0:
            # print('collided with ui', self._pq.getNumEntries())
            self.find_collision()
            return

        # collide with world
        self._pickerNP.reparent_to(camera)
        self._pickerRay.set_from_lens(scene.camera.lens_node,
                                      self.x * 2 / window.aspect_ratio,
                                      self.y * 2)
        self._picker.traverse(base.render)
        if self._pq.get_num_entries() > 0:
            # print('collided with world', self._pq.getNumEntries())
            self.find_collision()
            return
        # else:
        #     print('mouse miss', base.render)

        # unhover all if it didn't hit anything
        for entity in scene.entities:
            if hasattr(entity, 'hovered') and entity.hovered:
                entity.hovered = False
                self.hovered_entity = None
                if hasattr(entity, 'on_mouse_exit'):
                    entity.on_mouse_exit()
                for s in entity.scripts:
                    if hasattr(s, 'on_mouse_exit'):
                        s.on_mouse_exit()

    @property
    def normal(self):
        if not self.collision:
            return None
        if not self.collision.has_surface_normal():
            print('no surface normal')
            return None
        n = self.collision.get_surface_normal(
            self.collision.get_into_node_path().parent)
        return (n[0], n[2], n[1])

    @property
    def world_normal(self):
        if not self.collision:
            return None
        if not self.collision.has_surface_normal():
            print('no surface normal')
            return None
        n = self.collision.get_surface_normal(render)
        return (n[0], n[2], n[1])

    @property
    def point(self):
        if self.hovered_entity:
            p = self.collision.getSurfacePoint(self.hovered_entity)
            return Point3(p[0], p[2], p[1])
        else:
            return None

    @property
    def world_point(self):
        if self.hovered_entity:
            p = self.collision.getSurfacePoint(render)
            return Point3(p[0], p[2], p[1])
        else:
            return None

    def find_collision(self):
        if not self.raycast:
            return
        self._pq.sortEntries()
        if len(self._pq.get_entries()) == 0:
            self.collision = None
            return

        self.collisions = list()
        for entry in self._pq.getEntries():
            # print(entry.getIntoNodePath().parent)
            for entity in scene.entities:
                if entry.getIntoNodePath().parent == entity:
                    if entity.collision:
                        self.collisions.append(
                            Hit(
                                hit=entry.collided(),
                                entity=entity,
                                distance=0,
                                point=entry.getSurfacePoint(entity),
                                world_point=entry.getSurfacePoint(scene),
                                normal=entry.getSurfaceNormal(entity),
                                world_normal=entry.getSurfaceNormal(scene),
                            ))
                        break

        self.collision = self._pq.getEntry(0)
        nP = self.collision.getIntoNodePath().parent

        for entity in scene.entities:
            if not hasattr(entity, 'collision'
                           ) or not entity.collision or not entity.collider:
                continue
            # if hit entity is not hovered, call on_mouse_enter()
            if entity == nP:
                if not entity.hovered:
                    entity.hovered = True
                    self.hovered_entity = entity
                    # print(entity.name)
                    if hasattr(entity, 'on_mouse_enter'):
                        entity.on_mouse_enter()
                    for s in entity.scripts:
                        if hasattr(s, 'on_mouse_enter'):
                            s.on_mouse_enter()
            # unhover the rest
            else:
                if entity.hovered:
                    entity.hovered = False
                    if hasattr(entity, 'on_mouse_exit'):
                        entity.on_mouse_exit()
                    for s in entity.scripts:
                        if hasattr(s, 'on_mouse_exit'):
                            s.on_mouse_exit()
Example #30
0
class FlyThroughAir(ShowBase):
    # method completely taken from RoamingRalph demo:
    def addInstructions(self, pos, msg):
        return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=.05,
                            shadow=(0, 0, 0, 1), parent=base.a2dTopLeft,
                            pos=(0.08, -pos - 0.04), align=TextNode.ALeft)

    def setUpFlyingInstructions(self):
        self.inst[0] = self.addInstructions(.06, "Arrow Keys to move around")
        self.inst[1] = self.addInstructions(.12, "w and s to control pitch")
        self.inst[2] = self.addInstructions(.18, "a and d to control yaw")
        self.inst[3] = self.addInstructions(.24, "h to switch to driving mode")
        self.inst[4] = self.addInstructions(.3, "mouse click to add object")

    def destroyInstructions(self):
        # got way to destroy text from:
        # https://www.panda3d.org/manual/index.php/OnscreenText
        for element in self.inst:
            element.destroy()

    def setUpTreeButton(self):
        pass

    def setUpDrivingInstructions(self):
        self.inst[0] = self.addInstructions(.06, "Right arrow and left arrow to turn")
        self.inst[1] = self.addInstructions(.12, "Forward and Backward arrow to go forward and backward")
        self.inst[2] = self.addInstructions(.18, "h to switch to add object mode")

    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)

        # Set the background color to black
        self.win.setClearColor((0, 1, 1, 1))

        # This is used to store which keys are currently pressed.
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0,
            "backward": 0, "cam-up": 0, "cam-down": 0, "add-car": 0,
            "switch-mode":0, "mouse-click":0}

        # this is the egg that came with the module
        # environ = loader.loadModel("models/world")
        # this is the one I created using mountainMaker.py
        self.environ = loader.loadModel("TestMountain1")
        self.environ.reparentTo(render)

        self.car = loader.loadModel("TestCar")
        #self.car = loader.loadModel("testModel/ball")
        self.car.reparentTo(render)

        #instructions
        self.inst = [""]*5
        self.setUpFlyingInstructions()

        # for adjusting so that the position is the center of the car
        self.adjustedXForCenter = 10/2
        self.adjustedYForCenter = 20/2

        # important for setting the size relative to everything else
        # found it here : https://www.panda3d.org/manual/index.php/Common_State_Changes
        # set the mode that the player is currently in
        self.mode = 0
        self.modeFly = 0
        self.modeRace = 1

        # to ensure that when pressing h it only switches once each press
        self.hasSwitched = False

        self.carPositionX = 10
        self.carPositionY = 10
        self.carPositionZ = 100
        # note for rotating camera: from this website: 
        # https://www.panda3d.org/manual/index.php/Common_State_Changes
        # setHpr(Yaw, Pitch, Roll)

        # setting up initial conditions for which way camera is rotated
        self.carYaw = 0
        self.carPitch = 0

        self.setUpCarCollider()
        self.setUpMouseCollider()

        # make the rocks and other stuff that will show up
        self.objects = []

        # Accept the control keys for movement and rotation

        #setting up keys for movement
        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("arrow_down", self.setKey, ["backward", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("arrow_down-up", self.setKey, ["backward", False])

        # adding car
        self.accept("mouse1", self.setKey, ["mouse-click", True])
        self.accept("mouse1-up", self.setKey, ["mouse-click", False])

        # setting up orientation of the camera
        self.accept("a", self.setKey, ["cam-left", True])
        self.accept("s", self.setKey, ["cam-down", True])
        self.accept("a-up", self.setKey, ["cam-left", False])
        self.accept("s-up", self.setKey, ["cam-down", False])
        self.accept("d", self.setKey, ["cam-right", True])
        self.accept("d-up", self.setKey, ["cam-right", False])
        self.accept("w", self.setKey, ["cam-up", True])
        self.accept("w-up", self.setKey, ["cam-up", False])


        # to switch between tasks
        self.accept("h", self.setKey, ["switch-mode", True])
        self.accept("h-up", self.setKey, ["switch-mode", False])

        taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False

        self.cameraPositionX = 0
        self.cameraPositionY = 0
        self.cameraPositionZ = 0
        # note for rotating camera: from this website: 
        # https://www.panda3d.org/manual/index.php/Common_State_Changes
        # setHpr(Yaw, Pitch, Roll)
        
        # setting up initial conditions for which way camera is rotated
        self.cameraYaw = 0
        self.cameraPitch = 0
        
        # Set up the camera
        self.disableMouse()
        
        # should probably clean up these magic numbers
        self.camera.setPos(20, 20, 20)


        # Create some lighting
        # this is a part that is completely unchanged from demo
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def setUpCarCollider(self):
        self.carCollideTrav = CollisionTraverser()
        base.cTrav = self.carCollideTrav
        self.handler = CollisionHandlerQueue()
        self.carRay = CollisionRay(self.carPositionX, self.carPositionY, 
                                   self.carPositionZ, 0, 0, -1)
        self.carCollision = CollisionNode("groundCollision")
        self.carCollision.addSolid(self.carRay)
        # add to .egg <Scalar> collide-mask { 0x0 }
        #self.carCollision.setFromCollideMask(CollideMask.bit(0))
        #self.carCollision.setIntoCollideMask(CollideMask.allOff())
        self.carCollisionNode = self.car.attachNewNode(self.carCollision)
        self.carCollideTrav.addCollider(self.carCollisionNode, self.handler)
        self.carCollisionNode.show()

    def setUpMouseCollider(self):
        # clicking on objects stuff came from here:
        # https://www.panda3d.org/manual/index.php/Collision_Traversers
        # https://www.panda3d.org/manual/index.php/Collision_Handlers
        # will not use the traverser set up by car because slow
        # instead we will render each time clicked
        self.mouseCollideTrav = CollisionTraverser("mouseTraverse")
        self.mousehandler = CollisionHandlerQueue()
        # edit this so that from Object is the camera
        # self.mouseCollideTrav.addCollider(fromObject, queue)
        # self.mouseCollideTrav.traverse(render)
        # this next part came from:
        # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
        pickerNode = CollisionNode("mouseRay")
        pickerNp = camera.attachNewNode(pickerNode)
        pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.pickerRay = CollisionRay()
        pickerNode.addSolid(self.pickerRay)
        self.mouseCollideTrav.addCollider(pickerNp, self.mousehandler)
        

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    def move(self, task):
        if(self.mode==self.modeFly):
            # Get the time that elapsed since last frame.  We multiply this with
            # the desired speed in order to find out with which distance to move
            # in order to achieve that desired speed.
            dt = globalClock.getDt()

            if self.keyMap["switch-mode"] and not self.hasSwitched:
                self.mode = (self.mode+1)%2
                self.destroyInstructions()
                self.setUpDrivingInstructions()
                self.hasSwitched = True
            elif not self.keyMap["switch-mode"]:
                self.hasSwitched = False

            # the angle is in degrees with 360 equal to full rotation
            angleAdjustment = 100
            if self.keyMap["cam-left"]:
                self.cameraYaw += angleAdjustment*dt
            if self.keyMap["cam-right"]:
                self.cameraYaw -= angleAdjustment*dt
            if self.keyMap["cam-up"]:
                self.cameraPitch += angleAdjustment*dt
            if self.keyMap["cam-down"]:
                self.cameraPitch -= angleAdjustment*dt

            positionAdjustment = 500
            # should switch rad and Deg in variable name
            radToDeg = math.pi/180
            # the x and y component of left and right moves, do not need to 
            # compensate in z axis because not doing any roll, so there should be 
            # no zComponent
            xComponent = math.cos(self.cameraYaw*radToDeg)
            yComponent = math.sin(self.cameraYaw*radToDeg)
    
            if self.keyMap["left"]:
                self.cameraPositionX -= positionAdjustment * dt *xComponent
                self.cameraPositionY -= positionAdjustment * dt *yComponent
            if self.keyMap["right"]:
                self.cameraPositionX += positionAdjustment * dt*xComponent
                self.cameraPositionY += positionAdjustment * dt*yComponent
    
            # for going forward, the orientation is rotated 90 degrees so need to 
            # change components
            xComponent = math.cos(self.cameraYaw*radToDeg+math.pi/2)*math.cos(
                                                        self.cameraPitch*radToDeg)
            yComponent = math.sin(self.cameraYaw*radToDeg+math.pi/2)*math.cos(
                                                        self.cameraPitch*radToDeg)
            zComponent = math.sin(self.cameraPitch*radToDeg)

            if self.keyMap["forward"]:
                self.cameraPositionX += positionAdjustment * dt*xComponent
                self.cameraPositionY += positionAdjustment * dt*yComponent
                self.cameraPositionZ += positionAdjustment * dt*zComponent
            if self.keyMap["backward"]:
                self.cameraPositionX -= positionAdjustment * dt*xComponent
                self.cameraPositionY -= positionAdjustment * dt*yComponent
                self.cameraPositionZ -= positionAdjustment * dt*zComponent

            self.camera.setX(self.cameraPositionX)
            self.camera.setY(self.cameraPositionY)
            self.camera.setZ(self.cameraPositionZ)
            self.camera.setHpr(self.cameraYaw, self.cameraPitch, 0)

            # when implementing the use of the mouse look here:
            # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects

    
            # clicking on 3D objects comes from here:
            # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
            # checks if it needs to add any objects:
            if(self.keyMap["mouse-click"]):
                # found way to speed this up by only doing collision check
                # when mouse clicked by not using cTrav like in this method
                # the way I did it I found here:
                # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
                self.mouseCollideTrav.traverse(render)
                if(base.mouseWatcherNode.hasMouse()):
                    mousePos = base.mouseWatcherNode.getMouse()
                    self.pickerRay.setFromLens(base.camNode, mousePos.getX(), mousePos.getY())
                    if(self.mousehandler.getNumEntries()>0):
                        entries = list(self.mousehandler.getEntries())
                        # pathagorean formula for sorting
                        entries.sort(key=lambda x: ((x.getSurfacePoint(render).getX(
                                    )-self.cameraPositionX)**2 + 
                                    (x.getSurfacePoint(render).getY()-
                                    self.cameraPositionY)**2)**.5)
                        newX = entries[0].getSurfacePoint(render).getX()
                        newY = entries[0].getSurfacePoint(render).getY()
                        newZ = entries[0].getSurfacePoint(render).getZ()
                        self.objects.append(loader.loadModel("TestCar.egg"))
                        self.objects[len(self.objects)-1].reparentTo(render)
                        self.objects[len(self.objects)-1].setPos(newX, newY, newZ)
            return task.cont
        elif(self.mode == self.modeRace):
            # Get the time that elapsed since last frame.  We multiply this with
            # the desired speed in order to find out with which distance to move
            # in order to achieve that desired speed.
            dt = globalClock.getDt()

            degreeAdjustment = 60
            positionAdjustment = 100
            # should switch rad and Deg in variable name
            radToDeg = math.pi/180
            # the x and y component of left and right moves, do not need to 
            # compensate in z axis because not doing any roll, so there should be 
            # no zComponent

            xComponent = math.sin(self.carYaw*radToDeg)
            yComponent = math.cos(self.carYaw*radToDeg)

            if self.keyMap["switch-mode"] and not self.hasSwitched:
                self.mode = (self.mode+1)%2
                self.destroyInstructions()
                self.setUpFlyingInstructions()
                self.hasSwitched = True
            elif not self.keyMap["switch-mode"]:
                self.hasSwitched = False

            if self.keyMap["left"]:
                self.carYaw += degreeAdjustment * dt
            if self.keyMap["right"]:
                self.carYaw -= degreeAdjustment * dt
            if self.keyMap["forward"]:
                self.carPositionX -= positionAdjustment * dt*xComponent
                self.carPositionY += positionAdjustment * dt*yComponent
            if self.keyMap["backward"]:
                self.carPositionX += positionAdjustment * dt*xComponent
                self.carPositionY -= positionAdjustment * dt*yComponent

            # need to consider both the x and y component of offset for both
            # because x slowly changes to y as it turns

            actualXPos = (self.carPositionX+self.adjustedXForCenter*
                          math.cos(radToDeg*self.carYaw)+self.adjustedYForCenter
                          *math.sin(radToDeg*self.carYaw))
            actualYPos = (self.carPositionY+self.adjustedYForCenter*
                          math.cos(radToDeg*self.carYaw)+self.adjustedXForCenter
                          *math.sin(radToDeg*self.carYaw))
            self.car.setX(actualXPos)
            self.car.setY(actualYPos)
            self.car.setZ(self.carPositionZ)
            self.car.setHpr(self.carYaw, self.carPitch, 0)

            # when implementing the use of the mouse look here:
            # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
            
            # almost directly taken from ralph example
            entries = list(self.handler.getEntries())
            entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())
            # worry about which thing it collides with later
            if (len(entries) > 0):
                # and entries[0].getIntoNode().getName() == "mountainCollide":
                self.carPositionZ = (entries[0].getSurfacePoint(render).getZ())
            else:
                # because at 100 everything should be below car and do not want
                # to continually go up or else it may go up forever. 
                self.car.setZ(100)
                print("less")
            
            # Modify view of camera so that it is behind car
            distanceBehind = 40
            distanceAbove = 20
            self.camera.setHpr(self.carYaw, -.5, 0)
            camX = actualXPos + distanceBehind * math.sin(radToDeg*self.carYaw)
            camY = actualYPos - distanceBehind * math.cos(radToDeg*self.carYaw)
            camZ = self.carPositionZ + distanceAbove
            self.camera.setPos(camX, camY, camZ)
            return task.cont
Example #31
0
class World(ShowBase):

	def __init__(self):
		ShowBase.__init__(self)

		#PStatClient.connect()

		#self.lookPoint = NodePath(PandaNode("floater"))
		self.lookPoint = self.loader.loadModel("models/cone")
		self.lookPoint.reparentTo(render)

		self.menu = StartMenu(self)
		#self.bar = Bar()

		#self.messenger.toggleVerbose()


		#sys.exit()
		#pdb.set_trace()

		# Window change event handler
		#self.windowEventSetup()



	def setup(self):

		print("Init Levels...")
		self.initLevels()

		print("Init World...")
		self.initWorld("yard")

		print("Init Items...")
		self.initItems()

		print("Init Actors...")
		self.initActors()

		print("Init GUI ...")
		self.initGui()

		print("Init Lights...")
		self.initLights()

		print("Init Collisions...")
		self.initCollision()

		print("Init Tasks...")
		self.initTasks()

		print("Launching World")

		# Accept the control keys
		#self.accept("h", self.crono.start)

	def initItems(self):

		with open('items/items.json') as items_file:
			self.items = json.load(items_file)

	def initActors(self):

		self.player = Player(self, 20, 10, 10, 10, 10, 10) #app, hp, mana, strength, dexterity, vigor, magic):

		self.enemies = []
		self.npcs = []

		#Creating AI World

		self.AIworld = AIWorld(render)

		"""self.foe1 = Enemy(self, 100, 50, 5, 2, "bug") #(self, app, hp, mana, speed, attackSpeed, name):
		self.nasgul = Enemy(self, 100, 50, 5, 2, "nasgul")

		self.npc1 = Npc(self, 100, 50, 5, 2, "guy2")
		self.npc2 = Npc(self, 100, 50, 5, 2, "ralph")

		self.enemies.append(self.foe1)
		self.enemies.append(self.nasgul)

		self.npcs.append(self.npc1)
		self.npcs.append(self.npc2)"""


	def initGui(self):

		# Load the models.

		self.inventory = Inventory(self)
		self.status = Status(self)
		self.skills = Skills(self)

		#self.statusBar = self.loader.loadModel("models/statusbar")


		##self.statusBar.setDepthTest(True)
		#self.statusBar.setDepthWrite(True)


		# Reparent the model to render2d.
		#self.statusBar.reparentTo(self.render2d)


		#self.statusBar.setScale(0.15, 0.15, 0.15)
		#self.statusBar.setPos(-0.95, 0, 0.65)


		#self.crono = Crono(self)
		##self.cursorpos = CursorPos(self)
		#self.playerpos = PlayerPos(self)

		#self.crono.draw(0.7, -0.85)
		#self.cursorpos.draw(0.0, -0.85)
		#self.playerpos.draw(-0.7, -0.85)


		self.accept("i", self.inventory.toggle)
		self.accept("c", self.status.toggle)
		self.accept("k", self.skills.toggle)

	def initTasks(self):

		#self.taskMgr.add(self.crono.task, "cronoTask")
		#self.taskMgr.add(self.cursorpos.task, "cursorposTask")

		###self.taskMgr.add(self.playerpos.task, "playerposTask")

		self.taskMgr.add(self.checkCollision, "collisionTask")

		#self.taskMgr.add(self.player.update, "updateTask")
		self.taskMgr.add(self.player.move, "moveTask")
		self.taskMgr.add(self.player.updateCamera, "playerCameraTask",priority=1)
		"""
		#self.taskMgr.add(self.foe1.update, "bugTask",priority=1)
		#self.taskMgr.add(self.nasgul.update, "nasgulTask",priority=1)

		#self.taskMgr.add(self.npc1.update, "npc1Task",priority=1)
		#self.taskMgr.add(self.npc2.update, "npc2Task",priority=1)
		"""
		self.taskMgr.add(self.update, 'update')

	def initLights(self):
		# Create some lighting

		#self.environ.ls()

		#print(self.environ.findAllMatches("**/Spot"))

		ambientLight = AmbientLight("ambientLight")
		ambientLight.setColor(Vec4(0.8, 0.8, 0.8, 0.65))

		"""
		directionalLight = DirectionalLight("directionalLight")
		directionalLight.setDirection(Vec3(-10, -10, 5))
		directionalLight.showFrustum()
		directionalLight.setColor(Vec4(1, 1, 1, 1))
		directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
		dirnp = render.attachNewNode(directionalLight)
		dirnp.setPos(10, 0, 6)
		"""

		plight1 = PointLight('plight1')
		plight1.setColor(VBase4(1, 1, 1, 1))
		plight1.showFrustum()
		#plight1.setShadowCaster(True)
		plnp1 = render.attachNewNode(plight1)
		plnp1.setPos(26.71, -33.2, 26)

		plight2 = PointLight('plight2')
		plight2.setColor(VBase4(1, 1, 1, 1))
		plight2.showFrustum()
		plnp2 = render.attachNewNode(plight2)
		plnp2.setPos(-25, 25, 25)

		slight = Spotlight('slight')
		slight.setColor(VBase4(1, 1, 1, 1))
		lens = PerspectiveLens()
		lens.setFilmSize(1, 1)  # Or whatever is appropriate for your scene
		slight.setLens(lens)
		slight.setShadowCaster(True, 512, 512)
		slight.showFrustum()
		slnp = render.attachNewNode(slight)
		slnp.setPos(0, 0, 100)

		slnp.lookAt(Vec3(0,0,0))

		render.setLight(slnp)
		render.setLight(plnp1)
		render.setLight(plnp2)
		#render.setLight(render.attachNewNode(ambientLight))

		#render.setLight(dirnp)

		render.setShaderAuto()

		#render.setLight(render.attachNewNode(directionalLight))

		"""
		self.light = render.attachNewNode(Spotlight("Spot"))
		self.light.node().setScene(render)
		self.light.node().setShadowCaster(True)
		self.light.node().showFrustum()
		self.light.node().getLens().setFov(40)
		self.light.node().getLens().setNearFar(10,100)
		render.setLight(self.light)
		"""

	def initLevels(self):
		with open('levels/levels.json') as levels_file:
			self.levels = json.load(levels_file)

	def initWorld(self, level):

		self.environ = self.loader.loadModel(self.levels["levels"][level]["model"])
		#self.environ.setScale(20, 20, 20)
		#self.environ.setHpr(0, 0, 0)
		self.environ.setPos(0, 0, 0)

		self.playerStartPos = self.environ.find("**/startPos").getPos()

		# Reparent the model to render

		self.environ.reparentTo(render)
		#self.environ.ls()
		self.accept("q", self.changeMap)

	def destroyWorld(self):

		self.environ.detachNode()
		self.environ.removeNode()

	def changeMap(self):#, levelName):
		self.destroyWorld()
		self.initWorld("yard")

	def update(self, task):
		dt = globalClock.getDt()

		self.AIworld.update()
		return task.cont

	def setKey(self, key, value):
		self.keyMap[key] = value

	def windowEventSetup( self ):
		# accept the window event's
		self.accept( 'window-event', self.windowEventHandler)
		# create a window event yourself
		#messenger.send( 'window-event', [self.win] )

	def windowEventHandler( self, window=None ):
		wp = window.getProperties()

		print("Window changed")
		print("X = %s" % wp.getXSize())
		print("Y = %s" % wp.getYSize())
		self.setResolution( wp.getXSize(), wp.getYSize() )

	def setResolution( self, w, h ):
		wp = WindowProperties()
		wp.setSize( w, h )

		if os.name == 'posix':
			self.openMainWindow()
			self.graphicsEngine.openWindows()
		self.win.requestProperties( wp )

	# Define a procedure to move the camera.
	def spinCameraTask(self, task):
		angleDegrees = task.time * 6.0
		angleRadians = angleDegrees * (pi / 180.0)
		self.camera.setPos(40 * sin(angleRadians), -10.0 * cos(angleRadians), 3)
		self.camera.setHpr(angleDegrees, 0, 0)
		return Task.cont

	def initCollision(self):


		self.enemyGroundRay = []
		self.enemyGroundCol = []
		self.enemyGroundColNp = []
		self.enemyGroundHandler = []

		self.npcGroundRay = []
		self.npcGroundCol = []
		self.npcGroundColNp = []
		self.npcGroundHandler = []

		self.cTrav = CollisionTraverser()


		self.playerGroundRay = CollisionRay()
		self.playerGroundRay.setOrigin(0, 0, 9)
		self.playerGroundRay.setDirection(0, 0, -1)
		self.playerGroundCol = CollisionNode('playerRay')
		self.playerGroundCol.addSolid(self.playerGroundRay)
		self.playerGroundCol.setFromCollideMask(CollideMask.bit(0))
		self.playerGroundCol.setIntoCollideMask(CollideMask.allOff())
		self.playerGroundColNp = self.player.moveFloater.attachNewNode(self.playerGroundCol)
		self.playerGroundHandler = CollisionHandlerQueue()
		self.cTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler)

		self.mouseGroundRay = CollisionRay()
		self.mouseGroundRay.setOrigin(0, 0, 9)
		self.mouseGroundRay.setDirection(0, 0, -1)
		self.mouseGroundCol = CollisionNode('mouseRay')
		self.mouseGroundCol.addSolid(self.mouseGroundRay)
		self.mouseGroundCol.setFromCollideMask(CollideMask.bit(0))
		self.mouseGroundCol.setIntoCollideMask(CollideMask.allOff())
		self.mouseGroundColNp = self.camera.attachNewNode(self.mouseGroundCol)
		self.mouseGroundHandler = CollisionHandlerQueue()
		self.cTrav.addCollider(self.mouseGroundColNp, self.mouseGroundHandler)

		# Uncomment this line to see the collision rays
		#self.playerGroundColNp.show()
		#self.mouseGroundColNp.show()

		# Uncomment this line to show a visual representation of the
		# collisions occuring
		#self.cTrav.showCollisions(render)


		i = 0
		for enemy in self.enemies:

			self.enemyGroundRay.append(CollisionRay())
			self.enemyGroundRay[i].setOrigin(0, 0, 9)
			self.enemyGroundRay[i].setDirection(0, 0, -1)

			self.enemyGroundCol.append(CollisionNode('%sRay' % enemy.name))
			self.enemyGroundCol[i].addSolid(self.enemyGroundRay[i])
			self.enemyGroundCol[i].setFromCollideMask(CollideMask.bit(0))
			self.enemyGroundCol[i].setIntoCollideMask(CollideMask.allOff())

			self.enemyGroundColNp.append(enemy.enemyActor.attachNewNode(self.enemyGroundCol[i]))
			self.enemyGroundHandler.append(CollisionHandlerQueue())
			self.cTrav.addCollider(self.enemyGroundColNp[i], self.enemyGroundHandler[i])

			#self.enemyGroundColNp.show()
			i += 1

		i = 0
		for npc in self.npcs:

			self.npcGroundRay.append(CollisionRay())
			self.npcGroundRay[i].setOrigin(0, 0, 9)
			self.npcGroundRay[i].setDirection(0, 0, -1)

			self.npcGroundCol.append(CollisionNode('%sRay' % npc.name))
			self.npcGroundCol[i].addSolid(self.npcGroundRay[i])
			self.npcGroundCol[i].setFromCollideMask(CollideMask.bit(0))
			self.npcGroundCol[i].setIntoCollideMask(CollideMask.allOff())

			self.npcGroundColNp.append(npc.npcActor.attachNewNode(self.npcGroundCol[i]))
			self.npcGroundHandler.append(CollisionHandlerQueue())
			self.cTrav.addCollider(self.npcGroundColNp[i], self.npcGroundHandler[i])

			#self.npcGroundColNp.show()
			i += 1

	def checkCollision(self, task):

		startpos = self.player.moveFloater.getPos()

		entries = list(self.playerGroundHandler.getEntries())
		entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

		for entry in entries:
			if entry > 0 and entries[0].getIntoNode().getName() == "Ground":
				self.player.moveFloater.setZ(entry.getSurfacePoint(render).getZ())
			else:
				self.player.moveFloater.setPos(startpos)

		if self.mouseWatcherNode.hasMouse():

			mpos = self.mouseWatcherNode.getMouse()

			self.mouseGroundRay.setFromLens(self.camNode, mpos.getX(), mpos.getY())


			nearPoint = render.getRelativePoint(self.camera, self.mouseGroundRay.getOrigin())
			nearVec = render.getRelativeVector(self.camera, self.mouseGroundRay.getDirection())
			try:
				self.lookPoint.setPos(PointAtZ(self.player.moveFloater.getZ(), nearPoint, nearVec))
			except:
				pass

		i = 0

		for enemy in self.enemies:
			startpos = enemy.enemyActor.getPos()

			entries = list(self.enemyGroundHandler[i].getEntries())
			entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

			for entry in entries:
				if entry > 0: # and entries[0].getIntoNode().getName() == "Ground":
					enemy.enemyActor.setZ(entry.getSurfacePoint(render).getZ())
				else:
					enemy.enemyActor.setPos(startpos)
			i += 1


		i = 0
		for npc in self.npcs:
			startpos = npc.npcActor.getPos()

			entries = list(self.npcGroundHandler[i].getEntries())
			entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

			for entry in entries:
				if entry > 0: # and entries[0].getIntoNode().getName() == "Ground":
					npc.npcActor.setZ(entry.getSurfacePoint(render).getZ())
				else:
					npc.npcActor.setPos(startpos)
			i += 1

		return task.cont
Example #32
0
class MousePicker(object):
    def __init__(self,
                 pickTag='MyPickingTag',
                 nodeName='pickRay',
                 showCollisions=False):
        self.pickTag = pickTag
        self.nodeName = nodeName
        self.showCollisions = showCollisions

    def create(self):
        self.mPickerTraverser = CollisionTraverser()
        self.mCollisionQue = CollisionHandlerQueue()

        self.mPickRay = CollisionRay()
        self.mPickRay.setOrigin(base.camera.getPos(base.render))
        self.mPickRay.setDirection(
            base.render.getRelativeVector(base.camera, Vec3(0, 1, 0)))

        #create our collison Node to hold the ray
        self.mPickNode = CollisionNode(self.nodeName)
        self.mPickNode.addSolid(self.mPickRay)

        #Attach that node to the camera since the ray will need to be positioned
        #relative to it, returns a new nodepath
        #well use the default geometry mask
        #this is inefficent but its for mouse picking only

        self.mPickNP = base.camera.attachNewNode(self.mPickNode)

        #we'll use what panda calls the "from" node.  This is reall a silly convention
        #but from nodes are nodes that are active, while into nodes are usually passive environments
        #this isnt a hard rule, but following it usually reduces processing

        #Everything to be picked will use bit 1. This way if we were doing other
        #collision we could seperate it, we use bitmasks to determine what we check other objects against
        #if they dont have a bitmask for bit 1 well skip them!
        self.mPickNode.setFromCollideMask(BitMask32(1))

        #Register the ray as something that can cause collisions
        self.mPickerTraverser.addCollider(self.mPickNP, self.mCollisionQue)

        #Setup 2D picker
        self.mPickerTraverser2D = CollisionTraverser()
        self.mCollisionQue2D = CollisionHandlerQueue()

        self.mPickNode2D = CollisionNode('2D PickNode')
        self.mPickNode2D.setFromCollideMask(BitMask32(1))
        self.mPickNode2D.setIntoCollideMask(BitMask32.allOff())

        self.mPick2DNP = base.camera2d.attachNewNode(self.mPickNode2D)

        self.mPickRay2D = CollisionRay()
        self.mPickNode2D.addSolid(self.mPickRay2D)

        self.mPickerTraverser2D.addCollider(self.mPick2DNP,
                                            self.mCollisionQue2D)

        if self.showCollisions:
            self.mPickerTraverser.showCollisions(base.render)
            self.mPickerTraverser2D.showCollisions(base.aspect2d)

    def mousePick(self, traverse=None, tag=None):
        #do we have a mouse
        if (base.mouseWatcherNode.hasMouse() == False):
            return None, None

        traverse = traverse or base.render
        tag = tag or self.pickTag

        mpos = base.mouseWatcherNode.getMouse()

        #Set the position of the ray based on the mouse position
        self.mPickRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
        self.mPickerTraverser.traverse(traverse)

        if (self.mCollisionQue.getNumEntries() > 0):
            self.mCollisionQue.sortEntries()

            for entry in self.mCollisionQue.getEntries():
                pickedObj = entry.getIntoNodePath()
                pickedObj = pickedObj.findNetTag(tag)

                if not pickedObj.isEmpty():
                    pos = entry.getSurfacePoint(base.render)
                    return pickedObj, pos

        return None, None

    def mousePick2D(self, traverse=None, tag=None, all=False):
        #do we have a mouse
        if (base.mouseWatcherNode.hasMouse() == False):
            return None, None

        traverse = traverse or base.render
        tag = tag or self.pickTag

        mpos = base.mouseWatcherNode.getMouse()

        self.mPickRay2D.setFromLens(base.cam2d.node(), mpos.getX(),
                                    mpos.getY())

        self.mPickerTraverser2D.traverse(base.aspect2d)

        if self.mCollisionQue2D.getNumEntries() > 0:
            self.mCollisionQue2D.sortEntries()

            if all:
                return [(entry.getIntoNodePath().findNetTag(tag),
                         entry.getSurfacePoint(base.aspect2d))
                        for entry in self.mCollisionQue2D.getEntries()], None
            else:
                entry = self.mCollisionQue2D.getEntry(0)
                pickedObj = entry.getIntoNodePath()

                pickedObj = pickedObj.findNetTag(tag)
                if not pickedObj.isEmpty():
                    pos = entry.getSurfacePoint(base.aspect2d)
                    return pickedObj, pos

        return None, None
Example #33
0
class PandaPath(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)

        # Set the background color to black
        self.win.setClearColor((0, 0, 0, 1))

        # This is used to store which keys are currently pressed.
        self.key_map = {"left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0}

        # Post the Instruction
        self.title = add_title("Panda 3D Demo")

        # Instructions
        self.inst1 = add_instructions(0.06, "[ESC]: Quit")
        self.inst2 = add_instructions(0.12, "[Left Arrow]: Rotate Left")
        self.inst3 = add_instructions(0.18, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = add_instructions(0.24, "[Up Arrow]: Run Ralph Forward")
        # self.inst6 = add_instructions(0.30, "[A]: Rotate Camera Left")
        # self.inst7 = add_instructions(0.36, "[S]: Rotate Camera Right")

        # Load the Environment Model
        self.environ = self.loader.loadModel(ENVIRONMENT)
        # Reparent the model to the render controller
        self.environ.reparentTo(render)

        # Apply scale and position transform on the model
        # self.environ.setScale(0.25, 0.25, 0.25)
        # self.environ.setPos(-8, 42, 0)

        # Create the Main Character
        # Load and transform the panda actor
        ralph_start_pos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor(RALPH_ACTOR, RALPH_ACTIONS)

        # self.ralph.setScale(0.005, 0.005, 0.005)
        self.ralph.reparentTo(render)
        # Loop it's animation
        self.ralph.setScale(0.2)
        self.ralph.setPos(ralph_start_pos + (0, 0, 0.5))
        # self.ralph.loop("walk")

        # Create a floater object, which floats 2 units above rlaph. We use this as a target for the camera to look at
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(self.ralph)
        # 2 Units above Ralph
        self.floater.setZ(2.0)

        # Configure the Camera
        # Add the spin camera taks procedure to the taks manager
        # self.taskMgr.add(self.spinCameraTask, "SpinCameraTask")

        # Accept certain control keys
        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.set_key, ["left", True])
        self.accept("arrow_right", self.set_key, ["right", True])
        self.accept("arrow_up", self.set_key, ["forward", True])
        self.accept("a", self.set_key, ["cam-left", True])
        self.accept("s", self.set_key, ["cam-right", True])
        self.accept("arrow_left-up", self.set_key, ["left", False])
        self.accept("arrow_right-up", self.set_key, ["right", False])
        self.accept("arrow_up-up", self.set_key, ["forward", False])
        self.accept("a-up", self.set_key, ["cam-left", False])
        self.accept("s-up", self.set_key, ["cam-right", False])

        # Game States
        taskMgr.add(self.move, "moveTask")
        self.is_moving = False

        self.disableMouse()
        self.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 2)
        self.camera.lookAt(self.floater)

        """
        Detect the height of hte terrain by creating a collision ray and casting it down towards the terrain.

        One ray will start above ralph's head and the other will start above the camera.
        A ray may hit the terrain, or it may hit a rock or a tree.
        If it hits the terrain we ca ndetect the height.

        If it hits anything else, we rule that the move is illegal.
        """
        self.cTrav = CollisionTraverser()

        # Create a vector, it's location is at the top of ralph's head
        self.ralph_ground_ray = CollisionRay()
        self.ralph_ground_ray.setOrigin(0, 0, 9)  # Top of ralph's head
        self.ralph_ground_ray.setDirection(0, 0, -1)  # Points -Z axis

        # Create a Collision node
        self.ralph_ground_col = CollisionNode("ralph_ray")  # Give the node a name
        self.ralph_ground_col.addSolid(self.ralph_ground_ray)  # the vector from ralph's head to the ground is solid
        self.ralph_ground_col.setFromCollideMask(CollideMask.bit(0))  # ??
        self.ralph_ground_col.setIntoCollideMask(
            CollideMask.allOff()
        )  # ?? This seems like it defines the behavior of ray
        self.ralph_ground_col_np = self.ralph.attachNewNode(self.ralph_ground_col)  # Attach the ray to ralph
        self.ralph_ground_handler = (
            CollisionHandlerQueue()
        )  # I think that when a collision occurs it sends through this
        self.cTrav.addCollider(self.ralph_ground_col_np, self.ralph_ground_handler)  # Attach the collision

        """
        Attach the a camera ray to the camera
        """
        self.cam_ground_ray = CollisionRay()
        self.cam_ground_ray.setOrigin(0, 0, 9)
        self.cam_ground_ray.setDirection(0, 0, -1)
        self.cam_ground_col = CollisionNode("camera_ray")
        self.cam_ground_col.addSolid(self.cam_ground_ray)
        self.cam_ground_col.setFromCollideMask(CollideMask.bit(0))
        self.cam_ground_col.setIntoCollideMask(CollideMask.allOff())
        self.cam_ground_col_np = self.camera.attachNewNode(self.cam_ground_col)
        self.cam_ground_handler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.cam_ground_col_np, self.cam_ground_handler)

        # Uncomment the following lines to view the rays
        self.ralph_ground_col_np.show()
        self.cam_ground_col_np.show()

        # Uncomment this line to show a visual representation of the Collision occuring
        self.cTrav.showCollisions(render)

        # Create some lighting
        ambient_light = AmbientLight("ambient_light")
        ambient_light.setColor((0.3, 0.3, 0.3, 1))
        directional_light = DirectionalLight("directional_light")
        directional_light.setDirection((-5, -5, -5))
        directional_light.setColor((1, 1, 1, 1))
        directional_light.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambient_light))
        render.setLight(render.attachNewNode(directional_light))

        # Add Cube
        X_OFFSET = 0
        Y_OFFSET = -3
        Z_OFFSET = 1

        CUBE_SIZE = 2

        x, y, z = ralph_start_pos
        x += X_OFFSET
        y += Y_OFFSET
        z += Z_OFFSET

        # make_cube(x, y, z, CUBE_SIZE)

    def set_key(self, key, value):
        self.key_map[key] = value

    def move(self, task):
        dt = globalClock.getDt()
        # print "DT: %f" % dt

        # ****: Movement
        # Get Ralph's position before we do anything to it
        start_pos = self.ralph.getPos()

        # User wants to turn
        if self.key_map["left"]:
            self.ralph.setH(self.ralph.getH() + 300 * dt)
        if self.key_map["right"]:
            self.ralph.setH(self.ralph.getH() - 300 * dt)

        # Perform a move forward
        if self.key_map["forward"]:
            self.ralph.setY(self.ralph, -25 * dt)

        # ****: Animation
        if self.key_map["forward"] or self.key_map["left"] or self.key_map["right"]:
            if not self.is_moving:
                self.ralph.loop("run")
                self.is_moving = True

        else:
            if self.is_moving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.is_moving = False

        # ****: Camera Movement
        if self.key_map["cam-left"]:
            self.camera.setX(self.camera, -20 * dt)
        elif self.key_map["cam-right"]:
            self.camera.setX(self.camera, +20 * dt)

        # If the camera is too far from ralph, move it closer
        # If the camera is too close to ralph, move it farther
        camvec = self.ralph.getPos() - self.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if camdist > 10.0:
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0
        if camdist < 5.0:
            self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist))
            camdist - 5.0

        # ****: Collision
        """
        Normally, we would have to call traverse() to check for collisions.

        However, the class ShowBase that we inherit from has a task to do this for us

        If we assign a CollisionTraverser to self.cTrav

        Adjust ralph's Z coordinate. If ralph's ray hit terrain update his Z.

        If it hit anything else, or didn't hit anything put him back where he was last frame.
        """

        entries = list(self.ralph_ground_handler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())
        # print "Entry count: %d" % len(entries)

        if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain":
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(start_pos)

        # Keep the camera at one foot above the terrain or two feet above ralph, whichever is greater
        entries = list(self.cam_ground_handler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain":
            self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)
        if self.camera.getZ() < self.ralph.getZ() + 2.0:
            self.camera.setZ(self.ralph.getZ() + 2.0)

        """
        The camera should look in rlaphs direction, but it should also try to stay horizontal so look at a
        floater which hovers above ralph's head
        """
        self.camera.lookAt(self.floater)
        return task.cont
Example #34
0
class Raycaster(Entity):
    def __init__(self):
        super().__init__(name='raycaster', eternal=True)
        self._picker = CollisionTraverser()  # Make a traverser
        self._pq = CollisionHandlerQueue()  # Make a handler
        self._pickerNode = CollisionNode('raycaster')
        self._pickerNode.set_into_collide_mask(0)
        self._pickerNP = self.attach_new_node(self._pickerNode)
        self._picker.addCollider(self._pickerNP, self._pq)
        self._pickerNP.show()

    def distance(self, a, b):
        return math.sqrt(sum((a - b)**2 for a, b in zip(a, b)))

    def raycast(self,
                origin,
                direction=(0, 0, 1),
                distance=math.inf,
                traverse_target=scene,
                ignore=list(),
                debug=False):
        self.position = origin
        self.look_at(self.position + direction)
        self._pickerNode.clearSolids()
        # if thickness == (0,0):
        if distance == math.inf:
            ray = CollisionRay()
            ray.setOrigin(Vec3(0, 0, 0))
            ray.setDirection(Vec3(0, 1, 0))
        else:
            ray = CollisionSegment(Vec3(0, 0, 0), Vec3(0, distance, 0))

        self._pickerNode.addSolid(ray)

        if debug:
            self._pickerNP.show()
        else:
            self._pickerNP.hide()

        self._picker.traverse(traverse_target)

        if self._pq.get_num_entries() == 0:
            self.hit = Hit(hit=False)
            return self.hit

        ignore += tuple([e for e in scene.entities if not e.collision])

        self._pq.sort_entries()
        self.entries = [  # filter out ignored entities
            e for e in self._pq.getEntries()
            if e.get_into_node_path().parent not in ignore
        ]

        if len(self.entries) == 0:
            self.hit = Hit(hit=False)
            return self.hit

        self.collision = self.entries[0]
        nP = self.collision.get_into_node_path().parent
        point = self.collision.get_surface_point(nP)
        point = Vec3(point[0], point[2], point[1])
        world_point = self.collision.get_surface_point(render)
        world_point = Vec3(world_point[0], world_point[2], world_point[1])
        hit_dist = self.distance(self.world_position, world_point)

        if nP.name.endswith('.egg'):
            nP = nP.parent

        self.hit = Hit(hit=True)
        for e in scene.entities:
            if e == nP:
                # print('cast nP to Entity')
                self.hit.entity = e

        self.hit.point = point
        self.hit.world_point = world_point
        self.hit.distance = hit_dist

        normal = self.collision.get_surface_normal(
            self.collision.get_into_node_path().parent)
        self.hit.normal = (normal[0], normal[2], normal[1])

        normal = self.collision.get_surface_normal(render)
        self.hit.world_normal = (normal[0], normal[2], normal[1])
        return self.hit

        self.hit = Hit(hit=False)
        return self.hit

    def boxcast(self,
                origin,
                direction=(0, 0, 1),
                distance=math.inf,
                thickness=(1, 1),
                traverse_target=scene,
                ignore=list(),
                debug=False):
        if isinstance(thickness, (int, float, complex)):
            thickness = (thickness, thickness)
        resolution = 3
        rays = list()
        debugs = list()

        for y in range(3):
            for x in range(3):
                pos = origin + Vec3(
                    lerp(-(thickness[0] / 2), thickness[0] / 2, x / (3 - 1)),
                    lerp(-(thickness[1] / 2), thickness[1] / 2, y /
                         (3 - 1)), 0)
                ray = self.raycast(pos, direction, distance, traverse_target,
                                   ignore, False)
                rays.append(ray)

                if debug and ray.hit:
                    d = Entity(model='cube',
                               origin_z=-.5,
                               position=pos,
                               scale=(.02, .02, distance),
                               ignore=True)
                    d.look_at(pos + Vec3(direction))
                    debugs.append(d)
                    # print(pos, hit.point)
                    if ray.hit and ray.distance > 0:
                        d.scale_z = ray.distance
                        d.color = color.green

        from ursina import destroy
        # [destroy(e, 1/60) for e in debugs]

        rays.sort(key=lambda x: x.distance)
        closest = rays[0]

        return Hit(
            hit=sum([int(e.hit) for e in rays]) > 0,
            entity=closest.entity,
            point=closest.point,
            world_point=closest.world_point,
            distance=closest.distance,
            normal=closest.normal,
            world_normal=closest.world_normal,
            hits=[e.hit for e in rays],
            entities=list(set([e.entity
                               for e in rays])),  # get unique entities hit
        )
Example #35
0
class RoamingRalphDemo(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)

        # Set the background color to black
        self.win.setClearColor((0, 0, 0, 1))

        # This is used to store which keys are currently pressed.
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0}

        # Post the instructions
        self.title = addTitle(
            "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.06, "[ESC]: Quit")
        self.inst2 = addInstructions(0.12, "[Left Arrow]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.18, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.24, "[Up Arrow]: Run Ralph Forward")
        self.inst6 = addInstructions(0.30, "[A]: Rotate Camera Left")
        self.inst7 = addInstructions(0.36, "[S]: Rotate Camera Right")

        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)

        # Create the main character, Ralph

        ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor("models/ralph",
                           {"run": "models/ralph-run",
                            "walk": "models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos + (0, 0, 0.5))

        # Create a floater object, which floats 2 units above ralph.  We
        # use this as a target for the camera to look at.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(self.ralph)
        self.floater.setZ(2.0)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("a", self.setKey, ["cam-left", True])
        self.accept("s", self.setKey, ["cam-right", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("a-up", self.setKey, ["cam-left", False])
        self.accept("s-up", self.setKey, ["cam-right", False])

        taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera
        self.disableMouse()
        self.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 2)




        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above ralph's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.
        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 9)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.ralphGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 9)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.camGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.camGroundColNp = self.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # Uncomment this line to see the collision rays
        #self.ralphGroundColNp.show()
        #self.camGroundColNp.show()

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #self.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):

        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        if self.keyMap["cam-left"]:
            self.camera.setX(self.camera, -20 * dt)
        if self.keyMap["cam-right"]:
            self.camera.setX(self.camera, +20 * dt)

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if self.keyMap["left"]:
            self.ralph.setH(self.ralph.getH() + 300 * dt)
        if self.keyMap["right"]:
            self.ralph.setH(self.ralph.getH() - 300 * dt)
        if self.keyMap["forward"]:
            self.ralph.setY(self.ralph, -25 * dt)

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"]:
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - self.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if camdist > 10.0:
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0
        if camdist < 5.0:
            self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist))
            camdist = 5.0

        # Normally, we would have to call traverse() to check for collisions.
        # However, the class ShowBase that we inherit from has a task to do
        # this for us, if we assign a CollisionTraverser to self.cTrav.
        #self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = list(self.ralphGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain":
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.

        entries = list(self.camGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain":
            self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)
        if self.camera.getZ() < self.ralph.getZ() + 2.0:
            self.camera.setZ(self.ralph.getZ() + 2.0)

        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.
        self.camera.lookAt(self.floater)

        return task.cont
Example #36
0
class Demo(ShowBase):
    _speed = 25

    def reset(self):
        x = random.random() * 40 - 20
        y = random.random() * 40 - 20
        self.ralph.setPos((x, y, 0))

    def __init__(self, img_size=512, screen_off=True):
        self.img_size = img_size
        loadPrcFileData("", "transform-cache false")
        loadPrcFileData("", "audio-library-name null")  # Prevent ALSA errors
        loadPrcFileData("", "win-size %d %d" % (img_size, img_size))
        loadPrcFileData("", "parallax-mapping-samples 3\n"
                            "parallax-mapping-scale 0.1")

        if screen_off:
            # Spawn an offscreen buffer
            loadPrcFileData("", "window-type offscreen")
        # Initialize the ShowBase class from which we inherit, which will
        # create a window and set up everything we need for rendering into it.
        ShowBase.__init__(self)

        # Load the 'abstract room' model.  This is a model of an
        # empty room containing a pillar, a pyramid, and a bunch
        # of exaggeratedly bumpy textures.

        self.room = loader.loadModel("models/abstractroom")
        self.room.reparentTo(render)

        # Create the main character, Ralph

        self.ralph = Actor("models/ralph",
                           {"run": "models/ralph-run",
                            "walk": "models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.reset()

        self.pieces = [Piece(self.room) for _ in range(200)]
        ##################################################
        cnodePath = self.room.attachNewNode(CollisionNode('cnode'))
        plane = CollisionPlane(Plane(Vec3(1, 0, 0), Point3(-60, 0, 0)))  # left
        cnodePath.node().addSolid(plane)
        plane = CollisionPlane(
            Plane(Vec3(-1, 0, 0), Point3(60, 0, 0)))  # right
        cnodePath.node().addSolid(plane)
        plane = CollisionPlane(Plane(Vec3(0, 1, 0), Point3(0, -60, 0)))  # back
        cnodePath.node().addSolid(plane)
        plane = CollisionPlane(
            Plane(Vec3(0, -1,  0), Point3(0, 60,  0)))  # front
        cnodePath.node().addSolid(plane)

        sphere = CollisionSphere(-25, -25, 0, 12.5)
        cnodePath.node().addSolid(sphere)

        box = CollisionBox(Point3(5, 5, 0), Point3(45, 45, 10))
        cnodePath.node().addSolid(box)

        # Make the mouse invisible, turn off normal mouse controls
        self.disableMouse()
        self.camLens.setFov(80)

        # Set the current viewing target
        self.focus = LVector3(55, -55, 20)
        self.heading = 180
        self.pitch = 0
        self.mousex = 0
        self.mousey = 0
        self.last = 0
        self.mousebtn = [0, 0, 0]

        # Add a light to the scene.
        self.lightpivot = render.attachNewNode("lightpivot")
        self.lightpivot.setPos(0, 0, 25)
        self.lightpivot.hprInterval(10, LPoint3(360, 0, 0)).loop()
        plight = PointLight('plight')
        plight.setColor((5, 5, 5, 1))
        plight.setAttenuation(LVector3(0.7, 0.05, 0))
        plnp = self.lightpivot.attachNewNode(plight)
        plnp.setPos(45, 0, 0)
        self.room.setLight(plnp)

        # Add an ambient light
        alight = AmbientLight('alight')
        alight.setColor((0.2, 0.2, 0.2, 1))
        alnp = render.attachNewNode(alight)
        self.room.setLight(alnp)

        # Create a sphere to denote the light
        sphere = loader.loadModel("models/icosphere")
        sphere.reparentTo(plnp)

        self.cameraModel = self.ralph
        camera.reparentTo(self.cameraModel)
        camera.setZ(2)

        self.cTrav = CollisionTraverser()

        cs = CollisionSphere(0, 0, 0, 1)
        cnodePath = self.ralph.attachNewNode(CollisionNode('cnode'))
        cnodePath.node().addSolid(cs)

        cnodePath.show()
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(cnodePath, self.ralphGroundHandler)

        self.cnodePath = cnodePath

        # Tell Panda that it should generate shaders performing per-pixel
        # lighting for the room.
        self.room.setShaderAuto()

        self.shaderenable = 1

        tex = Texture()
        self.depthmap = tex
        tex.setFormat(Texture.FDepthComponent)
        altBuffer = self.win.makeTextureBuffer(
            "hello", img_size, img_size, tex, True)
        self.altBuffer = altBuffer
        altCam = self.makeCamera(altBuffer)
        altCam.reparentTo(self.ralph)  # altRender)
        altCam.setZ(2)
        l = altCam.node().getLens()
        l.setFov(80)
        ################### end init

    def step(self, rotation):
        dt = 0.02

        self.ralph.setH(self.ralph.getH() + rotation * dt)
        self.ralph.setY(self.ralph, self._speed * dt)
        for _ in range(5):
            random.choice(self.pieces).step(dt)

        f = taskMgr.getAllTasks()[-1].getFunction()
        f(None)
        f = taskMgr.getAllTasks()[2].getFunction()
        f(None)
        entries = (self.ralphGroundHandler.getEntries())
        if len(entries) > 0:
            self.reset()
            return 1
        else:
            return 0

    def resetGame(self):
        while True:
            self.reset()
            for p in self.pieces:
                p.reset()
            if 0 == self.step(0):
                break

    def renderFrame(self):
        base.graphicsEngine.renderFrame()

    def getDepthMapT(self):
        tex = self.depthmap
        #tex = self.altBuffer.getTexture()
        r = tex.getRamImage()
        s = r.getData()
        i = np.fromstring(s, dtype='float32')
        i = i.reshape((self.img_size, self.img_size))
        i = np.flipud(i)
        return i
Example #37
0
class RoamingRalphDemo(ShowBase):
    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)

        # Set the background color to black
        self.win.setClearColor((0, 0, 0, 1))

        # This is used to store which keys are currently pressed.
        self.keyMap = {
            "left": 0,
            "right": 0,
            "forward": 0,
            "cam-left": 0,
            "cam-right": 0
        }

        # Post the instructions
        self.title = addTitle(
            "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.06, "[ESC]: Quit")
        self.inst2 = addInstructions(0.12, "[Left Arrow]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.18, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.24, "[Up Arrow]: Run Ralph Forward")
        self.inst6 = addInstructions(0.30, "[A]: Rotate Camera Left")
        self.inst7 = addInstructions(0.36, "[S]: Rotate Camera Right")

        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)

        # Create the main character, Ralph

        ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor("models/ralph", {
            "run": "models/ralph-run",
            "walk": "models/ralph-walk"
        })
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos + (0, 0, 0.5))

        # Create a floater object, which floats 2 units above ralph.  We
        # use this as a target for the camera to look at.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(self.ralph)
        self.floater.setZ(2.0)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("a", self.setKey, ["cam-left", True])
        self.accept("s", self.setKey, ["cam-right", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("a-up", self.setKey, ["cam-left", False])
        self.accept("s-up", self.setKey, ["cam-right", False])

        taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera
        self.disableMouse()
        self.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 2)

        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above ralph's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.
        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 9)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.ralphGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 9)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.camGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.camGroundColNp = self.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # Uncomment this line to see the collision rays
        #self.ralphGroundColNp.show()
        #self.camGroundColNp.show()

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #self.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):

        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        if self.keyMap["cam-left"]:
            self.camera.setX(self.camera, -20 * dt)
        if self.keyMap["cam-right"]:
            self.camera.setX(self.camera, +20 * dt)

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if self.keyMap["left"]:
            self.ralph.setH(self.ralph.getH() + 300 * dt)
        if self.keyMap["right"]:
            self.ralph.setH(self.ralph.getH() - 300 * dt)
        if self.keyMap["forward"]:
            self.ralph.setY(self.ralph, -25 * dt)

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap[
                "right"]:
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - self.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if camdist > 10.0:
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0
        if camdist < 5.0:
            self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist))
            camdist = 5.0

        # Normally, we would have to call traverse() to check for collisions.
        # However, the class ShowBase that we inherit from has a task to do
        # this for us, if we assign a CollisionTraverser to self.cTrav.
        #self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = list(self.ralphGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName(
        ) == "terrain":
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.

        entries = list(self.camGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

        if len(entries) > 0 and entries[0].getIntoNode().getName(
        ) == "terrain":
            self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)
        if self.camera.getZ() < self.ralph.getZ() + 2.0:
            self.camera.setZ(self.ralph.getZ() + 2.0)

        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.
        self.camera.lookAt(self.floater)

        return task.cont
Example #38
0
class RoamingRalphDemo(CosmoniumBase):

    def get_local_position(self):
        return base.camera.get_pos()

    def create_terrain_appearance(self):
        self.terrain_appearance.set_shadow(self.shadow_caster)

    def create_terrain_heightmap(self):
        self.heightmap = PatchedHeightmap('heightmap',
                                          self.noise_size,
                                          self.height_scale,
                                          self.size,
                                          self.size,
                                          True,
                                          ShaderHeightmapPatchFactory(self.noise))

    def create_terrain_biome(self):
        self.biome = PatchedHeightmap('biome',
                                      self.biome_size,
                                      1.0,
                                      self.size,
                                      self.size,
                                      False,
                                      ShaderHeightmapPatchFactory(self.biome_noise))

    def create_terrain_shader(self):
#         control4 = HeightColorMap('colormap',
#                 [
#                  ColormapLayer(0.00, top=LRGBColor(0, 0.1, 0.24)),
#                  ColormapLayer(0.40, top=LRGBColor(0, 0.1, 0.24)),
#                  ColormapLayer(0.49, top=LRGBColor(0, 0.6, 0.6)),
#                  ColormapLayer(0.50, bottom=LRGBColor(0.9, 0.8, 0.6), top=LRGBColor(0.5, 0.4, 0.3)),
#                  ColormapLayer(0.80, top=LRGBColor(0.2, 0.3, 0.1)),
#                  ColormapLayer(0.90, top=LRGBColor(0.7, 0.6, 0.4)),
#                  ColormapLayer(1.00, bottom=LRGBColor(1, 1, 1), top=LRGBColor(1, 1, 1)),
#                 ])
        appearance = DetailMap(self.terrain_control, self.heightmap, create_normals=True)
        data_source = [HeightmapDataSource(self.heightmap, PatchedGpuTextureSource, filtering=HeightmapDataSource.F_none),
                       HeightmapDataSource(self.biome, PatchedGpuTextureSource, filtering=HeightmapDataSource.F_none),
                       TextureDictionaryDataSource(self.terrain_appearance, TextureDictionaryDataSource.F_hash)]
        if settings.allow_tesselation:
            tesselation_control = ConstantTesselationControl(invert_v=False)
        else:
            tesselation_control = None
        if self.fog is not None:
            after_effects = [Fog(**self.fog)]
        else:
            after_effects = None
        self.terrain_shader = BasicShader(appearance=appearance,
                                          tesselation_control=tesselation_control,
                                          geometry_control=DisplacementGeometryControl(self.heightmap),
                                          data_source=data_source,
                                          after_effects=after_effects)

    def create_tile(self, x, y):
        self.terrain_shape.add_root_patch(x, y)

    def create_terrain(self):
        self.tile_factory = TileFactory(self.tile_density, self.size, self.has_water, self.water)
        self.terrain_shape = TiledShape(self.tile_factory, self.size, self.max_lod, lod_control=VertexSizeMaxDistancePatchLodControl(self.max_distance, self.max_vertex_size))
        self.create_terrain_heightmap()
        self.create_terrain_biome()
        self.create_terrain_appearance()
        self.create_terrain_shader()
        self.terrain = HeightmapSurface(
                               'surface',
                               0,
                               self.terrain_shape,
                               self.heightmap,
                               self.biome,
                               self.terrain_appearance,
                               self.terrain_shader,
                               self.size,
                               clickable=False,
                               average=True)
        self.terrain.set_parent(self)
        self.terrain.create_instance()

    def toggle_water(self):
        if not self.has_water: return
        self.water.visible = not self.water.visible
        self.terrain_shape.check_settings()

    def get_height(self, position):
        height = self.terrain.get_height(position)
        if self.has_water and self.water.visible and height < self.water.level:
            height = self.water.level
        return height

    #Used by populator
    def get_height_patch(self, patch, u, v):
        height = self.terrain.get_height_patch(patch, u, v)
        if self.has_water and self.water.visible and height < self.water.level:
            height = self.water.level
        return height

    def skybox_init(self):
        skynode = base.cam.attachNewNode('skybox')
        self.skybox = loader.loadModel('ralph-data/models/rgbCube')
        self.skybox.reparentTo(skynode)

        self.skybox.setTextureOff(1)
        self.skybox.setShaderOff(1)
        self.skybox.setTwoSided(True)
        # make big enough to cover whole terrain, else there'll be problems with the water reflections
        self.skybox.setScale(1.5* self.size)
        self.skybox.setBin('background', 1)
        self.skybox.setDepthWrite(False)
        self.skybox.setDepthTest(False)
        self.skybox.setLightOff(1)
        self.skybox.setShaderOff(1)
        self.skybox.setFogOff(1)

        #self.skybox.setColor(.55, .65, .95, 1.0)
        self.skybox_color = LColor(pow(0.5, 1/2.2), pow(0.6, 1/2.2), pow(0.7, 1/2.2), 1.0)
        self.skybox.setColor(self.skybox_color)

    def objects_density_for_patch(self, patch):
        scale = 1 << patch.lod
        return int(self.objects_density / scale + 1.0)

    def create_populator(self):
        if settings.allow_instancing:
            TerrainPopulator = GpuTerrainPopulator
        else:
            TerrainPopulator = CpuTerrainPopulator
        self.rock_collection = TerrainPopulator(RockFactory(self), self.objects_density_for_patch, self.objects_density, RandomObjectPlacer(self))
        self.tree_collection = TerrainPopulator(TreeFactory(self), self.objects_density_for_patch, self.objects_density, RandomObjectPlacer(self))
        self.object_collection = MultiTerrainPopulator()
        self.object_collection.add_populator(self.rock_collection)
        self.object_collection.add_populator(self.tree_collection)

    def set_light_angle(self, angle):
        self.light_angle = angle
        self.light_quat.setFromAxisAngleRad(angle * pi / 180, LVector3.forward())
        self.light_dir = self.light_quat.xform(LVector3.up())
        cosA = self.light_dir.dot(LVector3.up())
        self.vector_to_star = self.light_dir
        if self.shadow_caster is not None:
            self.shadow_caster.set_direction(-self.light_dir)
        if self.directionalLight is not None:
            self.directionalLight.setDirection(-self.light_dir)
        if cosA >= 0:
            coef = sqrt(cosA)
            self.light_color = (1, coef, coef, 1)
            self.directionalLight.setColor(self.light_color)
            self.skybox.setColor(self.skybox_color * cosA)
        else:
            self.light_color = (1, 0, 0, 1)
            self.directionalLight.setColor(self.light_color)
            self.skybox.setColor(self.skybox_color * 0)
        self.update()

    def update(self):
        self.object_collection.update_instance()
        self.terrain.update_instance(None, None)

    def apply_instance(self, instance):
        pass

    def create_instance_delayed(self):
        pass

    def get_apparent_radius(self):
        return 0

    def get_name(self):
        return "terrain"

    def is_emissive(self):
        return False

    def __init__(self):
        CosmoniumBase.__init__(self)

        config = RalphConfigParser()
        (self.noise, self.biome_noise, self.terrain_control, self.terrain_appearance, self.water, self.fog) = config.load_and_parse('ralph-data/ralph.yaml')

        self.tile_density = 64
        self.default_size = 128
        self.max_vertex_size = 64
        self.max_lod = 10

        self.size = 128 * 8
        self.max_distance = 1.001 * self.size * sqrt(2)
        self.noise_size = 512
        self.biome_size = 128
        self.noise_scale = 0.5 * self.size / self.default_size
        self.objects_density = int(25 * (1.0 * self.size / self.default_size) * (1.0 * self.size / self.default_size))
        self.objects_density = 250
        self.height_scale = 100 * 5.0
        self.has_water = True
        self.fullscreen = False
        self.shadow_caster = None
        self.light_angle = None
        self.light_dir = LVector3.up()
        self.vector_to_star = self.light_dir
        self.light_quat = LQuaternion()
        self.light_color = (1.0, 1.0, 1.0, 1.0)
        self.directionalLight = None
        self.shadow_size = self.default_size / 8
        self.shadow_box_length = self.height_scale

        self.observer = RalphCamera(self.cam, self.camLens)
        self.observer.init()

        self.distance_to_obs = float('inf')
        self.height_under = 0.0
        self.scene_position = LVector3()
        self.scene_scale_factor = 1
        self.scene_orientation = LQuaternion()

        #Size of an edge seen from 4 units above
        self.edge_apparent_size = (1.0 * self.size / self.tile_density) / (4.0 * self.observer.pixel_size)
        print("Apparent size:", self.edge_apparent_size)

        self.win.setClearColor((135.0/255, 206.0/255, 235.0/255, 1))

        # This is used to store which keys are currently pressed.
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "backward": 0,
            "cam-left": 0, "cam-right": 0, "cam-up": 0, "cam-down": 0,
            "sun-left": 0, "sun-right": 0,
            "turbo": 0}

        # Set up the environment
        #
        # Create some lighting
        self.vector_to_obs = base.cam.get_pos()
        self.vector_to_obs.normalize()
        if True:
            self.shadow_caster = ShadowCaster(1024)
            self.shadow_caster.create()
            self.shadow_caster.set_lens(self.shadow_size, -self.shadow_box_length / 2.0, self.shadow_box_length / 2.0, -self.light_dir)
            self.shadow_caster.set_pos(self.light_dir * self.shadow_box_length / 2.0)
            self.shadow_caster.bias = 0.1
        else:
            self.shadow_caster = None

        self.ambientLight = AmbientLight("ambientLight")
        self.ambientLight.setColor((settings.global_ambient, settings.global_ambient, settings.global_ambient, 1))
        self.directionalLight = DirectionalLight("directionalLight")
        self.directionalLight.setDirection(-self.light_dir)
        self.directionalLight.setColor(self.light_color)
        self.directionalLight.setSpecularColor(self.light_color)
        render.setLight(render.attachNewNode(self.ambientLight))
        render.setLight(render.attachNewNode(self.directionalLight))

        render.setShaderAuto()
        base.setFrameRateMeter(True)

        self.create_terrain()
        self.create_populator()
        self.terrain_shape.set_populator(self.object_collection)
        self.create_tile(0, 0)
        self.skybox_init()

        self.set_light_angle(45)

        # Create the main character, Ralph

        ralphStartPos = LPoint3()
        self.ralph = Actor("ralph-data/models/ralph",
                           {"run": "ralph-data/models/ralph-run",
                            "walk": "ralph-data/models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos + (0, 0, 0.5))
        self.ralph_shape = InstanceShape(self.ralph)
        self.ralph_shape.parent = self
        self.ralph_shape.set_owner(self)
        self.ralph_shape.create_instance()
        self.ralph_appearance = ModelAppearance(self.ralph)
        self.ralph_appearance.set_shadow(self.shadow_caster)
        self.ralph_shader = BasicShader()
        self.ralph_appearance.bake()
        self.ralph_appearance.apply(self.ralph_shape, self.ralph_shader)
        self.ralph_shader.apply(self.ralph_shape, self.ralph_appearance)
        self.ralph_shader.update(self.ralph_shape, self.ralph_appearance)

        # Create a floater object, which floats 2 units above ralph.  We
        # use this as a target for the camera to look at.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(self.ralph)
        self.floater.setZ(2.0)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("control-q", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("arrow_down", self.setKey, ["backward", True])
        self.accept("shift", self.setKey, ["turbo", True])
        self.accept("a", self.setKey, ["cam-left", True], direct=True)
        self.accept("s", self.setKey, ["cam-right", True], direct=True)
        self.accept("u", self.setKey, ["cam-up", True], direct=True)
        self.accept("u-up", self.setKey, ["cam-up", False])
        self.accept("d", self.setKey, ["cam-down", True], direct=True)
        self.accept("d-up", self.setKey, ["cam-down", False])
        self.accept("o", self.setKey, ["sun-left", True], direct=True)
        self.accept("o-up", self.setKey, ["sun-left", False])
        self.accept("p", self.setKey, ["sun-right", True], direct=True)
        self.accept("p-up", self.setKey, ["sun-right", False])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("arrow_down-up", self.setKey, ["backward", False])
        self.accept("shift-up", self.setKey, ["turbo", False])
        self.accept("a-up", self.setKey, ["cam-left", False])
        self.accept("s-up", self.setKey, ["cam-right", False])
        self.accept("w", self.toggle_water)
        self.accept("h", self.print_debug)
        self.accept("f2", self.connect_pstats)
        self.accept("f3", self.toggle_filled_wireframe)
        self.accept("shift-f3", self.toggle_wireframe)
        self.accept("f5", self.bufferViewer.toggleEnable)
        self.accept("f8", self.terrain_shape.dump_tree)
        self.accept('alt-enter', self.toggle_fullscreen)

        taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera
        self.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 2)
        self.camera_height = 2.0
        render.set_shader_input("camera", self.camera.get_pos())

        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 9)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(CollideMask.bit(0))
        self.ralphGroundCol.setIntoCollideMask(CollideMask.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        # Uncomment this line to see the collision rays
        #self.ralphGroundColNp.show()

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #self.cTrav.showCollisions(render)

        #self.terrain_shape.test_lod(LPoint3d(*self.ralph.getPos()), self.distance_to_obs, self.pixel_size, self.terrain_appearance)
        #self.terrain_shape.update_lod(LPoint3d(*self.ralph.getPos()), self.distance_to_obs, self.pixel_size, self.terrain_appearance)
        #self.terrain.shape_updated()
        self.terrain.update_instance(LPoint3d(*self.ralph.getPos()), None)

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):

        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        if self.keyMap["cam-left"]:
            self.camera.setX(self.camera, -20 * dt)
        if self.keyMap["cam-right"]:
            self.camera.setX(self.camera, +20 * dt)
        if self.keyMap["cam-up"]:
            self.camera_height *= (1 + 2 * dt)
        if self.keyMap["cam-down"]:
            self.camera_height *= (1 - 2 * dt)
        if self.camera_height < 1.0:
            self.camera_height = 1.0

        if self.keyMap["sun-left"]:
            self.set_light_angle(self.light_angle + 30 * dt)
        if self.keyMap["sun-right"]:
            self.set_light_angle(self.light_angle - 30 * dt)

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        delta = 25
        if self.keyMap["turbo"]:
            delta *= 10
        if self.keyMap["left"]:
            self.ralph.setH(self.ralph.getH() + 300 * dt)
        if self.keyMap["right"]:
            self.ralph.setH(self.ralph.getH() - 300 * dt)
        if self.keyMap["forward"]:
            self.ralph.setY(self.ralph, -delta * dt)
        if self.keyMap["backward"]:
            self.ralph.setY(self.ralph, delta * dt)

        #self.limit_pos(self.ralph)

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if self.keyMap["forward"] or self.keyMap["backward"] or self.keyMap["left"] or self.keyMap["right"]:
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - self.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if camdist > 10.0:
            self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0
        if camdist < 5.0:
            self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist))
            camdist = 5.0

        # Normally, we would have to call traverse() to check for collisions.
        # However, the class ShowBase that we inherit from has a task to do
        # this for us, if we assign a CollisionTraverser to self.cTrav.
        self.cTrav.traverse(render)

        if False:
            # Adjust ralph's Z coordinate.  If ralph's ray hit anything, put
            # him back where he was last frame.

            entries = list(self.ralphGroundHandler.getEntries())
            entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

            if len(entries) > 0:
                self.ralph.setPos(startpos)
        ralph_height = self.get_height(self.ralph.getPos())
        self.ralph.setZ(ralph_height)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.

        camera_height = self.get_height(self.camera.getPos()) + 1.0
        if camera_height < ralph_height + self.camera_height:
            self.camera.setZ(ralph_height + self.camera_height)
        else:
            self.camera.setZ(camera_height)
        #self.limit_pos(self.camera)

        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.
        self.camera.lookAt(self.floater)

        #self.shadow_caster.set_pos(self.ralph.get_pos())
        self.shadow_caster.set_pos(self.ralph.get_pos() - camvec * camdist + camvec * self.shadow_size / 2)

        render.set_shader_input("camera", self.camera.get_pos())
        self.vector_to_obs = base.cam.get_pos()
        self.vector_to_obs.normalize()

        if self.isMoving:
            #self.terrain_shape.test_lod(LPoint3d(*self.ralph.getPos()), self.distance_to_obs, self.pixel_size, self.terrain_appearance)
            pass#self.terrain_shape.update_lod(LPoint3d(*self.ralph.getPos()), self.distance_to_obs, self.pixel_size, self.terrain_appearance)

        self.object_collection.update_instance()
        self.terrain.update_instance(LPoint3d(*self.ralph.getPos()), None)
        return task.cont

    def print_debug(self):
        print("Height:", self.get_height(self.ralph.getPos()), self.terrain.get_height(self.ralph.getPos()))
        print("Ralph:", self.ralph.get_pos())
        print("Camera:", base.camera.get_pos())
Example #39
0
class Raycaster(Entity):
    line_model = Mesh(vertices=[Vec3(0, 0, 0), Vec3(0, 0, 1)], mode='line')
    _boxcast_box = Entity(model='cube',
                          origin_z=-.5,
                          collider='box',
                          color=color.white33,
                          enabled=False)

    def __init__(self):
        super().__init__(name='raycaster', eternal=True)
        self._picker = CollisionTraverser()  # Make a traverser
        self._pq = CollisionHandlerQueue()  # Make a handler
        self._pickerNode = CollisionNode('raycaster')
        self._pickerNode.set_into_collide_mask(0)
        self._pickerNP = self.attach_new_node(self._pickerNode)
        self._picker.addCollider(self._pickerNP, self._pq)

    def distance(self, a, b):
        return sqrt(sum((a - b)**2 for a, b in zip(a, b)))

    def raycast(self,
                origin,
                direction=(0, 0, 1),
                distance=inf,
                traverse_target=scene,
                ignore=list(),
                debug=False):
        self.position = origin
        self.look_at(self.position + direction)

        self._pickerNode.clearSolids()
        ray = CollisionRay()
        ray.setOrigin(Vec3(0, 0, 0))
        ray.setDirection(Vec3(0, 0, 1))

        self._pickerNode.addSolid(ray)

        if debug:
            temp = Entity(position=origin,
                          model=Raycaster.line_model,
                          scale=Vec3(1, 1, min(distance, 9999)),
                          add_to_scene_entities=False)
            temp.look_at(self.position + direction)
            destroy(temp, 1 / 30)

        self._picker.traverse(traverse_target)

        if self._pq.get_num_entries() == 0:
            self.hit = HitInfo(hit=False, distance=distance)
            return self.hit

        ignore += tuple([e for e in scene.entities if not e.collision])

        self._pq.sort_entries()
        self.entries = [  # filter out ignored entities
            e for e in self._pq.getEntries()
            if e.get_into_node_path().parent not in ignore and self.distance(
                self.world_position, Vec3(
                    *e.get_surface_point(render))) <= distance
        ]

        if len(self.entries) == 0:
            self.hit = HitInfo(hit=False, distance=distance)
            return self.hit

        self.collision = self.entries[0]
        nP = self.collision.get_into_node_path().parent
        point = Vec3(*self.collision.get_surface_point(nP))
        world_point = Vec3(*self.collision.get_surface_point(render))
        hit_dist = self.distance(self.world_position, world_point)

        self.hit = HitInfo(hit=True, distance=distance)
        for e in scene.entities:
            if e == nP:
                self.hit.entity = e

        nPs = [e.get_into_node_path().parent for e in self.entries]
        self.hit.entities = [e for e in scene.entities if e in nPs]

        self.hit.point = point
        self.hit.world_point = world_point
        self.hit.distance = hit_dist

        self.hit.normal = Vec3(*self.collision.get_surface_normal(
            self.collision.get_into_node_path().parent).normalized())
        self.hit.world_normal = Vec3(
            *self.collision.get_surface_normal(render).normalized())
        return self.hit

        self.hit = HitInfo(hit=False, distance=distance)
        return self.hit

    def boxcast(self,
                origin,
                direction=(0, 0, 1),
                distance=9999,
                thickness=(1, 1),
                traverse_target=scene,
                ignore=list(),
                debug=False):  # similar to raycast, but with width and height
        if isinstance(thickness, (int, float, complex)):
            thickness = (thickness, thickness)

        Raycaster._boxcast_box.enabled = True
        Raycaster._boxcast_box.collision = True
        Raycaster._boxcast_box.position = origin
        Raycaster._boxcast_box.scale = Vec3(abs(thickness[0]),
                                            abs(thickness[1]), abs(distance))
        Raycaster._boxcast_box.always_on_top = debug
        Raycaster._boxcast_box.visible = debug

        Raycaster._boxcast_box.look_at(origin + direction)
        hit_info = Raycaster._boxcast_box.intersects(
            traverse_target=traverse_target, ignore=ignore)
        if hit_info.world_point:
            hit_info.distance = ursinamath.distance(origin,
                                                    hit_info.world_point)
        else:
            hit_info.distance = distance

        if debug:
            Raycaster._boxcast_box.collision = False
            Raycaster._boxcast_box.scale_z = hit_info.distance
            invoke(setattr, Raycaster._boxcast_box, 'enabled', False, delay=.2)
        else:
            Raycaster._boxcast_box.enabled = False

        return hit_info
Example #40
0
class Picker(Viewer):
    """ View and click objects in a scene."""
    def __init__(self):
        # Parent init.
        super(Picker, self).__init__()
        self.disableMouse()
        # Picker stuff.
        self.contact_margin = Vec3(0.01, 0.01, 0.01)
        self.parser = None
        self.marked = None
        self.attached_pairs = set()
        self.contacts = None
        self.contact_points = None
        self.contact_bottoms = None
        self.compound_components = []
        self.compound_objects = []
        self.joints = JointManager()
        self.wire_attrib = RenderModeAttrib.make(RenderModeAttrib.MWireframe,
                                                 4.)
        self.attachment_colors = (Vec4(0.1, 0.1, 1.,
                                       1.), Vec4(0.1, 0.8, 0.1,
                                                 1.), Vec4(1., 0.1, 1., 1.),
                                  Vec4(1., 0.5, 0.1, 1.), Vec4(1., 1., 1., 1.))
        self.max_attach = 999
        self.permanent_events += ["mouse1"]
        # Make cursor dot.
        self.cursor = self._build_cursor("cross")
        s = 0.08
        self.cursor.setScale(s, s, s)
        self.cursor.setColor(1, 1, 1, 1)
        self.cursor.reparentTo(self.aspect2d)
        self.taskMgr.add(self.draw_cursor2d, "draw_cursor2d")
        self.permanent_tasks.append("draw_cursor2d")

    def init_ssos(self, *args, **kwargs):
        super(Picker, self).init_ssos(*args, **kwargs)

    def init_physics(self, *args, **kwargs):
        super(Picker, self).init_physics(*args, **kwargs)
        self.joints.bbase = self.bbase

    def init_picker(self):
        # Collision traverser
        self.traverser = CollisionTraverser("traverser")
        # Collision handler
        self.handler = CollisionHandlerQueue()
        # Initialize and set up picker ray node and NodePath
        self.picker = CollisionNode("mouse_ray")
        self.pickerNP = self.camera.attachNewNode(self.picker)
        self.picker.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.picker_ray = CollisionRay()
        self.picker.addSolid(self.picker_ray)
        self.traverser.addCollider(self.pickerNP, self.handler)
        mark_color = (1, 1, 1, 0.3)
        self.base_mark = self.create_mark(color=mark_color)
        connector_color = (1, 1, 1, 1)
        self.base_connector = self.create_connector(color=connector_color)

    def _build_cursor(self, shape="sphere"):
        if shape == "sphere":
            cursor = self._load("sphere.bam")
        elif shape == "cross":
            cursor = LineNodePath()
            lines = [[Point3(-0.5, 0, 0),
                      Point3(0.5, 0, 0)],
                     [Point3(0, 0, -0.5),
                      Point3(0, 0, 0.5)]]
            cursor.drawLines(lines)
            cursor.setThickness(1)
            cursor.create()
            # cursor = NodePath("cross")
            # S = {"cylinderX.bam": ((0., 0., 0.), (1., 0.1, 0.1)),
            #      "cylinderY.bam": ((0., 0., 0.), (0.1, 1., 0.1)),
            #      "cylinderZ.bam": ((0., 0., 0.), (0.1, 0.1, 1.))}
            # for k, v in S.iteritems():
            #     m = self._load(k)
            #     m.setName(k)
            #     m.setPos(*v[0])
            #     m.setScale(*v[1])
            #     m.reparentTo(cursor)
        #BP()
        return cursor

    def create_mark(self, color):
        """ Makes a graphical mark object."""
        # Make a graphical box.
        props = dict(name="mark", color=color, model="box-round.egg")
        obj = GSO(props=props)
        return obj

    def create_connector(self, color):
        """ Makes a graphical connector object."""
        # Make a graphical box.
        props = dict(name="connector", color=color, model="connector.egg")
        obj = GSO(props=props)
        return obj

    def start_picker(self, pickables):
        # Set pickable objs.
        for i, obj in enumerate(pickables):
            obj.setTag("pickable", str(i))
        # Add mouse events.
        self.accept("mouse1", self.clicked, extraArgs=[1])
        # Start contact detector.
        detector = ContactDetector(self.bbase.world,
                                   self.scene,
                                   margin=self.contact_margin)
        self.contacts = detector.contacts
        self.contact_bodies = detector.bodies
        self.contact_points = detector.points
        parser = Parser(self.contacts, self.contact_bodies)
        self.contact_bottoms = parser.bottom_bodies
        self.connectors = {}

    def stop_picker(self):
        self.removeTask("mouse1")

    def goto_sso(self, *args, **kwargs):
        self.clear_attachments()
        self.stop_picker()
        super(Picker, self).goto_sso(*args, **kwargs)
        self.remove_physics()
        # Start picker.
        pickables = self.sso.descendants(type_=PSO)
        self.start_picker(pickables)
        self.attach_physics()

    def get_picked_obj(self):
        mpos = self.mouseWatcherNode.getMouse()
        self.picker_ray.setFromLens(self.cam.node(), mpos.getX(), mpos.getY())
        self.traverser.traverse(self.render)
        if self.handler.getNumEntries() > 0:
            # This is so we get the closest object
            self.handler.sortEntries()
            entries = self.handler.getEntries()
            for entry in entries:
                picked_obj = entry.getIntoNodePath().findNetTag("pickable")
                if not picked_obj.isEmpty():
                    break
            if picked_obj.isEmpty():
                picked_obj = None
        else:
            picked_obj = None
        return picked_obj

    def clicked(self, button):
        """ Mouse click handler."""
        if self.mouseWatcherNode.hasMouse():
            # Get picked object
            picked_obj = self.get_picked_obj()
            if picked_obj is not None:
                if self.marked is None:
                    # New mark activated.
                    self.marked = picked_obj
                    self.show_marked(picked_obj, True)
                    event = "mark"
                elif picked_obj == self.marked:
                    # Existing mark deactivated.
                    self.show_marked(picked_obj, False)
                    self.marked = None
                    event = "unmark"
                else:
                    # New attachment or detachment.
                    pair = tuple(sorted((self.marked, picked_obj)))
                    ij = tuple(
                        sorted((self.contact_bodies.index(pair[0]),
                                self.contact_bodies.index(pair[1]))))
                    if ij in self.contacts:
                        f_add = (ij, pair) not in self.attached_pairs
                        if (not f_add
                                or len(self.attached_pairs) < self.max_attach):
                            self.store_attachment(ij, pair, f_add)
                            self.show_marked(self.marked, False)
                            self.marked = None
                            event = "attach" if f_add else "detach"
                        else:
                            print("Max attachments already reached.")
                            event = "max-attach"
                    else:
                        event = "non-contact"
            else:
                event = "non-pick"
            return picked_obj, event

    def store_attachment(self, ij, pair, f_add):
        """ Stores the attached objects, and draws them."""
        if f_add:
            self.attached_pairs.add((ij, pair))
            self.show_attachment(ij, True)
            self.attach_pair(pair, True)
        else:
            try:
                self.attached_pairs.remove((ij, pair))
            except KeyError:
                pass
            else:
                self.attach_pair(pair, False)
                self.show_attachment(ij, False)

    def clear_attachments(self):
        """ Clear all attachments."""
        if self.marked:
            self.show_marked(self.marked, False)
            self.marked = None
            self.mark = None
        for ij, pair in self.attached_pairs:
            self.attach_pair(pair, False)
            self.show_attachment(ij, False)
        self.attached_pairs = set()
        #
        self.reset_compounds()
        self.contacts = None
        self.contact_bodies = None
        self.contact_points = None
        self.contact_bottoms = None

    def _make_mark(self, node, extent, name):
        """ Makes a mark GSO."""
        mark = self.base_mark.copy()
        mat = node.getMat(self.scene)
        mark.apply_prop(dict(name=name), other=self.scene)
        mark.setMat(self.scene, mat)
        mark.setScale(self.scene, mark.getScale(self.scene) + extent)
        mark.wrtReparentTo(node)
        return mark

    def show_marked(self, node, f_on):
        """ Turns on/off marked graphic."""
        if f_on:
            extent = Vec3(0.15, 0.15, 0.15)
            name = "mark"
            self.mark = self._make_mark(node, extent, name)
            self.mark.init_tree(tags=("model", ))
            # Exclude object from casting shadows
            self.mark.hide(self.shadow_mask)
            self.mark.setTransparency(TransparencyAttrib.MAlpha)
            self.mark.setDepthWrite(False)
            self.mark.setBin("fixed", 0, priority=5)
        else:
            self.mark.removeNode()

    def _make_connector(self, parent, points, extent, name):
        """ Makes connector object."""
        connector = self.base_connector.copy()
        scale = Vec3(*(np.ptp(points, axis=0)))
        scale_extended = scale + extent
        pos = Point3(*(np.min(points, axis=0) + scale / 2.))
        connector.apply_prop(dict(name=name, scale=scale_extended, pos=pos),
                             other=self.scene)
        connector.wrtReparentTo(parent)
        return connector

    def show_attachment(self, ij, f_on):
        """ Turns on/off attachment graphic."""
        if f_on:
            parent = self.contact_bottoms[ij]
            points = self.contact_points[ij]
            extent = Vec3(0.15, 0.15, 0.15)
            name = "connector_%d-%d" % ij
            self.connectors[ij] = self._make_connector(parent, points, extent,
                                                       name)
            self.connectors[ij].init_tree(tags=("model", ))
        else:
            self.connectors.pop(ij).removeNode()

    # def attach_pair(self, pair, f_on):
    #     """ Adds/removes physical attachment between a pair of nodes."""
    #     key = tuple(sorted(p.node() for p in pair))
    #     # key = frozenset(pair)
    #     if f_on:
    #         # Create the joint and add it.
    #         self.joints[key] = self.joints.make_fixed(*pair)
    #     else:
    #         # Remove it.
    #         del self.joints[key]

    def attach_physics(self):
        # Attach `self.scene` to the physics world.
        try:
            exclude = zip(*self.compound_components)[0]
        except IndexError:
            exclude = []
        bnodes = [
            bnode for bnode in self.scene.descendants(type_=PSO)
            if bnode not in exclude
        ]
        for bnode in bnodes:
            bnode.init_resources(tags=("shape", ))
            bnode.setCollideMask(BitMask32.allOn())
            bnode.node().setDeactivationEnabled(False)
        self.bbase.attach(bnodes)

    def reset_compounds(self):
        for n, p in self.compound_components:
            n.wrtReparentTo(p)
        self.compound_components = []
        for cnode in self.compound_objects:
            cnode.destroy_resources()
            cnode.removeNode()
        self.compound_objects = []

    def make_attachment_graph(self):
        if not self.contact_bodies:
            return None
        n = len(self.contact_bodies)
        mtx = np.zeros((n, n), dtype="i")
        for (i, j), _ in self.attached_pairs:
            # i = self.contact_bodies.index(pair[0])
            # j = self.contact_bodies.index(pair[1])
            mtx[i, j] = 1
            # mtx[j, i] = 1
        graph = nx.from_numpy_matrix(mtx)
        return graph

    def attach_pair(self, pair, f_on):
        """ Adds/removes physical attachment between a pair of nodes."""
        # Get the connected subgroups.
        graph = self.make_attachment_graph()
        sgs = [sg for sg in nx.connected_components(graph) if len(sg) > 1]
        self.reset_compounds()
        # Iterate over subgroups, creating compound shapes.
        for sg in sgs:
            nodes = [self.contact_bodies[i] for i in sg]
            parents = [c.getParent() for c in nodes]
            self.compound_components.extend(zip(nodes, parents))
            cname = "+".join([str(i) for i in sorted(sg)])
            cnode = CPSO(cname)
            cnode.reparentTo(self.scene)
            cnode.add(nodes)
            cnode.init_tree(tags=("shape", ))
            cnode.destroy_component_shapes()
            self.compound_objects.append(cnode)
Example #41
0
class RacingGame(ShowBase):
    # method completely taken from RoamingRalph demo:
    def addInstructions(self, pos, msg):
        return OnscreenText(text=msg,
                            style=1,
                            fg=(1, 1, 1, 1),
                            scale=.05,
                            shadow=(0, 0, 0, 1),
                            parent=base.a2dTopLeft,
                            pos=(0.08, -pos - 0.04),
                            align=TextNode.ALeft)

    def addWin(self, time):
        msg = (
            "You finished the course in: \n%d seconds \n press z to race again"
            % (time))
        self.winText = OnscreenText(text=msg,
                                    style=1,
                                    fg=(1, 1, 1, 1),
                                    scale=.2,
                                    shadow=(0, 0, 0, 1),
                                    parent=base.a2dTopLeft,
                                    pos=(0.10, -0.5),
                                    align=TextNode.ALeft)

    def destroyWin(self):
        if (self.winText != None):
            self.winText.destroy()

    def setUpFlyingInstructions(self):
        self.inst[0] = self.addInstructions(.06, "Arrow Keys to move around")
        self.inst[1] = self.addInstructions(.12, "w and s to control pitch")
        self.inst[2] = self.addInstructions(.18, "a and d to control yaw")
        self.inst[3] = self.addInstructions(.24, "h to switch to driving mode")
        self.inst[4] = self.addInstructions(.3, "mouse click to add object")
        self.inst[5] = self.addInstructions(.36, "m to go to main")

    def startMovement(self):
        taskMgr.add(self.move, "moveTask")

    def destroyInstructions(self):
        # got way to destroy text from:
        # https://www.panda3d.org/manual/index.php/OnscreenText
        for element in self.inst:
            element.destroy()

    def startCreating(self):
        self.switchToCreateMode()
        self.destroyStartScreenButtons()
        self.startMovement()

    def startDriving(self):
        self.switchToDrivingMode()
        self.destroyStartScreenButtons()
        self.startMovement()

    def startTutorial(self):
        self.mode = self.modeTutorial
        self.setUpTutorial()
        self.destroyStartScreenButtons()
        self.startMovement()

    def setUpStartScreenButtons(self):
        self.creatingButton = DirectButton(text="Start Creating",
                                           scale=.1,
                                           command=self.startCreating,
                                           pos=(0, 0, .2))
        self.drivingButton = DirectButton(text="Start Driving",
                                          scale=.1,
                                          command=self.startDriving,
                                          pos=(0, 0, 0))
        self.tutorialButton = DirectButton(text="Start Tutorial",
                                           scale=.1,
                                           command=self.startTutorial,
                                           pos=(0, 0, -.2))

    def destroyStartScreenButtons(self):
        self.creatingButton.destroy()
        self.drivingButton.destroy()
        self.tutorialButton.destroy()

    def setAddObjectTree(self):
        self.createdObject = self.createTree

    def setAddObjectRock(self):
        self.createdObject = self.createRock

    def setAddObjectPole(self):
        self.createdObject = self.createPole

    def setUpCreateButtons(self):
        # todo: add toggle for instructions so that they do not always interfere with button
        self.treeButton = DirectButton(text="Add Block",
                                       scale=.1,
                                       command=self.setAddObjectTree,
                                       pos=(0, 0, .85))
        #self.rockButton = DirectButton(text="Add Rock", scale=.1, command=self.setAddObjectRock, pos=(-.5,.9,.85))
        self.poleButton = DirectButton(text="Add Pole",
                                       scale=.1,
                                       command=self.setAddObjectPole,
                                       pos=(.5, 0, .85))

    def setUpCreateObjects(self):
        self.createdObject = 0
        self.createTree = 0
        self.createRock = 1
        self.createPole = 2

    def destroyCreateButtons(self):
        self.treeButton.destroy()
        #self.rockButton.destroy()
        self.poleButton.destroy()

    def setUpDrivingInstructions(self):
        self.inst[0] = self.addInstructions(
            .06, "Right arrow and left arrow to turn")
        self.inst[1] = self.addInstructions(
            .12, "Forward and Backward arrow to go forward and backward")
        self.inst[2] = self.addInstructions(.18,
                                            "h to switch to add object mode")
        self.inst[3] = self.addInstructions(.24,
                                            "z to switch to start the race")
        self.inst[4] = self.addInstructions(.30, "m to go to main")

    def setUpWindow(self):
        # set up the egg files needed
        # since this method is made for python 2.7 but these objects are made for python 3.5, seems to be incompatible
        #m = Mountain("TestMountain", 60)
        #m.editFile()
        #p = Pole("TestPole", 0, 0, 0)
        #p.editFile()
        #c = Car("TestCar", 0,0,0)
        #c.editFile()
        #b = BeaconLight("BeaconLight",0,0,0)
        #b.editFile()
        # Set up the window, camera, etc
        ShowBase.__init__(self)

        # Set the background color to black
        self.win.setClearColor((0, 1, 1, 1))
        # this is the model I created using mountainMaker.py
        self.environ = loader.loadModel("TestMountain1")
        self.environ.reparentTo(render)

        self.car = loader.loadModel("TestCar")
        # found how to solve the problem of only being able to see objects from
        # certain angles with this:
        # http://www.panda3d.org/manual/index.php/Backface_Culling_and_Frontface_Culling
        self.car.setTwoSided(True)
        self.car.reparentTo(render)

        # Create some lighting
        # this is a part that is completely unchanged from demo
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        # to get light from other direction to light up things on both sides
        directionalLight2 = DirectionalLight("directionalLight")
        directionalLight2.setDirection((5, 5, 5))
        directionalLight2.setColor((1, 1, 1, 1))
        directionalLight2.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(directionalLight2))

    def setUpCar(self):
        # for adjusting so that the position is the center of the car
        self.adjustedXForCenter = 10 / 2
        self.adjustedYForCenter = 20 / 2

        # for some reason can't change this or the collisions do not work
        self.carPositionX = 20
        self.carPositionY = 20
        self.carPositionZ = 100
        # note for rotating camera: from this website:
        # https://www.panda3d.org/manual/index.php/Common_State_Changes
        # setHpr(Yaw, Pitch, Roll)

        # setting up initial conditions for which way camera is rotated
        self.carYaw = 0
        self.carPitch = 0
        (actualXPos, actualYPos) = RacingGame.findActualCenter(
            self, self.carPositionX, self.carPositionY,
            self.adjustedXForCenter, self.adjustedYForCenter, self.carYaw)
        self.car.setX(actualXPos)
        self.car.setY(actualYPos)
        self.car.setZ(self.carPositionZ)
        self.car.setHpr(self.carYaw, self.carPitch, 0)

    def setUpCamera(self):
        # for flying mode
        self.cameraPositionX = 500
        self.cameraPositionY = 500
        self.cameraPositionZ = 40
        # note for rotating camera: from this website:
        # https://www.panda3d.org/manual/index.php/Common_State_Changes
        # setHpr(Yaw, Pitch, Roll)

        # setting up initial conditions for which way camera is rotated
        self.cameraYaw = 0
        self.cameraPitch = 0

        # Set up the camera
        self.disableMouse()

        # should probably clean up these magic numbers
        self.camera.setPos(self.cameraPositionX, self.cameraPositionY,
                           self.cameraPositionZ)

    def setUpKeyMap(self):
        # This is used to store which keys are currently pressed.
        self.keyMap = {
            "left": 0,
            "right": 0,
            "forward": 0,
            "cam-left": 0,
            "cam-right": 0,
            "backward": 0,
            "cam-up": 0,
            "cam-down": 0,
            "add-car": 0,
            "switch-mode": 0,
            "mouse-click": 0,
            "race-start": 0,
            "to-main": 0
        }
        # Accept the control keys for movement and rotation

        #setting up keys for movement
        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("arrow_down", self.setKey, ["backward", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("arrow_down-up", self.setKey, ["backward", False])

        self.accept("m", self.setKey, ["to-main", True])
        self.accept("m-up", self.setKey, ["to-main", False])

        # starting race
        self.accept("z", self.setKey, ["race-start", True])
        self.accept("z-up", self.setKey, ["race-start", False])

        # adding car
        self.accept("mouse1", self.setKey, ["mouse-click", True])
        self.accept("mouse1-up", self.setKey, ["mouse-click", False])

        # setting up orientation of the camera
        self.accept("a", self.setKey, ["cam-left", True])
        self.accept("s", self.setKey, ["cam-down", True])
        self.accept("a-up", self.setKey, ["cam-left", False])
        self.accept("s-up", self.setKey, ["cam-down", False])
        self.accept("d", self.setKey, ["cam-right", True])
        self.accept("d-up", self.setKey, ["cam-right", False])
        self.accept("w", self.setKey, ["cam-up", True])
        self.accept("w-up", self.setKey, ["cam-up", False])

        # to switch between tasks
        self.accept("h", self.setKey, ["switch-mode", True])
        self.accept("h-up", self.setKey, ["switch-mode", False])

    def __init__(self):
        self.setUpWindow()
        self.setUpKeyMap()
        #instructions
        self.inst = [""] * 6
        self.setUpFlyingInstructions()

        self.mouseClicked = False

        self.winText = None

        # important for setting the size relative to everything else
        # found it here : https://www.panda3d.org/manual/index.php/Common_State_Changes
        # set the mode that the player is currently in
        self.mode = 0
        self.modeFly = 2
        self.modeRace = 1
        self.modeStart = 0
        self.modeTutorial = 3
        # to ensure that when pressing h it only switches once each press
        self.hasSwitched = False
        self.raceBegan = False
        self.raceTime = 0
        self.poleOn = 0

        self.setUpCamera()
        self.setUpCar()
        self.setUpCarCollider()
        self.setUpMouseCollider()
        self.setUpStartScreenButtons()
        # make the rocks and other stuff that will show up
        self.setUpCreateObjects()
        self.objects = []
        self.poles = []
        self.beaconLight = None
        self.beaconLightZ = 50
        self.target = None

        taskMgr.add(self.move, "moveTask")

    def findCollisionTube(self):
        # using bassically same formula as Y position
        # decided not to use this because possible problems with ground getting
        # hit instead of things in front
        degToRad = math.pi / 180
        xAddition = (
            self.adjustedXForCenter * math.cos(self.carYaw * degToRad) +
            self.adjustedYForCenter * math.sin(self.carYaw * degToRad)) / 2
        yAddition = (
            self.adjustedXForCenter * math.cos(self.carYaw * degToRad) +
            self.adjustedYForCenter * math.sin(self.carYaw * degToRad))

    def findCarFrontDir(self):
        degToRad = math.pi / 180
        xDir = -1 * math.sin(degToRad * self.carYaw) * math.cos(
            degToRad * self.carPitch)
        yDir = 1 * math.cos(degToRad * self.carYaw) * math.cos(
            degToRad * self.carPitch)
        zDir = 1 * math.sin(degToRad * self.carPitch)
        return (xDir, yDir, zDir)

    def setUpCarCollider(self):
        self.carCollideTrav = CollisionTraverser()
        base.cTrav = self.carCollideTrav
        self.handler = CollisionHandlerQueue()
        self.carRay = CollisionRay(self.carPositionX, self.carPositionY,
                                   self.carPositionZ, 0, 0, -1)
        self.carForwardHandler = CollisionHandlerQueue()
        # so that it doesn't collide with things forward and backward.
        degToRad = math.pi / 180
        (xDir, yDir, zDir) = self.findCarFrontDir()
        self.carRayForward = CollisionRay(self.carPositionX, self.carPositionY,
                                          self.carPositionZ, xDir, yDir, zDir)
        self.carForwardCollision = CollisionNode("forwardCollision")
        self.carForwardCollision.addSolid(self.carRayForward)
        self.carForwardCollision.setIntoCollideMask(CollideMask.allOff())
        self.carForwardCollisionNode = self.car.attachNewNode(
            self.carForwardCollision)
        (centerX,
         centerY) = self.findActualCenter(0, 0, self.adjustedXForCenter,
                                          self.adjustedYForCenter, self.carYaw)
        self.carRayForward.setOrigin(5, 10, 5)
        self.carCollision = CollisionNode("groundCollision")
        self.carCollision.addSolid(self.carRay)
        self.carCollision.setIntoCollideMask(CollideMask.allOff())
        self.carCollisionNode = self.car.attachNewNode(self.carCollision)
        self.carCollideTrav.addCollider(self.carCollisionNode, self.handler)
        self.carCollideTrav.addCollider(self.carForwardCollisionNode,
                                        self.carForwardHandler)
        self.carForwardCollisionNode.show()

    def setUpMouseCollider(self):
        # clicking on objects stuff came from here:
        # https://www.panda3d.org/manual/index.php/Collision_Traversers
        # https://www.panda3d.org/manual/index.php/Collision_Handlers
        # will not use the traverser set up by car because slow
        # instead we will render each time clicked
        self.mouseCollideTrav = CollisionTraverser("mouseTraverse")
        self.mousehandler = CollisionHandlerQueue()
        # edit this so that from Object is the camera
        # self.mouseCollideTrav.addCollider(fromObject, queue)
        # self.mouseCollideTrav.traverse(render)
        # this next part came from:
        # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
        pickerNode = CollisionNode("mouseRay")
        pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
        pickerNode.setIntoCollideMask(CollideMask.allOff())
        self.pickerRay = CollisionRay()
        pickerNode.addSolid(self.pickerRay)
        pickerNp = camera.attachNewNode(pickerNode)
        self.mouseCollideTrav.addCollider(pickerNp, self.mousehandler)

    # Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    def switchToCreateMode(self):
        self.mode = self.modeFly
        self.destroyInstructions()
        self.setUpFlyingInstructions()
        self.hasSwitched = True
        self.setUpCreateButtons()

    def switchToDrivingMode(self):
        self.mode = self.modeRace
        self.destroyInstructions()
        self.setUpDrivingInstructions()
        self.hasSwitched = True

    def switchToMainMode(self):
        self.mode = 0
        self.setUpStartScreenButtons()

    def setTutorialText(self, str):
        # reusing inst so that it is easy to erase
        self.inst[0] = self.addInstructions(.06, str)

    def move(self, task):
        if (self.keyMap["to-main"]):
            self.switchToMainMode()
        elif (self.mode == self.modeFly):
            if self.keyMap["switch-mode"] and not self.hasSwitched:
                self.switchToDrivingMode()
                self.destroyCreateButtons()
            elif not self.keyMap["switch-mode"]:
                # to ensure switch mode only happens once per button pressed
                self.hasSwitched = False
            self.findNewCameraPosition()
            self.checkAndAddNewObject()
        elif (self.mode == self.modeRace):
            if self.keyMap["switch-mode"] and not self.hasSwitched:
                self.destroyWin()
                self.switchToCreateMode()
            elif not self.keyMap["switch-mode"]:
                # this ensures that when key is pressed only switch states once
                self.hasSwitched = False
            self.findCarNewXandY()
            # when implementing the use of the mouse look here:
            # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
            self.setCarZ()
            self.setCameraPositionBehindCar()
            if (self.keyMap["race-start"] and not self.raceBegan
                    and len(self.poles) >= 2):
                self.destroyWin()
                # try so that if there are not enough poles then the game
                # doesn't crash
                try:
                    self.raceBegan = True
                    self.raceTime = time.time()
                    # puts in the car where the first two poles are
                    # first col of poles is model, second x coord, thrid y coord, fourth z coord
                    self.carPositionX = (self.poles[0][1] +
                                         self.poles[1][1]) / 2
                    self.carPositionY = (self.poles[0][2] +
                                         self.poles[1][2]) / 2
                    # meant to show where car should go
                    # got info on how to do point lights from here:
                    # https://www.panda3d.org/manual/index.php/Lighting
                    self.beaconLight = PointLight("beaconLight")
                    self.beaconLight.setColor((1, 1, 1, 1))
                    self.beaconLight.setAttenuation((0, 0, 1))
                    self.beaconLightHolder = render.attachNewNode(
                        self.beaconLight)
                    (beaconLightX, beaconLightY) = self.getNextGateCenter()
                    # target for driver
                    if (self.target == None):
                        self.target = loader.loadModel("BeaconLight.egg")
                    self.target.setTwoSided(True)
                    self.target.reparentTo(render)
                    if (beaconLightX != None):
                        self.beaconLightHolder.setPos(beaconLightX,
                                                      beaconLightY,
                                                      self.beaconLightZ)
                        render.setLight(self.beaconLightHolder)
                        self.target.setPos(beaconLightX, beaconLightY,
                                           self.beaconLightZ)
                except:
                    # not enough poles
                    pass
            if (self.raceBegan):
                # minus 1 just in case non even
                if (self.poleOn + 1 >= len(self.poles)):
                    self.raceBegan = False
                    self.addWin(time.time() - self.raceTime)
                    # since race ended
                    try:
                        self.target.destroy()
                    except:
                        pass
                    self.beaconLight = None  # use object + lights
                    self.beaconLightHolder = None
                    self.poleOn = 0
                else:
                    acceptableError = 100
                    # formula I created: (p2y-p1y)/(p2x-p1x)*(p2x-pAx)+p2y =
                    # expected pAy
                    # so if the actual car positionY is within acceptableError of
                    # pAy then the car is between the two poles
                    # if in between poles
                    middleX = (self.poles[self.poleOn][1] +
                               self.poles[self.poleOn + 1][1]) / 2
                    middleY = (self.poles[self.poleOn][2] +
                               self.poles[self.poleOn + 1][2]) / 2
                    expectedCarY = (
                        (self.poles[self.poleOn][2] -
                         self.poles[self.poleOn + 1][2]) /
                        (self.poles[self.poleOn][1] -
                         self.poles[self.poleOn + 1][1]) *
                        (self.poles[self.poleOn][1] - self.carPositionX) +
                        self.poles[self.poleOn][2])
                    # do not really care about car being inbetween pole in z axis
                    # because 2 demensional
                    if (expectedCarY + acceptableError > self.carPositionY
                            and expectedCarY - acceptableError <
                            self.carPositionY):
                        self.poleOn += 2
                        # only when last pole found is it necesary to add light
                        # to guide to next place elsewhere
                        (beaconLightX, beaconLightY) = self.getNextGateCenter()
                        if (beaconLightX != None):
                            self.beaconLightHolder.setPos(
                                beaconLightX, beaconLightY, self.beaconLightZ)
                            self.target.setPos(beaconLightX, beaconLightY,
                                               self.beaconLightZ)
        elif (self.mode == self.modeTutorial):
            self.destroyWin()
            # do the tutorial part for the creating
            timeBeforeNext = 2
            if (self.tutorialPause == True):
                if (time.time() - self.tutorialActionTime > timeBeforeNext):
                    self.tutorialPause = False
            else:
                if (self.tutorialStep == -1):
                    self.destroyInstructions()
                    self.setTutorialText(
                        "use w and s to move camera up and down")
                    self.tutorialStep += 1
                # do this until the user has completed all of the task
                self.checkTutorialStep(
                    0, (self.keyMap["cam-up"] or self.keyMap["cam-down"]),
                    "use a and d to rotate camera right and left")
                self.checkTutorialStep(
                    1, (self.keyMap["cam-left"] or self.keyMap["cam-right"]),
                    "use up-arrow and down-arrow to turn camera forward and backward"
                )
                self.checkTutorialStep(
                    2, (self.keyMap["forward"] or self.keyMap["backward"]),
                    "use left-arrow and right-arrow to slide camera left and right"
                )
                self.checkTutorialStep(
                    3, (self.keyMap["left"] or self.keyMap["right"]),
                    "use mouse click to place objects on terrain")
                self.checkTutorialStep(
                    4, (self.keyMap["mouse-click"]),
                    "use up-arrow and down-arrow to move car forward and backward",
                    (self.switchToDrivingMode, self.destroyInstructions))
                # need to ensure that the mode stays as tutorial
                self.mode = self.modeTutorial
                # then tutorial part for the driving
                self.checkTutorialStep(
                    5, (self.keyMap["forward"] or self.keyMap["backward"]),
                    "use right-arrow and left-arrow to rotate car left and right"
                )
                self.checkTutorialStep(
                    6, (self.keyMap["left"] or self.keyMap["right"]),
                    "Use poles to make the race course\n use z to start race")
                self.checkTutorialStep(
                    7, True,
                    "Follow yellow block through the gates till you win")
                self.checkTutorialStep(
                    8, True,
                    "Watch for high Terrain and blocks because you can not get through those"
                )
                self.checkTutorialStep(9, True, "")
                if (self.tutorialStep > 9):
                    # switch to main
                    self.switchToMainMode()
            # for movement
            if (self.tutorialStep <= 4):
                self.findNewCameraPosition()
                self.checkAndAddNewObject()
            if (self.tutorialStep > 4 and self.tutorialStep <= 9):
                self.findCarNewXandY()
                self.setCarZ()
                self.setCameraPositionBehindCar()
        return task.cont

    def getNextGateCenter(self):
        if (len(self.poles) > self.poleOn + 1):
            positionX = (self.poles[self.poleOn][1] +
                         self.poles[self.poleOn + 1][1]) / 2
            positionY = (self.poles[self.poleOn][2] +
                         self.poles[self.poleOn + 1][2]) / 2
            return (positionX, positionY)
        else:
            return (None, None)

    def checkTutorialStep(self, step, keysNeeded, nextText, functions=None):
        if (self.tutorialStep == step and self.tutorialNextStep == True):
            if (functions != None):
                for func in functions:
                    func()
            self.destroyInstructions()
            self.setTutorialText(nextText)
            self.tutorialStep += 1
            self.tutorialNextStep = False
        elif (self.tutorialStep == step and keysNeeded):
            self.tutorialNextStep = True
            self.tutorialActionTime = time.time()
            self.tutorialPause = True

    def setUpTutorial(self):
        self.tutorialStep = -1
        self.tutorialPause = False
        # this records when last tutorial action taken
        self.tutorialActionTime = 0
        self.tutorialNextStep = False

    def checkAndAddNewObject(self):
        # clicking on 3D objects comes from here:
        # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
        # checks if it needs to add any objects:
        if (self.keyMap["mouse-click"] and self.mouseClicked == False):
            self.mouseClicked = True
            # found way to speed this up by only doing collision check
            # when mouse clicked by not using cTrav like in this method
            # the way I did it I found here:
            # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
            # self.mouseCollideTrav.traverse(render)
            if (base.mouseWatcherNode.hasMouse()):
                mousePos = base.mouseWatcherNode.getMouse()
                self.pickerRay.setFromLens(base.camNode, mousePos.getX(),
                                           mousePos.getY())
                # do not put this before previous line, will get the coordinates
                # of last mouse click and where pickerRay was
                # ahhhhhhh!!!!!!!!!!!
                self.mouseCollideTrav.traverse(render)
                if (self.mousehandler.getNumEntries() > 0):
                    entries = list(self.mousehandler.getEntries())
                    # pathagorean formula for sorting
                    entries.sort(
                        key=lambda x: ((x.getSurfacePoint(render).getX(
                        ) - self.cameraPositionX)**2 + (x.getSurfacePoint(
                            render).getY() - self.cameraPositionY)**2)**.5)
                    newX = entries[0].getSurfacePoint(render).getX()
                    newY = entries[0].getSurfacePoint(render).getY()
                    newZ = entries[0].getSurfacePoint(render).getZ()
                    adjustedX = 10 / 2
                    adjustedY = 20 / 2
                    yaw = 0
                    # have to adjust this once there are different sized
                    # objects added
                    (actualXPos, actualYPos) = RacingGame.findActualCenter(
                        self, newX, newY, adjustedX, adjustedY, yaw)
                    if (self.createdObject == self.createPole):
                        self.poles.append([
                            loader.loadModel("TestPole.egg"), actualXPos,
                            actualYPos, newZ
                        ])
                        self.poles[len(self.poles) - 1][0].reparentTo(render)
                        self.poles[len(self.poles) - 1][0].setTwoSided(True)
                        self.poles[len(self.poles) - 1][0].setPos(
                            actualXPos, actualYPos, newZ)
                    else:
                        newCar = loader.loadModel("TestCar.egg")
                        newCar.reparentTo(render)
                        newCar.setPos(actualXPos, actualYPos, newZ)
                        # should take out because slow, but objects can not be
                        # seen without this because only seen from one direction
                        # even though normal vectors set up.
                        newCar.setTwoSided(True)
                        self.objects.append(newCar)
        elif (not self.keyMap["mouse-click"]):
            # elif because for some reason mouseClicked was becoming false
            # while click still pressed
            self.mouseClicked = False

    def findNewCameraPosition(self):
        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        dt = globalClock.getDt()
        # the angle is in degrees with 360 equal to full rotation
        angleAdjustment = 100
        if self.keyMap["cam-left"]:
            self.cameraYaw += angleAdjustment * dt
        if self.keyMap["cam-right"]:
            self.cameraYaw -= angleAdjustment * dt
        if self.keyMap["cam-up"]:
            self.cameraPitch += angleAdjustment * dt
        if self.keyMap["cam-down"]:
            self.cameraPitch -= angleAdjustment * dt

        positionAdjustment = 500
        # should switch rad and Deg in variable name
        radToDeg = math.pi / 180
        # the x and y component of left and right moves, do not need to
        # compensate in z axis because not doing any roll, so there should be
        # no zComponent
        xComponent = math.cos(self.cameraYaw * radToDeg)
        yComponent = math.sin(self.cameraYaw * radToDeg)

        if self.keyMap["left"]:
            self.cameraPositionX -= positionAdjustment * dt * xComponent
            self.cameraPositionY -= positionAdjustment * dt * yComponent
        if self.keyMap["right"]:
            self.cameraPositionX += positionAdjustment * dt * xComponent
            self.cameraPositionY += positionAdjustment * dt * yComponent

        # for going forward, the orientation is rotated 90 degrees so need to
        # change components
        xComponent = math.cos(self.cameraYaw * radToDeg + math.pi /
                              2) * math.cos(self.cameraPitch * radToDeg)
        yComponent = math.sin(self.cameraYaw * radToDeg + math.pi /
                              2) * math.cos(self.cameraPitch * radToDeg)
        zComponent = math.sin(self.cameraPitch * radToDeg)

        if self.keyMap["forward"]:
            self.cameraPositionX += positionAdjustment * dt * xComponent
            self.cameraPositionY += positionAdjustment * dt * yComponent
            self.cameraPositionZ += positionAdjustment * dt * zComponent
        if self.keyMap["backward"]:
            self.cameraPositionX -= positionAdjustment * dt * xComponent
            self.cameraPositionY -= positionAdjustment * dt * yComponent
            self.cameraPositionZ -= positionAdjustment * dt * zComponent

        self.camera.setX(self.cameraPositionX)
        self.camera.setY(self.cameraPositionY)
        self.camera.setZ(self.cameraPositionZ)
        self.camera.setHpr(self.cameraYaw, self.cameraPitch, 0)

    def carForwardImpact(self):
        # update position so that it is pointing right directions
        #(dirX, dirY, dirZ) = self.findCarFrontDir()
        #self.carRayForward.setDirection(dirX, dirY, dirZ)
        degToRad = math.pi / 180
        # + math.pi since it is taking corner and going to center rather
        # than opposite that function actually does
        #(centerX,centerY) = self.findActualCenter(0,0,self.adjustedXForCenter,
        #                                   self.adjustedYForCenter, self.carYaw
        #                                   +math.pi)
        posAboveGround = 5
        # need to update with new coordinates
        self.carCollideTrav.traverse(render)
        collisions = list(self.carForwardHandler.getEntries())
        # closest collision using pythagorean formula
        collisions.sort(
            key=lambda x:
            (x.getSurfacePoint(render).getX() - self.carPositionX)**2 +
            (x.getSurfacePoint(render).getY() - self.carPositionY)**2)
        if (len(collisions) > 0):
            (actualX, actualY) = RacingGame.findActualCenter(
                self, self.carPositionX, self.carPositionY,
                self.adjustedXForCenter, self.adjustedYForCenter, self.carYaw)
            distance = (
                (collisions[0].getSurfacePoint(render).getX() - actualX)**2 +
                (collisions[0].getSurfacePoint(render).getY() - actualY)**
                2)**.5
            error = .9  # so that the collisionray does not detect car itself
            return distance / 2 <= self.adjustedYForCenter * .9
        else:
            return False

    def findCarNewXandY(self):
        # Get the time that elapsed since last frame.  We multiply this with
        # the desired speed in order to find out with which distance to move
        # in order to achieve that desired speed.
        deltaTime = globalClock.getDt()
        degreeAdjustment = 60
        positionAdjustment = 100
        # should switch rad and Deg in variable name
        radToDeg = math.pi / 180
        # the x and y component of left and right moves, do not need to
        # compensate in z axis because not doing any roll, so there should be
        # no zComponent
        xComponent = math.sin(self.carYaw * radToDeg)
        yComponent = math.cos(self.carYaw * radToDeg)
        if self.keyMap["left"]:
            self.carYaw += degreeAdjustment * deltaTime
        if self.keyMap["right"]:
            self.carYaw -= degreeAdjustment * deltaTime
        if (self.keyMap["forward"] and not self.carForwardImpact()):
            self.carPositionX -= positionAdjustment * deltaTime * xComponent
            self.carPositionY += positionAdjustment * deltaTime * yComponent
        if self.keyMap["backward"]:
            self.carPositionX += positionAdjustment * deltaTime * xComponent
            self.carPositionY -= positionAdjustment * deltaTime * yComponent
        # need to consider both the x and y component of offset for both
        # because x slowly changes to y as it turns
        (actualXPos, actualYPos) = RacingGame.findActualCenter(
            self, self.carPositionX, self.carPositionY,
            self.adjustedXForCenter, self.adjustedYForCenter, self.carYaw)
        self.car.setX(actualXPos)
        self.car.setY(actualYPos)
        self.car.setZ(self.carPositionZ)
        self.car.setHpr(self.carYaw, self.carPitch, 0)

    def setCarZ(self):
        # almost directly taken from ralph example
        entries = list(self.handler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())
        # worry about which thing it collides with later
        if (len(entries) > 0):
            # and entries[0].getIntoNode().getName() == "mountainCollide":
            self.carPositionZ = (entries[0].getSurfacePoint(render).getZ())
        else:
            # because at 25 everything should be below car and do not want
            # to continually go up or else it may go up forever.
            self.carPositionZ = 25
        self.setCameraPositionBehindCar()

    def setCameraPositionBehindCar(self):
        # Modify view of camera so that it is behind car
        # should be named degToRad
        radToDeg = math.pi / 180
        distanceBehind = 200
        distanceAbove = 60
        self.camera.setHpr(self.carYaw, -.5, 0)
        (actualXPos, actualYPos) = self.findActualCenter(
            self.carPositionX, self.carPositionY, self.adjustedXForCenter,
            self.adjustedXForCenter, self.carYaw)
        camX = actualXPos + distanceBehind * math.sin(radToDeg * self.carYaw)
        camY = actualYPos - distanceBehind * math.cos(radToDeg * self.carYaw)
        camZ = self.carPositionZ + distanceAbove
        self.camera.setPos(camX, camY, camZ)

    def findActualCenter(self, positionX, positionY, adjustedX, adjustedY,
                         yaw):
        # will need to fix this later, it seems to be adjusting wrong
        # so that it is puting box away from click instead of on it
        # update, I think this is fixed?!?
        degToRad = math.pi / 180
        actualXPos = (positionX - adjustedX * math.cos(degToRad * yaw) +
                      adjustedY * math.sin(degToRad * yaw))
        actualYPos = (positionY - adjustedY * math.cos(degToRad * yaw) -
                      adjustedX * math.sin(degToRad * yaw))
        return (actualXPos, actualYPos)
Example #42
0
class Character(DirectObject, XMLExportable, PropertiesTableAbstract,
                GameEntity):
    def __init__(self, attributes, showCollisions, grid_currentx,
                 grid_currenty, grid_playable_pos, parent):
        GameEntity.__init__(self, parent)  #running parent constructor

        self.movtask = 0
        self.showCollisions = showCollisions
        self.grid_currentx = grid_currentx
        self.grid_currenty = grid_currenty
        self.grid_playable_pos = grid_playable_pos
        self.attributes = attributes
        self.onPicked = ''
        self.onWalked = ''
        self.typeName = 'character'

        self.properties = {
            'url': '',
            'onWalked': '',
            'onPicked': '',
            'id': '',
            'inclination': '',
            'scale': '',
            'hitboxscale': '',
            'speed': '',
            'playable': '',
            'direction': ''
        }

        if attributes.has_key('url'):
            self.properties['url'] = attributes['url'].value
        else:
            print "WARNING: url not defined, loading placeholder"
            self.properties['url'] = 'misc/placeholder'

        if attributes.has_key('id'):
            self.properties['id'] = attributes['id'].value
        else:
            self.properties['id'] = 'all'

        if attributes.has_key('inclination'):
            self.properties['inclination'] = float(
                attributes['inclination'].value)
        else:
            self.properties['inclination'] = 30.0

        if attributes.has_key('scale'):
            self.properties['scale'] = float(attributes['scale'].value)
        else:
            self.properties['scale'] = 1.0

        if attributes.has_key('hitboxscale'):
            self.properties['hitboxscale'] = float(
                attributes['hitboxscale'].value)
        else:
            self.properties['hitboxscale'] = 1.0

        if attributes.has_key('speed'):
            self.properties['speed'] = float(attributes['speed'].value)
        else:
            self.properties['speed'] = 1.0

        #self.isNPC remains true while isPlayable is changable
        if attributes.has_key('playable'):
            self.playable = playable = attributes['playable'].value
            if self.playable == 'false':
                self.isNPC = False
                #print "setting ", self.properties['id'], " to ", self.isNPC
            else:
                self.isNPC = True
                #print "setting ", self.properties['id'], " to ", self.isNPC
        else:
            self.playable = playable = 'false'
            self.isNPC = True
        self.properties['playable'] = self.playable

        if attributes.has_key('direction'):
            self.properties['direction'] = attributes['direction'].value
        else:
            self.properties['direction'] = "down"

        if attributes.has_key('onWalked'):
            self.properties['onWalked'] = self.onWalked = attributes[
                'onWalked'].value
        else:
            self.properties['onWalked'] = self.onWalked = ""

        if attributes.has_key('onPicked'):
            self.properties['onPicked'] = self.onPicked = attributes[
                'onPicked'].value

        self.generateNode(showCollisions)

    def generateNode(self, showCollisions):
        self.destroy()

        #setting local variable
        attributes = self.attributes

        #defaulted to None
        self.pickCTrav = None

        #movement
        self.state = "still"
        self.showCollisions = showCollisions

        self.movtask = 0
        self.currentlydown = []
        self.currentlyfollowed = 0

        self.pickRequest = False

        #public props
        self.node = NodePath("characternode")
        self.node.setTwoSided(True)

        self.wtop = self.applyNearestFilter(
            loader.loadModel(
                resourceManager.getResource(self.properties['url']) +
                '/wtop.egg'))
        self.wdown = self.applyNearestFilter(
            loader.loadModel(
                resourceManager.getResource(self.properties['url']) +
                '/wdown.egg'))
        self.wleft = self.applyNearestFilter(
            loader.loadModel(
                resourceManager.getResource(self.properties['url']) +
                '/wleft.egg'))
        self.wright = self.applyNearestFilter(
            loader.loadModel(
                resourceManager.getResource(self.properties['url']) +
                '/wright.egg'))
        self.stop = self.applyNearestFilter(
            loader.loadModel(
                resourceManager.getResource(self.properties['url']) +
                '/stop.egg'))
        self.sdown = self.applyNearestFilter(
            loader.loadModel(
                resourceManager.getResource(self.properties['url']) +
                '/sdown.egg'))
        self.sleft = self.applyNearestFilter(
            loader.loadModel(
                resourceManager.getResource(self.properties['url']) +
                '/sleft.egg'))
        self.sright = self.applyNearestFilter(
            loader.loadModel(
                resourceManager.getResource(self.properties['url']) +
                '/sright.egg'))

        #Texture.FTNearest

        self.wtop.reparentTo(self.node)
        self.wdown.reparentTo(self.node)
        self.wleft.reparentTo(self.node)
        self.wright.reparentTo(self.node)
        self.stop.reparentTo(self.node)
        self.sdown.reparentTo(self.node)
        self.sleft.reparentTo(self.node)
        self.sright.reparentTo(self.node)

        self.leftdown = False
        self.rightdown = False
        self.downdown = False
        self.topdown = False

        if self.playable == "true":
            self.setPlayable(
                False)  #seems nonsense, triggered on grid.changeMap event
            self.node.setTag(
                "playable", "true"
            )  #setting this to make it recognizable from grid changeMap api
            self.setCollisions(True)
            self.setPickCollisions(True)
        else:
            self.setPlayable(False)
            self.node.setTag("playable", "false")
            self.setCollisions(False)
            self.setPickCollisions(False)

        #self.node.setX((-32/2)+0.5)
        self.node.setP(-(360 - int(self.properties['inclination'])))
        self.node.setScale(float(self.properties['scale']))
        self.node.setTransparency(TransparencyAttrib.MAlpha)

        self.lastpos = self.node.getPos()

        self.showAllSubnodes()

        #taskMgr.doMethodLater(4, self.face, 'charload'+self.properties['id'], [self.properties['direction']])
        self.face(self.properties['direction'])

        #set unique id
        self.node.setTag("id", self.properties['id'])
        #setting scripting part
        self.node.setTag("onWalked", self.onWalked)
        self.node.setTag("onPicked", self.onPicked)

        #storing a pointer of the gamenode
        self.node.setPythonTag("gamenode", self)

        self.npc_walk_stack = []
        self.npc_walk_happening = False
        self.globalLock = False

        self.setX(self.grid_currentx)
        self.setY(self.grid_currenty)

        if self.isNPC != True:
            print "attempting creation of NPC in ", self.grid_currentx, "-", self.grid_currenty

        if attributes.has_key('playable'):
            if self.isNPC != False:
                if ((self.grid_playable_pos.getX() != 0)
                        and (self.grid_playable_pos.getY() != 0)):
                    print 'GRID: moving player to ' + str(
                        self.grid_playable_pos)
                    self.setX(self.grid_playable_pos.getX())
                    self.setY(self.grid_playable_pos.getY())

        #automatic reparenting (and showing) when (re)generating node
        self.node.wrtReparentTo(self.parent.node)

    def getName(self):
        return 'Character: ' + self.properties['id']

    def xmlAttributes(self):
        return self.properties

    def xmlTypeName(self):
        return self.typeName

    '''
    Sanitize properties data to be of correct type from string
    '''

    def sanitizeProperties(self):
        #sanitizing data
        self.properties['inclination'] = float(self.properties['inclination'])
        self.properties['hitboxscale'] = float(self.properties['hitboxscale'])
        self.properties['speed'] = float(self.properties['speed'])
        self.properties['scale'] = float(self.properties['scale'])

        self.updateTilePosition()

    #interface needed by PropertiesTable
    # regenerates the node at every change
    def onPropertiesUpdated(self):
        self.sanitizeProperties()
        self.generateNode(self.showCollisions)

    #interface needed by PropertiesTable
    #TODO: implement as real interface?
    def getPropertyList(self):
        return self.properties

    #interface needed by PropertiesTable
    def setProperty(self, key, value):
        self.properties[key] = value

    def setSpeed(self, s):
        self.properties['speed'] = s

    def applyNearestFilter(self, model):
        for tex in model.findAllTextures():
            tex.setMinfilter(Texture.FT_nearest)
            tex.setMagfilter(Texture.FT_nearest)
        return model

    '''
    make the npc walk in direction for units
    '''

    def npc_push_walk(self, direction, units):
        #locking script execution
        self.globalLock = True
        script.addOneCustomLock(self)

        #start the walking
        self.npc_walk_stack.append([direction, units])
        self.npc_walk_helper()

    #apicall
    def npc_walk_helper(self):
        x = self.node.getX()
        y = self.node.getZ()

        #concurrent protection
        if self.npc_walk_happening == True:
            return

        #returning if no movement has to be performed
        if len(self.npc_walk_stack) < 0:
            return

        movement = self.npc_walk_stack.pop(0)

        direction = movement[0]
        units = movement[1]

        self.npc_targetx = x
        self.npc_targety = y
        self.npc_direction = direction

        if (direction == "down"):
            self.npc_targety = self.npc_targety - units
        elif (direction == "up"):
            self.npc_targety = self.npc_targety + units
        elif (direction == "left"):
            self.npc_targetx = self.npc_targetx - units
        elif (direction == "right"):
            self.npc_targetx = self.npc_targetx + units

        self.setAnim(direction)

        self.npc_walk_happening = True
        self.npc_movtask = taskMgr.add(self.npc_walk_task,
                                       "npc_moveCharacterTask" +
                                       self.properties['id'],
                                       uponDeath=self.npc_walk_callback)

    def npc_walk_task(self, task):
        dt = globalClock.getDt()

        if (self.npc_direction == 'left'):
            self.node.setX(self.node.getX() -
                           1 * dt * self.properties['speed'])
            currentx = self.node.getX()

            if currentx <= self.npc_targetx:
                return task.done
        if (self.npc_direction == 'right'):
            self.node.setX(self.node.getX() +
                           1 * dt * self.properties['speed'])
            currentx = self.node.getX()

            if currentx >= self.npc_targetx:
                return task.done
        if (self.npc_direction == 'up'):
            self.node.setZ(self.node.getZ() +
                           1 * dt * self.properties['speed'])
            currenty = self.node.getZ()

            if currenty >= self.npc_targety:
                return task.done
        if (self.npc_direction == 'down'):
            self.node.setZ(self.node.getZ() -
                           1 * dt * self.properties['speed'])
            currenty = self.node.getZ()

            if currenty <= self.npc_targety:
                return task.done

        return task.cont

    def npc_walk_callback(self, task):
        self.face(self.npc_direction)

        #unlocking concurrent movement protection
        self.npc_walk_happening = False

        if len(self.npc_walk_stack) > 0:
            self.npc_walk_helper()
        else:  #character ended walking, unlock
            self.globalLock = False

    '''
    write destroyfunction
    '''

    def destroy(self):
        #not accepting events
        self.ignoreAll()
        #destroying everything down
        if self.node != None:
            self.node.remove_node()
        #removing all tasks
        if self.movtask != 0:
            taskMgr.remove(self.movtask)
            self.movtask = 0

    def face(self, direction):
        if direction == "left":
            self.hideAllSubnodes()
            self.sleft.show()
        if direction == "right":
            self.hideAllSubnodes()
            self.sright.show()
        if direction == "top" or direction == "up":  #let's keep retrocompatibility
            self.hideAllSubnodes()
            self.stop.show()
        if direction == "down":
            self.hideAllSubnodes()
            self.sdown.show()

    def setCollisions(self, value):
        if value == True:
            b = self.node.getBounds().getRadius()

            self.cTrav = CollisionTraverser()

            self.collisionTube = CollisionSphere(
                b / 2, 0, b / 2, 0.035 * self.properties['hitboxscale'])
            self.collisionNode = CollisionNode('characterTube')
            self.collisionNode.addSolid(self.collisionTube)
            self.collisionNodeNp = self.node.attachNewNode(self.collisionNode)
            self.collisionHandler = CollisionHandlerQueue()
            self.cTrav.addCollider(self.collisionNodeNp, self.collisionHandler)

            if self.showCollisions == True or main.editormode:
                # Uncomment this line to see the collision rays
                self.collisionNodeNp.show()

                # Uncomment this line to show a visual representation of the
                # collisions occuring
                self.cTrav.showCollisions(render)
        else:
            b = self.node.getBounds().getRadius()
            self.collisionTube = CollisionSphere(
                b / 2, 0, b / 2, 0.035 * self.properties['hitboxscale'])

            #allowing playables to collide with npcs
            if self.isNPC == True:  #TODO: fix because it's completely f****d up
                self.collisionNode = CollisionNode('characterTube')
            else:
                self.collisionNode = CollisionNode('characterNPCTube')

            self.collisionNode.addSolid(self.collisionTube)
            self.collisionNodeNp = self.node.attachNewNode(self.collisionNode)

    #set if camera has to effectively follow the character
    #while it moves
    def setFollowedByCamera(self, value):
        #camera follow
        if value:
            if self.currentlyfollowed != True:
                customCamera.follow(self)
                self.currentlyfollowed = True
        else:
            if self.currentlyfollowed != False:
                customCamera.dontFollow()
                self.currentlyfollowed = False

    def setPickCollisions(self, value):
        if value:
            print "setting pick collisions"
            b = self.node.getBounds().getRadius()

            self.pickCTrav = CollisionTraverser()

            self.pickCollisionTube = CollisionSphere(
                b / 2, 0, b / 2, 0.035 * self.properties['hitboxscale'] + 0.01)
            self.pickCollisionNode = CollisionNode('characterPickTube')
            self.pickCollisionNode.addSolid(self.pickCollisionTube)
            self.pickCollisionNodeNp = NodePath(self.pickCollisionNode)
            self.pickCollisionNodeNp.reparentTo(self.node)
            self.pickCollisionHandler = CollisionHandlerQueue()
            self.pickCTrav.addCollider(self.pickCollisionNodeNp,
                                       self.pickCollisionHandler)

            if self.showCollisions == True:
                # Uncomment this line to see the collision rays
                self.pickCollisionNodeNp.show()

                # Uncomment this line to show a visual representation of the
                # collisions occuring
                self.pickCTrav.showCollisions(render)
        else:
            #dereferincing all pick colliders (must be done in order not to collide onto NPCs)
            self.pickCTrav = None
            self.pickCollisionTube = None
            self.pickCollisionNode = None
            self.pickCollisionNodeNp = None
            self.pickCollisionHandler = None

    #used to set playability in real time
    #useful when we want to switch context/scripted scenes
    def setPlayable(self, value):
        if self.isNPC != False:
            if value == True:
                #down events
                self.accept("arrow_left", self.arrowLeftDown)
                self.accept("arrow_right", self.arrowRightDown)
                self.accept("arrow_up", self.arrowUpDown)
                self.accept("arrow_down", self.arrowDownDown)
                #up events
                self.accept("arrow_left-up", self.arrowLeftUp)
                self.accept("arrow_right-up", self.arrowRightUp)
                self.accept("arrow_up-up", self.arrowUpUp)
                self.accept("arrow_down-up", self.arrowDownUp)
                self.accept("space", self.spaceDown)
                self.node.setTag("playable", "true")
                self.setFollowedByCamera(True)
                self.accept("pauseGameplay", self.setPlayable,
                            [False])  #can pause play
            else:
                self.ignoreAll()
                self.node.setTag("playable", "false")
                self.setFollowedByCamera(False)
                self.resetMovement()  #reset every movement happening
                self.accept("resumeGameplay", self.setPlayable,
                            [True])  #can resume play if not NPC

    #estimate loading time 4 seconds... lol... UPDATE: seems fixed in newer panda versions, inspect
    def showAllSubnodes(self):
        self.wtop.show()
        self.wdown.show()
        self.wleft.show()
        self.wright.show()
        self.stop.show()
        self.sdown.show()
        self.sleft.show()
        self.sright.show()

    def hideAllSubnodes(self):
        self.wtop.hide()
        self.wdown.hide()
        self.wleft.hide()
        self.wright.hide()
        self.stop.hide()
        self.sdown.hide()
        self.sleft.hide()
        self.sright.hide()

    def setMovement(self, value):
        if value == True:
            if self.movtask == 0:
                self.movtask = taskMgr.add(self.moveCharacter,
                                           "moveCharacterTask")
        if value == False:
            if self.movtask != 0:
                if len(self.currentlydown) == 0:
                    taskMgr.remove(self.movtask)
                    self.movtask = 0

    '''
    reset every movement actually happening
    '''

    def resetMovement(self):
        if self.leftdown == True:
            self.face("left")
        if self.rightdown == True:
            self.face("right")
        if self.downdown == True:
            self.face("down")
        if self.topdown == True:
            self.face("top")

        self.leftdown = False
        self.rightdown = False
        self.downdown = False
        self.topdown = False

        self.currentlydown = []

        self.setMovement(False)

    def setAnim(self, direction=''):
        self.hideAllSubnodes()

        if direction == '':
            if len(self.currentlydown) > 0:
                if self.currentlydown[-1] == 'left':
                    self.wleft.show()
                if self.currentlydown[-1] == 'right':
                    self.wright.show()
                if self.currentlydown[-1] == 'top':
                    self.wtop.show()
                if self.currentlydown[-1] == 'down':
                    self.wdown.show()
        else:
            if direction == 'left':
                self.wleft.show()
            if direction == 'right':
                self.wright.show()
            if direction == 'up':
                self.wtop.show()
            if direction == 'down':
                self.wdown.show()

    #pick request function
    def spaceDown(self):
        self.pickRequest = True

    #movement related functions
    def arrowLeftDown(self):
        #track key down
        self.leftdown = True
        self.setMovement(True)
        #show changes to screen
        self.currentlydown.append("left")
        self.setAnim()

    def arrowLeftUp(self):
        self.leftdown = False
        self.setMovement(False)
        #show changes to screen
        if len(self.currentlydown) == 1:
            self.hideAllSubnodes()
            self.sleft.show()
        if "left" in self.currentlydown:
            self.currentlydown.remove("left")

        if len(self.currentlydown) > 0:
            self.setAnim()

    def arrowRightDown(self):
        #track key down
        self.rightdown = True
        self.setMovement(True)
        #show changes to screen
        self.currentlydown.append("right")
        self.setAnim()

    def arrowRightUp(self):
        self.setMovement(False)
        self.rightdown = False
        #show changes to screen
        if len(self.currentlydown) == 1:
            self.hideAllSubnodes()
            self.sright.show()
        if "right" in self.currentlydown:
            self.currentlydown.remove("right")

        if len(self.currentlydown) > 0:
            self.setAnim()

    def arrowDownDown(self):
        #track key down
        self.downdown = True
        self.setMovement(True)
        #show changes to screen
        self.currentlydown.append("down")
        self.setAnim()

    def arrowDownUp(self):
        self.downdown = False
        self.setMovement(False)
        #show changes to screen
        if len(self.currentlydown) == 1:
            self.hideAllSubnodes()
            self.sdown.show()
        if "down" in self.currentlydown:
            self.currentlydown.remove("down")

        if len(self.currentlydown) > 0:
            self.setAnim()

    def arrowUpDown(self):
        #track key down
        self.topdown = True
        self.setMovement(True)
        #show changes to screen
        self.currentlydown.append("top")
        self.setAnim()

    def arrowUpUp(self):
        self.topdown = False
        self.setMovement(False)
        #show changes to screen
        if len(self.currentlydown) == 1:
            self.hideAllSubnodes()
            self.stop.show()
        if "top" in self.currentlydown:
            self.currentlydown.remove("top")
        if len(self.currentlydown) > 0:
            self.setAnim()

    def moveCharacter(self, task):
        dt = globalClock.getDt()
        if len(self.currentlydown) > 0:
            if self.currentlydown[-1] == 'left':
                self.node.setX(self.node.getX() -
                               1 * dt * self.properties['speed'])
            if self.currentlydown[-1] == 'right':
                self.node.setX(self.node.getX() +
                               1 * dt * self.properties['speed'])
            if self.currentlydown[-1] == 'top':
                self.node.setZ(self.node.getZ() +
                               1 * dt * self.properties['speed'])
            if self.currentlydown[-1] == 'down':
                self.node.setZ(self.node.getZ() -
                               1 * dt * self.properties['speed'])

        #check collisions
        if self.cTrav != None:
            self.cTrav.traverse(render)

        if self.pickCTrav != None:
            self.pickCTrav.traverse(render)

        #entries python list
        entries = list(self.collisionHandler.getEntries())
        pickentries = list(self.pickCollisionHandler.getEntries())

        for e in entries[:]:
            if e.getIntoNodePath().getName() == "characterPickTube":
                entries.remove(e)

        for e in pickentries[:]:
            if e.getIntoNodePath().getName() == "characterTube":
                pickentries.remove(e)

        if len(entries) == 0:
            self.lastpos = self.node.getPos()
        else:
            sp = entries[0].getSurfacePoint(self.node)  #surface point
            objectNode = entries[0].getIntoNodePath().getParent(
            )  #into object node
            groundNode = entries[0].getIntoNodePath()  #into object node

            if objectNode.hasTag("collideandwalk"):
                if objectNode.getTag("collideandwalk") != "yes":
                    self.node.setPos(self.lastpos)
            else:
                self.node.setPos(self.lastpos)

            #if node is a real object (not a wall)
            if objectNode.hasTag("avoidable"):
                if objectNode.getTag(
                        "avoidable"
                ) == "true":  #see if object is intelligently avoidable
                    if objectNode.hasTag("xscaled") and objectNode.hasTag(
                            "yscaled"):
                        if len(
                                self.currentlydown
                        ) > 0:  #at least 1, avoids list index out of range exception
                            if self.currentlydown[
                                    -1] == 'left' or self.currentlydown[
                                        -1] == 'right':  #TODO: fix the shiet, not always working
                                bottomObjPos = objectNode.getZ() - (
                                    float(objectNode.getTag("yscaled")) / 2)
                                topObjPos = objectNode.getZ() + (
                                    float(objectNode.getTag("yscaled")) / 2)
                                if self.node.getZ() < bottomObjPos:
                                    self.node.setZ(self.node.getZ() - 1 * dt *
                                                   self.properties['speed'])
                                if self.node.getZ() > topObjPos:
                                    self.node.setZ(self.node.getZ() + 1 * dt *
                                                   self.properties['speed'])
                                pass
                            if self.currentlydown[
                                    -1] == 'top' or self.currentlydown[
                                        -1] == 'down':
                                leftObjPos = objectNode.getX() - (
                                    float(objectNode.getTag("xscaled")) / 2)
                                rightObjPos = objectNode.getX() + (
                                    float(objectNode.getTag("xscaled")) / 2)

                                if self.node.getX() < leftObjPos:
                                    self.node.setX(self.node.getX() - 1 * dt *
                                                   self.properties['speed'])

                                if self.node.getX() > rightObjPos:
                                    self.node.setX(self.node.getX() + 1 * dt *
                                                   self.properties['speed'])
                            self.lastpos = self.node.getPos()

        for entry in entries:
            objectNode = entry.getIntoNodePath().getParent()
            onWalked = objectNode.getTag("onWalked")
            if len(onWalked) > 0:
                eval(onWalked)  #oh lol, danger detected here

        evaluatedOnce = False
        if self.pickRequest == True:
            for entry in pickentries:
                objectNode = entry.getIntoNodePath().getParent()
                onPicked = objectNode.getTag("onPicked")
                if len(onPicked) > 0 and evaluatedOnce == False:
                    eval(onPicked)  #oh lol, danger detected again here
                    evaluatedOnce = True
                else:
                    if hasattr(objectNode.getPythonTag('gamenode'), 'name'):
                        print "WARNING: picking on this object is not defined: ", objectNode.getPythonTag(
                            'gamenode').name
                        print "X: ", objectNode.getX()
                        print "Y: ", objectNode.getZ()
            self.pickRequest = False  #resetting request

        #this is needed for empty pick
        if self.pickRequest == True:
            self.pickRequest = False  #resetting request

        return Task.cont

    def getWorldPos(self):
        return self.node.getPos(render)

    def setX(self, x):
        self.node.setX(x)
        self.lastpos.setX(x)

    def setY(self, y):
        self.node.setZ(y)
        self.lastpos.setZ(y)

    #here for polymorph
    def getTileX(self):
        return self.parent.getX()

    #here for polymorph
    def getTileY(self):
        return self.parent.getY()
Example #43
0
class Raycaster(Entity):
    def __init__(self):
        super().__init__(name='raycaster', eternal=True)
        self._picker = CollisionTraverser()  # Make a traverser
        self._pq = CollisionHandlerQueue()  # Make a handler
        self._pickerNode = CollisionNode('raycaster')
        self._pickerNode.set_into_collide_mask(0)
        self._pickerNP = self.attach_new_node(self._pickerNode)
        self._picker.addCollider(self._pickerNP, self._pq)
        self._pickerNP.show()

    def distance(self, a, b):
        return sqrt(sum((a - b)**2 for a, b in zip(a, b)))

    def raycast(self,
                origin,
                direction=(0, 0, 1),
                distance=inf,
                traverse_target=scene,
                ignore=list(),
                debug=False):
        self.position = origin
        self.look_at(self.position + direction)
        self._pickerNode.clearSolids()
        # if thickness == (0,0):
        if distance == inf:
            ray = CollisionRay()
            ray.setOrigin(Vec3(0, 0, 0))
            # ray.setDirection(Vec3(0,1,0))
            ray.setDirection(Vec3(0, 0, 1))
        else:
            # ray = CollisionSegment(Vec3(0,0,0), Vec3(0,distance,0))
            ray = CollisionSegment(Vec3(0, 0, 0), Vec3(0, 0, distance))

        self._pickerNode.addSolid(ray)

        if debug:
            self._pickerNP.show()
        else:
            self._pickerNP.hide()

        self._picker.traverse(traverse_target)

        if self._pq.get_num_entries() == 0:
            self.hit = HitInfo(hit=False)
            return self.hit

        ignore += tuple([e for e in scene.entities if not e.collision])

        self._pq.sort_entries()
        self.entries = [  # filter out ignored entities
            e for e in self._pq.getEntries()
            if e.get_into_node_path().parent not in ignore
        ]

        if len(self.entries) == 0:
            self.hit = HitInfo(hit=False)
            return self.hit

        self.collision = self.entries[0]
        nP = self.collision.get_into_node_path().parent
        point = self.collision.get_surface_point(nP)
        # point = Vec3(point[0], point[2], point[1])
        point = Vec3(point[0], point[1], point[2])
        world_point = self.collision.get_surface_point(render)
        # world_point = Vec3(world_point[0], world_point[2], world_point[1])
        world_point = Vec3(world_point[0], world_point[1], world_point[2])
        hit_dist = self.distance(self.world_position, world_point)

        if nP.name.endswith('.egg'):
            nP = nP.parent

        self.hit = HitInfo(hit=True)
        for e in scene.entities:
            if e == nP:
                # print('cast nP to Entity')
                self.hit.entity = e

        self.hit.point = point
        self.hit.world_point = world_point
        self.hit.distance = hit_dist

        self.hit.normal = Vec3(*self.collision.get_surface_normal(
            self.collision.get_into_node_path().parent).normalized())
        self.hit.world_normal = Vec3(
            *self.collision.get_surface_normal(render).normalized())
        return self.hit

        self.hit = HitInfo(hit=False)
        return self.hit

    def boxcast(self,
                origin,
                direction=(0, 0, 1),
                distance=9999,
                thickness=(1, 1),
                traverse_target=scene,
                ignore=list(),
                debug=False):
        if isinstance(thickness, (int, float, complex)):
            thickness = (thickness, thickness)

        temp = Entity(position=origin,
                      model='cube',
                      origin_z=-.5,
                      scale=Vec3(abs(thickness[0]), abs(thickness[1]),
                                 abs(distance)),
                      collider='box',
                      color=color.white33,
                      always_on_top=debug,
                      visible=debug)
        temp.look_at(origin + direction)
        hit_info = temp.intersects(traverse_target=traverse_target,
                                   ignore=ignore)
        if debug:
            temp.collision = False
            destroy(temp, delay=.1)
        else:
            destroy(temp)
        return hit_info
Example #44
0
class Mouse():
    def __init__(self):
        self.enabled = False
        self.locked = False
        self.position = Vec3(0, 0, 0)
        self.delta = Vec3(0, 0, 0)
        self.prev_x = 0
        self.prev_y = 0
        self.start_x = 0
        self.start_y = 0
        self.velocity = Vec3(0, 0, 0)
        self.prev_click_time = time.time()
        self.double_click_distance = .5

        self.hovered_entity = None  # returns the closest hovered entity with a collider.
        self.left = False
        self.right = False
        self.middle = False
        self.delta_drag = Vec3(0, 0, 0)

        self.update_step = 1
        self.traverse_target = scene
        self._i = 0
        self._mouse_watcher = None
        self._picker = CollisionTraverser()  # Make a traverser
        self._pq = CollisionHandlerQueue()  # Make a handler
        self._pickerNode = CollisionNode('mouseRay')
        self._pickerNP = camera.attach_new_node(self._pickerNode)
        self._pickerRay = CollisionRay()  # Make our ray
        self._pickerNode.addSolid(self._pickerRay)
        self._picker.addCollider(self._pickerNP, self._pq)
        self._pickerNode.set_into_collide_mask(0)

        self.raycast = True
        self.collision = None
        self.collisions = list()
        self.enabled = True

    @property
    def x(self):
        if not self._mouse_watcher.has_mouse():
            return 0
        return self._mouse_watcher.getMouseX(
        ) / 2 * window.aspect_ratio  # same space as ui stuff

    @x.setter
    def x(self, value):
        self.position = (value, self.y)

    @property
    def y(self):
        if not self._mouse_watcher.has_mouse():
            return 0

        return self._mouse_watcher.getMouseY() / 2

    @y.setter
    def y(self, value):
        self.position = (self.x, value)

    @property
    def position(self):
        return Vec3(self.x, self.y, 0)

    @position.setter
    def position(self, value):
        base.win.move_pointer(
            0,
            round(value[0] + (window.size[0] / 2) +
                  (value[0] / 2 * window.size[0]) *
                  1.124),  # no idea why I have * with 1.124
            round(value[1] + (window.size[1] / 2) -
                  (value[1] * window.size[1])),
        )

    def __setattr__(self, name, value):

        if name == 'visible':
            window.set_cursor_hidden(not value)
            application.base.win.requestProperties(window)

        if name == 'locked':
            try:
                object.__setattr__(self, name, value)
                window.set_cursor_hidden(value)
                if value:
                    window.set_mouse_mode(window.M_relative)
                else:
                    window.set_mouse_mode(window.M_absolute)

                application.base.win.requestProperties(window)
            except:
                pass

        try:
            super().__setattr__(name, value)
            # return
        except:
            pass

    def input(self, key):
        if not self.enabled:
            return

        if key.endswith('mouse down'):
            self.start_x = self.x
            self.start_y = self.y

        elif key.endswith('mouse up'):
            self.delta_drag = Vec3(self.x - self.start_x,
                                   self.y - self.start_y, 0)

        if key == 'left mouse down':
            self.left = True
            if self.hovered_entity:
                if hasattr(self.hovered_entity, 'on_click'):
                    self.hovered_entity.on_click()
                for s in self.hovered_entity.scripts:
                    if hasattr(s, 'on_click'):
                        s.on_click()
            # double click
            if time.time(
            ) - self.prev_click_time <= self.double_click_distance:
                base.input('double click')

                if self.hovered_entity:
                    if hasattr(self.hovered_entity, 'on_double_click'):
                        self.hovered_entity.on_double_click()
                    for s in self.hovered_entity.scripts:
                        if hasattr(s, 'on_double_click'):
                            s.on_double_click()

            self.prev_click_time = time.time()

        if key == 'left mouse up':
            self.left = False
        if key == 'right mouse down':
            self.right = True
        if key == 'right mouse up':
            self.right = False
        if key == 'middle mouse down':
            self.middle = True
        if key == 'middle mouse up':
            self.middle = False

    def update(self):
        if not self.enabled or not self._mouse_watcher.has_mouse():
            self.velocity = Vec3(0, 0, 0)
            return

        self.moving = self.x + self.y != self.prev_x + self.prev_y

        if self.moving:
            if self.locked:
                self.velocity = self.position
                self.position = (0, 0)
            else:
                self.velocity = Vec3(self.x - self.prev_x,
                                     (self.y - self.prev_y) /
                                     window.aspect_ratio, 0)
        else:
            self.velocity = Vec3(0, 0, 0)

        if self.left or self.right or self.middle:
            self.delta = Vec3(self.x - self.start_x, self.y - self.start_y, 0)

        self.prev_x = self.x
        self.prev_y = self.y

        self._i += 1
        if self._i < self.update_step:
            return
        # collide with ui
        self._pickerNP.reparent_to(scene.ui_camera)
        self._pickerRay.set_from_lens(camera._ui_lens_node,
                                      self.x * 2 / window.aspect_ratio,
                                      self.y * 2)
        self._picker.traverse(camera.ui)
        if self._pq.get_num_entries() > 0:
            # print('collided with ui', self._pq.getNumEntries())
            self.find_collision()
            return

        # collide with world
        self._pickerNP.reparent_to(camera)
        self._pickerRay.set_from_lens(scene.camera.lens_node,
                                      self.x * 2 / window.aspect_ratio,
                                      self.y * 2)
        try:
            self._picker.traverse(self.traverse_target)
        except:
            # print('error: mouse._picker could not traverse', self.traverse_target)
            return

        if self._pq.get_num_entries() > 0:
            self.find_collision()
        else:
            # print('mouse miss', base.render)
            # unhover all if it didn't hit anything
            for entity in scene.entities:
                if hasattr(entity, 'hovered') and entity.hovered:
                    entity.hovered = False
                    self.hovered_entity = None
                    if hasattr(entity, 'on_mouse_exit'):
                        entity.on_mouse_exit()
                    for s in entity.scripts:
                        if hasattr(s, 'on_mouse_exit'):
                            s.on_mouse_exit()

    @property
    def normal(self):
        if not self.collision:
            return None
        return self.collision.normal

    @property
    def world_normal(self):
        if not self.collision:
            return None
        return self.collision.world_normal

    @property
    def point(self):  # returns the point hit in local space
        if self.collision:
            return self.collision.point
        return None

    @property
    def world_point(self):
        if self.collision:
            return self.collision.world_point
        return None

    def find_collision(self):
        self.collisions = list()
        self.collision = None
        if not self.raycast or self._pq.get_num_entries() == 0:
            self.unhover_everything_not_hit()
            return False

        self._pq.sortEntries()

        for entry in self._pq.getEntries():
            for entity in scene.entities:
                if entry.getIntoNodePath(
                ).parent == entity and entity.collision:
                    if entity.collision:
                        hit = HitInfo(
                            hit=entry.collided(),
                            entity=entity,
                            distance=distance(entry.getSurfacePoint(scene),
                                              camera.getPos()),
                            point=entry.getSurfacePoint(entity),
                            world_point=entry.getSurfacePoint(scene),
                            normal=entry.getSurfaceNormal(entity),
                            world_normal=entry.getSurfaceNormal(scene),
                        )
                        self.collisions.append(hit)
                        break

        if self.collisions:
            self.collision = self.collisions[0]
            self.hovered_entity = self.collision.entity
            if not self.hovered_entity.hovered:
                self.hovered_entity.hovered = True
                if hasattr(self.hovered_entity, 'on_mouse_enter'):
                    self.hovered_entity.on_mouse_enter()
                for s in self.hovered_entity.scripts:
                    if hasattr(s, 'on_mouse_enter'):
                        s.on_mouse_enter()

        self.unhover_everything_not_hit()

    def unhover_everything_not_hit(self):
        for e in scene.entities:
            if e == self.hovered_entity:
                continue

            if e.hovered:
                e.hovered = False
                if hasattr(e, 'on_mouse_exit'):
                    e.on_mouse_exit()
                for s in e.scripts:
                    if hasattr(s, 'on_mouse_exit'):
                        s.on_mouse_exit()
Example #45
0
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