Ejemplo n.º 1
0
def isCmListCmListCollided(objcmlist0, objcmlist1, toggleplot=False):
    """
    detect the collision between two collision model lists

    :return: True or False

    author: weiwei, Toyonaka
    date: 20190422
    """

    oocnp = NodePath("collision nodepath")
    obj0cnplist = []
    for objcm0 in objcmlist0:
        obj0cnplist.append(objcm0.copycdnpTo(oocnp))
    obj1cnplist = []
    for objcm1 in objcmlist1:
        obj1cnplist.append(objcm1.copycdnpTo(oocnp))
    if toggleplot:
        oocnp.reparentTo(base.render)
        for obj0cnp in obj0cnplist:
            obj0cnp.show()
        for obj1cnp in obj1cnplist:
            obj1cnp.show()
    ctrav = CollisionTraverser()
    chan = CollisionHandlerQueue()
    for obj0cnp in obj0cnplist:
        obj0cnp.node().setFromCollideMask(BitMask32(0x1))
        obj0cnp.setCollideMask(BitMask32(0x2))
        ctrav.addCollider(obj0cnp, chan)
    ctrav.traverse(oocnp)
    if chan.getNumEntries() > 0:
        return True
    else:
        return False
Ejemplo n.º 2
0
class ColTime(DirectObject.DirectObject):
    def __init__(self):
        self.colahand = CollisionHandlerEvent()
        #self.que=CollisionHandlerQueue()
        self.loc = CollisionTraverser()
        self.anim = loader.loadModel("BO1.egg")
        self.simco = CollisionNode("sim")
        self.simco.addSolid(
            CollisionSphere(self.anim.node().getBounds().getCenter(),
                            self.anim.node().getBounds().getRadius() * 1.2))
        self.colahand.addAgainPattern("modelintoacube-%in")
        self.simco = self.anim.attachNewNode(self.simco)
        self.accept("modelintoacube-sim", self.sim)
        self.loc.addCollider(self.simco, self.colahand)
        self.loc.addCollider(hifi.modcollision, self.colahand)
        taskMgr.add(self.startingcol, "StartingCol")
        #messenger.send("sim",[self.simco])

        self.anim.reparentTo(render)

    def sim(self, colEntry):
        colEntry.getIntoNodePath().removeNode()

    def startingcol(self, task):
        self.loc.traverse(render)
        return task.cont
Ejemplo n.º 3
0
def checkcmcdlistlist(objcmlist0, objcmlist1, toggleplot=False):
    """
    detect the collision between two collision model lists

    :return: True or False

    author: weiwei, Toyonaka
    date: 20190422
    """

    oocnp0 = NodePath("collision nodepath")
    oocnp1 = NodePath("collision nodepath")
    obj0cnplist = []
    for objcm0 in objcmlist0:
        obj0cnplist.append(objcm0.copycdnpTo(oocnp0))
    obj1cnplist = []
    for objcm1 in objcmlist1:
        obj1cnplist.append(objcm1.copycdnpTo(oocnp1))
    if toggleplot:
        oocnp0.reparentTo(base.render)
        oocnp1.reparentTo(base.render)
        for obj0cnp in obj0cnplist:
            obj0cnp.show()
        for obj1cnp in obj1cnplist:
            obj1cnp.show()
    ctrav = CollisionTraverser()
    chan = CollisionHandlerQueue()
    for obj0cnp in obj0cnplist:
        ctrav.addCollider(obj0cnp, chan)
    ctrav.traverse(oocnp1)
    if chan.getNumEntries() > 0:
        return True
    else:
        return False
Ejemplo n.º 4
0
def checkcmcd(objcm1, objcm2, toggleplot=False):
    """
    detect the collision between collision models

    :return: True or False

    author: weiwei, Toyonaka
    date: 20190312
    """

    oocnp = NodePath("collision nodepath")
    obj1cnp = objcm1.copycdnpTo(oocnp)
    obj2cnp = objcm2.copycdnpTo(oocnp)
    if toggleplot:
        oocnp.reparentTo(base.render)
        obj1cnp.show()
        obj2cnp.show()
    ctrav = CollisionTraverser()
    chan = CollisionHandlerQueue()
    ctrav.addCollider(obj1cnp, chan)
    ctrav.traverse(oocnp)
    if chan.getNumEntries() > 0:
        return True
    else:
        return False
Ejemplo n.º 5
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
Ejemplo n.º 6
0
def isCmCmListCollided(objcm, objcmlist, toggleplot=False):
    """
    detect the collision between a collision model and a collision model list

    :return: True or False

    author: weiwei, Toyonaka
    date: 20190312
    """

    oocnp = NodePath("collision nodepath")
    objcnp = objcm.copycdnpTo(oocnp)
    objcnplist = []
    for objcm2 in objcmlist:
        objcnplist.append(objcm2.copycdnpTo(oocnp))
    if toggleplot:
        oocnp.reparentTo(base.render)
        objcnp.show()
        for obj2cnp in objcnplist:
            obj2cnp.show()
    ctrav = CollisionTraverser()
    chan = CollisionHandlerQueue()
    ctrav.addCollider(objcnp, chan)
    ctrav.traverse(oocnp)
    if chan.getNumEntries() > 0:
        return True
    else:
        return False
Ejemplo n.º 7
0
class Mouse(DirectObject):
    def __init__(self, levelNP):
        self.setCursor()
        # store the nodepath to the level collisions
        # will be used to check for intersections with the mouse ray
        self.levelNP = levelNP
        # Setup a traverser for the picking collisions
        self.picker = CollisionTraverser()
        # Setup mouse ray
        self.pq = CollisionHandlerQueue()
        # Create a collision Node
        pickerNode = CollisionNode('MouseRay')
        # set the nodes collision bitmask
        pickerNode.setFromCollideMask(BitMask32.bit(1))#GeomNode.getDefaultCollideMask())
        # create a collision ray
        self.pickerRay = CollisionRay()
        # add the ray as a solid to the picker node
        pickerNode.addSolid(self.pickerRay)
        # create a nodepath with the camera to the picker node
        self.pickerNP = base.camera.attachNewNode(pickerNode)
        # add the nodepath to the base traverser
        self.picker.addCollider(self.pickerNP, self.pq)

    def setCursor(self):
        base.win.clearRejectedProperties()
        props = WindowProperties()
        if sys.platform.startswith('linux'):
            props.setCursorFilename("./assets/cursor.x11")
        else:
            props.setCursorFilename("./assets/cursor.ico")
        base.win.requestProperties(props)

    def getMousePos(self):
        # check if we have a mouse on the window
        if base.mouseWatcherNode.hasMouse():
            # get the mouse position on the screen
            mpos = base.mouseWatcherNode.getMouse()
            # set the ray's position
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            # Now call the traverse function to let the traverser check for collisions
            # with the added colliders and the levelNP
            self.picker.traverse(self.levelNP)
            # check if we have a collision
            if self.pq.getNumEntries() > 0:
                # sort the entries to get the closest first
                self.pq.sortEntries()
                # This is the point at where the mouse ray and the level plane intersect
                hitPos = self.pq.getEntry(0).getSurfacePoint(render)
                return hitPos
        return Point3(0, 0, 0)

        task.cont
Ejemplo n.º 8
0
class MouseCollision:
    def __init__(self, game):

        self.game = game

        self.c_trav = CollisionTraverser()

        self.mouse_groundHandler = CollisionHandlerQueue()
        self.mouse_ground_ray = CollisionRay()
        self.mouse_ground_col = CollisionNode('mouseRay')

        self.mouse_ground_ray.setOrigin(0, 0, 0)
        self.mouse_ground_ray.setDirection(0, -1, 0)

        self.mouse_ground_col.addSolid(self.mouse_ground_ray)
        self.mouse_ground_col.setFromCollideMask(CollideMask.bit(0))
        self.mouse_ground_col.setIntoCollideMask(CollideMask.allOff())

        self.mouse_ground_col_np = self.game.camera.attachNewNode(
            self.mouse_ground_col)

        self.c_trav.addCollider(self.mouse_ground_col_np,
                                self.mouse_groundHandler)

        self.game.taskMgr.add(self.update, 'updateMouse')

    def update(self, task):

        if self.game.mouseWatcherNode.hasMouse():
            if self.game.ship.model:

                mouse_pos = self.game.mouseWatcherNode.getMouse()

                self.mouse_ground_ray.setFromLens(self.game.camNode,
                                                  mouse_pos.getX(),
                                                  mouse_pos.getY())

                near_point = render.getRelativePoint(
                    self.game.camera, self.mouse_ground_ray.getOrigin())
                near_vec = render.getRelativeVector(
                    self.game.camera, self.mouse_ground_ray.getDirection())

                self.game.ship.shipPoint.setPos(
                    self.PointAtY(self.game.ship.model.getY(), near_point,
                                  near_vec))

        return task.cont

    def PointAtY(self, y, point, vec):
        return point + vec * ((y - point.getY()) / vec.getY())
Ejemplo n.º 9
0
class Mouse(object):
    def __init__(self, base):
        self.base = base
        if settings.mouse_over:
            taskMgr.add(self.mouse_task, 'mouse-task')
        self.picker = CollisionTraverser()
        self.pq = CollisionHandlerQueue()
        self.pickerNode = CollisionNode('mouseRay')
        self.pickerNP = self.base.cam.attachNewNode(self.pickerNode)
        self.pickerNode.setFromCollideMask(
            CollisionNode.getDefaultCollideMask()
            | GeomNode.getDefaultCollideMask())
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        self.picker.addCollider(self.pickerNP, self.pq)
        #self.picker.showCollisions(render)
        self.over = None

    def find_over(self):
        over = None
        if self.base.mouseWatcherNode.hasMouse():
            mpos = self.base.mouseWatcherNode.getMouse()
            self.pickerRay.setFromLens(self.base.camNode, mpos.getX(),
                                       mpos.getY())
            self.picker.traverse(render)
            if self.pq.getNumEntries() > 0:
                self.pq.sortEntries()
                np = self.pq.getEntry(0).getIntoNodePath().findNetPythonTag(
                    'owner')
                owner = np.getPythonTag('owner')
                over = owner
                np = self.pq.getEntry(0).getIntoNodePath().findNetPythonTag(
                    'patch')
                if np is not None:
                    self.patch = np.getPythonTag('patch')
                else:
                    self.patch = None
        return over

    def get_over(self):
        if settings.mouse_over:
            over = self.over
        else:
            over = self.find_over()
        return over

    def mouse_task(self, task):
        if self.mouseWatcherNode.hasMouse():
            self.over = self.find_over()
        return Task.cont
Ejemplo n.º 10
0
class SmartCar(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        # Override defaults
        self.disableMouse()
        self.setBackgroundColor(VBase3(160, 200, 150) / 255.0)
        self.setFrameRateMeter(True)

        # Lights
        dlight = DirectionalLight("dlight")
        dlnp = self.render.attachNewNode(dlight)
        dlnp.setHpr(180.0, -70.0, 0)
        self.render.setLight(dlnp)

        alight = AmbientLight("alight")
        alnp = self.render.attachNewNode(alight)
        alight.setColor(VBase4(0.4, 0.4, 0.4, 1))
        self.render.setLight(alnp)

        # Collision traverser
        self.cTrav = CollisionTraverser("collisionTraverser")

        # Collision handlers
        self.carCollisionHandler = CollisionHandlerEvent()
        self.carCollisionHandler.addInPattern("%fn-into-%in")

        # Camera controls
        self.cameraController = CameraController(self, 400, math.pi / 4.0, math.pi / 4.0)

        # Load the track
        self.track = self.loader.loadModel("models/trackValencia")
        checkpointsCollision = self.track.find("checkpoints").node()
        checkpointsCollision.setIntoCollideMask(BitMask32(0xF0))
        self.numCheckpoints = checkpointsCollision.getNumSolids()
        self.track.reparentTo(self.render)

        # Load the car
        self.car = NeuralNetworkCar(self)
        self.cameraController.follow(self.car.getNodePath())

        # Reposition the car
        # self.car.getNodePath().setH(180.0)

        # Register car collisions with track
        self.cTrav.addCollider(self.car.carCollider, self.carCollisionHandler)
        self.accept("carCollider-into-trackCollision", self.car.onCrash)
        self.accept("carCollider-into-checkpoints", self.car.onCheckpoint)
Ejemplo n.º 11
0
class PlayerObject():
	def __init__(self, render, player):
		self.username = player.getUsername()
		self.isMoving = False
		self.render = render

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

		self.actor = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"})
		self.actor.reparentTo(render)
		self.actor.setScale(0.2)
		self.actor.setPos(player.getX(), player.getY(), player.getZ())
		self.actor.setH(player.getH())

		self.cTrav = CollisionTraverser()
		self.GroundRay = CollisionRay()
		self.GroundRay.setOrigin(0,0,1000)
		self.GroundRay.setDirection(0,0,-1)
		self.GroundCol = CollisionNode('actorRay')
		self.GroundCol.addSolid(self.GroundRay)
		self.GroundCol.setFromCollideMask(BitMask32.bit(0))
		self.GroundCol.setIntoCollideMask(BitMask32.allOff())
		self.GroundColNp = self.actor.attachNewNode(self.GroundCol)
		self.GroundHandler = CollisionHandlerQueue()
		self.cTrav.addCollider(self.GroundColNp, self.GroundHandler)

# 	def getUsername(self):
# 		return self.username
	
	def getActor(self):
		return self.actor
	
	def setPos(self, x, y, z):
		self.actor.setPos(x, y, z)
		
	def setH(self, h):
		self.actor.setH(h)

	def move(self, isActorMove):
		if isActorMove == "True":
			if self.isMoving is False:
				self.actor.loop("run")
				self.isMoving = True
		else:
			if self.isMoving:
				self.actor.stop()
				self.actor.pose("walk",5)
				self.isMoving = False
Ejemplo n.º 12
0
class Colisiones:
    def __init__(self, energy, jeep):

        self.bebidas = 0
        self.energy = energy
        self.crash = []
        self.jeep = jeep
        """  ---------------------- Prepara las Colisiones ---------------------- """

        self.cs = CollisionSphere(0, 0, 0, 20)
        cont = 0
        while (cont < 80):
            self.crash.append(self.energy[cont].attachNewNode(
                CollisionNode(str(cont))))
            self.crash[cont].node().addSolid(self.cs)
            #self.crash[cont].show() Uncomment this line to see the colisions
            cont = cont + 1

        self.css = CollisionSphere(0, 0, 0, 12)
        self.cnodePath = self.jeep.attachNewNode(CollisionNode('cnode'))
        self.cnodePath.node().addSolid(self.css)

        #self.cnodePath.show() Uncomment this line to see the colisions

        self.traverser = CollisionTraverser()
        self.queue = CollisionHandlerQueue()
        """ --------------------------------------------------------------------- """

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

    def choque(self, task):

        self.traverser.addCollider(self.cnodePath, self.queue)
        self.traverser.traverse(render)
        for i in range(self.queue.getNumEntries()):
            entry = self.queue.getEntry(i)
            self.energy[int(entry.getIntoNode().getName())].setPos(0, 0, 5000)
            self.bebidas = self.bebidas + 1
            global texta
            texta.destroy()
            texta = addText(
                0.9, -1.2,
                "Hasta Ahora LLevamos " + str(self.bebidas) + " Bebidas", 0.07)
        return Task.cont
Ejemplo n.º 13
0
class Colisiones:

    def __init__(self, energy, jeep):

        self.bebidas = 0
        self.energy = energy
        self.crash = []
        self.jeep = jeep

        """  ---------------------- Prepara las Colisiones ---------------------- """
        
        self.cs = CollisionSphere(0, 0, 0, 20)
        cont = 0
        while( cont < 80 ):
            self.crash.append( self.energy[cont].attachNewNode(CollisionNode(str(cont))) )
            self.crash[cont].node().addSolid(self.cs)
            #self.crash[cont].show() Uncomment this line to see the colisions
            cont = cont + 1

        self.css = CollisionSphere(0, 0, 0, 12)
        self.cnodePath = self.jeep.attachNewNode(CollisionNode('cnode'))
        self.cnodePath.node().addSolid(self.css)

        #self.cnodePath.show() Uncomment this line to see the colisions

        self.traverser = CollisionTraverser()
        self.queue = CollisionHandlerQueue()
        
        """ --------------------------------------------------------------------- """

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

    def choque(self, task):
        
        self.traverser.addCollider(self.cnodePath, self.queue)
        self.traverser.traverse(render)
        for i in range(self.queue.getNumEntries()):
            entry = self.queue.getEntry(i)
            self.energy[int( entry.getIntoNode().getName() )].setPos(0,0,5000)
            self.bebidas = self.bebidas + 1
            global texta
            texta.destroy()
            texta = addText( 0.9, -1.2,  "Hasta Ahora LLevamos " + str(self.bebidas) + " Bebidas", 0.07 )
        return Task.cont
Ejemplo n.º 14
0
class MouseCollision:
    def __init__(self, game):

        self.game = game

        self.c_trav = CollisionTraverser()

        self.mouse_groundHandler = CollisionHandlerQueue()
        self.mouse_ground_ray = CollisionRay()
        self.mouse_ground_col = CollisionNode('mouseRay')

        self.mouse_ground_ray.setOrigin(0, 0, 0)
        self.mouse_ground_ray.setDirection(0, -1, 0)

        self.mouse_ground_col.addSolid(self.mouse_ground_ray)
        self.mouse_ground_col.setFromCollideMask(CollideMask.bit(0))
        self.mouse_ground_col.setIntoCollideMask(CollideMask.allOff())

        self.mouse_ground_col_np = self.game.camera.attachNewNode(self.mouse_ground_col)

        self.c_trav.addCollider(self.mouse_ground_col_np, self.mouse_groundHandler)

        self.game.taskMgr.add(self.update, 'updateMouse')

    def update(self, task):

        if self.game.mouseWatcherNode.hasMouse():
            if self.game.ship.model:

                mouse_pos = self.game.mouseWatcherNode.getMouse()

                self.mouse_ground_ray.setFromLens(self.game.camNode, mouse_pos.getX(), mouse_pos.getY())

                near_point = render.getRelativePoint(self.game.camera, self.mouse_ground_ray.getOrigin())
                near_vec = render.getRelativeVector(self.game.camera, self.mouse_ground_ray.getDirection())

                self.game.ship.shipPoint.setPos(self.PointAtY(self.game.ship.model.getY(), near_point, near_vec))

        return task.cont

    def PointAtY(self, y, point, vec):
        return point + vec * ((y - point.getY()) / vec.getY())
Ejemplo n.º 15
0
class MouseHandler:
    def __init__(self, camera, level):
        self.camera = camera
        self.level = level
        self.handler = CollisionHandlerQueue()
        self.traverser = CollisionTraverser('traverser')
        pickerNode = CollisionNode('mouseRay')
        pickerNP = self.camera.attachNewNode(pickerNode)
        pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.pickerRay = CollisionRay()
        pickerNode.addSolid(self.pickerRay)
        self.traverser.addCollider(pickerNP, self.handler)

    def pick_node(self, mpos):
        self.pickerRay.setFromLens(self.camera.getChild(0).node(), mpos.getX(), mpos.getY())
        self.traverser.traverse(self.level)

        if self.handler.getNumEntries() > 0:
            self.handler.sortEntries()
            node = self.handler.getEntry(0).getIntoNodePath()
            if not node.isEmpty():
                return node
Ejemplo n.º 16
0
class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        # Create player node and attach camera and collision node/solid
        self.Player = render.attachNewNode('Player')
        self.camera.reparentTo(self.Player)
        self.PlayerCN = CollisionNode('Player')
        self.PlayerCNP = self.Player.attachNewNode(self.PlayerCN)
        self.PlayerCSph = CollisionSphere(0, 0, 0, 1)
        self.PlayerCN.addSolid(self.PlayerCSph)
        # Player collision sphere
        playerCS = CollisionSphere(0, 0, 0, 2)
        playerCNP = self.Player.attachNewNode(CollisionNode('cnode'))
        playerCNP.node().addSolid(playerCS)
        #PlayerCNP.reparentTo(self.camera)
        playerCNP.show() # This won't show since we are inside
        
        # Create generic sphere in the world in front of us to see
        self.Sphere = self.loader.loadModel("models/misc/sphere")
        self.Sphere.reparentTo(self.render)
        self.Sphere.setPos(0, 20, -0.2)
        # Collision sphere for visible sphere, slightly larger
        cs = CollisionSphere(0, 0, 0, 1)
        cnodePath = self.Sphere.attachNewNode(CollisionNode('cSpherenode'))
        cnodePath.node().addSolid(cs)
        cnodePath.show()
        
        # Create global collision traverser
        self.cTrav = CollisionTraverser()
        # Collision handler pusher - visible sphere will push back
        self.pusher = CollisionHandlerPusher()

        # Tell player sphere to act as pusher - or world object?
        self.cTrav.addCollider(cnodePath, self.pusher)
        self.pusher.addCollider(cnodePath, self.Sphere, base.drive.node())

        seq = self.Player.posInterval(5, Point3(0, 40, 0), 
                                     startPos=Point3(0, 0, 0), fluid=1).loop()
Ejemplo n.º 17
0
class Usuario(object):
    """
    Usuario
    """

    def __init__(self, dadosUsuario, principal=False):
        self.key = dadosUsuario["key"]
        self.nick = dadosUsuario["nick"]
        self.vida_real = float(dadosUsuario["vida_real"])
        self.vida_total = float(dadosUsuario["vida_total"])
        self.mana_real = float(dadosUsuario["mana_real"])
        self.mana_total = float(dadosUsuario["mana_total"])
        self.forca = float(dadosUsuario["forca"])
        self.velocidade = float(dadosUsuario["velocidade"])
        self.velocidade_atack = float(dadosUsuario["velocidade_atack"])

        self.estaMovendo = False
        self.estaRodando = False

        self.__task_name = "Task Usuario - " + self.key

        self.keyMap = {TECLA_esquerda: EVENT_up, TECLA_direita: EVENT_up, TECLA_frente: EVENT_up, TECLA_traz: EVENT_up}

        pandaFileModelo = get_path_modelo("ralph")
        pandaFileAnimacaoRun = get_path_animacao("ralph-run")
        pandaFileAnimacaoWalk = get_path_animacao("ralph-walk")

        self.modelo = Actor(pandaFileModelo, {"run": pandaFileAnimacaoRun, "walk": pandaFileAnimacaoWalk})
        self.modelo.reparentTo(render)
        self.modelo.setScale(SCALE_MODELOS)

        self.set_pos((float(dadosUsuario["x"]), float(dadosUsuario["y"]), float(dadosUsuario["z"])))
        self.set_h(float(dadosUsuario["h"]))

        if not principal:
            self.text = Text(
                parent=self.modelo, pos=(0, 0, 5.5), scale=0.5, align="center", cor=COR_VERDE, text=self.nick
            )

            self.text.billboardEffect()

        self.__setup_collision()

        taskMgr.add(self.__task_movimentacao, self.__task_name, sort=1)

    def get_x(self):
        return self.modelo.getX()

    def get_y(self):
        return self.modelo.getY()

    def get_z(self):
        return self.modelo.getZ()

    def get_h(self):
        return self.modelo.getH()

    def get_pos(self):
        return self.modelo.getPos()

    def set_x(self, x):
        self.modelo.setX(x)

    def set_y(self, y):
        self.modelo.setY(y)

    def set_z(self, z):
        self.modelo.setZ(z)

    def set_h(self, h):
        self.modelo.setH(h)

    def set_pos(self, pos):
        self.modelo.setPos(pos)

    def delete(self):
        taskMgr.remove(self.__task_name)

        self.modelo.delete()

    def __setup_collision(self):
        # Colisao
        self.cTrav = CollisionTraverser("usuarioTraverser")

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 5)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode("ralphRay")
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.modelo.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()

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

        # self.ralphGroundColNp.show()
        # self.cTrav.showCollisions(render)
        # Colisao

    def __task_movimentacao(self, task):
        dt = globalClock.getDt()
        startpos = self.modelo.getPos()

        # movimentos usuario modelo
        if self.keyMap[TECLA_esquerda] == EVENT_down and self.keyMap[TECLA_direita] == EVENT_up:
            self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt))

            if not self.estaRodando:
                self.estaRodando = True

        elif self.keyMap[TECLA_direita] == EVENT_down and self.keyMap[TECLA_esquerda] == EVENT_up:
            self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt) * -1)

            if not self.estaRodando:
                self.estaRodando = True

        elif self.estaRodando:
            self.estaRodando = False

        if self.keyMap[TECLA_frente] == EVENT_down and self.keyMap[TECLA_traz] == EVENT_up:
            self.modelo.setY(self.modelo, ((self.velocidade * 2) * dt) * -1)

            if self.estaMovendo is False:
                self.modelo.loop("run")
                self.estaMovendo = True

        elif self.keyMap[TECLA_traz] == EVENT_down and self.keyMap[TECLA_frente] == EVENT_up:
            self.modelo.setY(self.modelo, (self.velocidade * dt))

            if self.estaMovendo is False:
                self.modelo.loop("walk")
                self.estaMovendo = True

        elif self.estaMovendo:
            self.modelo.stop()
            self.modelo.pose("walk", 5)
            self.estaMovendo = False
        # movimentos usuario modelo

        if self.estaMovendo:

            self.cTrav.traverse(render)

            if self.ralphGroundHandler.getNumEntries() == 1:
                entry = self.ralphGroundHandler.getEntry(0)
                if entry.getIntoNode().getName() == "terrain":
                    self.modelo.setZ(entry.getSurfacePoint(render).getZ())
            else:
                self.modelo.setPos(startpos)

        return task.cont
Ejemplo n.º 18
0
class World(DirectObject):

    def skyBoxLoad(self):
        self.spaceSkyBox = load_model('skybox1.egg')
        self.spaceSkyBox.setScale(150)
        self.spaceSkyBox.setLightOff()
        self.spaceSkyBox.reparentTo(render)
        self.spaceSkyBox.setPos(0,0,-200)
        self.spaceSkyBox.setHpr(0,0,0)        

    def loadEnviron(self):
        self.environ = load_model("secondWorld.egg")
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)

    def loadPokemon(self):
        self.pikachu = load_model("pikachu.egg")
        self.pikachu.reparentTo(render)
        self.pikachu.setScale(1)
        # self.pikachu.setPos(0,0,1)
        # self.pikachu.place()
        self.Groudon = load_model("Groudon.egg")
        self.Groudon.reparentTo(render)
        self.Groudon.setPos(-50,0,0)        
        # self.Groudon.place()
    def loadRalph(self):
        # Create the main character, Ralph
        basePath = r"../google_drive/ball/data/models/"
        ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor(basePath+"ralph",{"run":basePath+"ralph-run",
                                  "walk":basePath+"ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos)
        self.ralph.hide()
        
    def loadMusic(self, name="palette.mp3"):
        bgmusic = load_bgmusic(name)
        bgmusic.play()                    

    def keyControl(self):
        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("w",self.setKey,["upward",1])
        self.accept("w-up",self.setKey,["upward",0])
        self.accept("s",self.setKey,["downward",1])
        self.accept("s-up",self.setKey,["downward",0])        

    def displayInformation(self):
        self.title = addTitle("My Pokemon - Roam Mode")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[Arrow Keys]: Move")
        self.inst4 = addInstructions(0.85, "[w]: look up")
        self.inst4 = addInstructions(0.80, "[s]: look down")        
        
    def __init__(self):
        self.keyMap = {"left":0, "right":0, "forward":0,"backward":0,
                       "upward":0, "downward":0, "leftward":0,"rightward":0,
                       "cam-left":0, "cam-right":0}
        # base.win.setClearColor(Vec4(0,0,0,1))
        self.above = 3.0
        # load sky box
        self.skyBoxLoad()
        # load environment
        self.loadEnviron()
        # load pokemon
        self.loadPokemon()
        # load ralph
        self.loadRalph()
        # load music
        self.loadMusic()
        self.displayInformation()
        self.keyControl()
        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)
        taskMgr.add(self.move,"moveTask")
        taskMgr.add(self.setAbove,"setAbove")
        # Game state variables
        self.isMoving = False
        # Set up the camera
        base.disableMouse()
        base.camera.setPos(self.ralph.getX(),self.ralph.getY(),2)
        self.cTrav = CollisionTraverser()
        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,1000)
        self.ralphGroundRay.setDirection(0,0,-1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.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,1000)
        self.camGroundRay.setDirection(0,0,-1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.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(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def setAbove(self,task):
        if self.keyMap["upward"] == 1:
            self.above += 0.1
        if self.keyMap["downward"] == 1:
            self.above -= 0.1
        return task.cont
    #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):

        # 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"]!=0):
            self.ralph.setH(self.ralph.getH() + 113 * globalClock.getDt())
            base.camera.setX(base.camera, +20 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 113 * globalClock.getDt())
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -75 * globalClock.getDt())
        if (self.keyMap["backward"] != 0):
            pass
            #self.ralph.setY(self.ralph, 75 * globalClock.getDt())
        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0):# or (self.keyMap["backward"]!=0):
            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() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec*(5-camdist))
            camdist = 5.0

        # Now check for collisions.

        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 = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     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 = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.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.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + self.above)#self.above)
        
        base.camera.lookAt(self.floater)
        return task.cont
Ejemplo n.º 19
0
class TunnelPinchTask(ShowBase, GripStateMachine):
    DATA_DIR = 'data'
    
    def __init__(self, id, session, hand, block, mode, wrist):
        ShowBase.__init__(self)
        GripStateMachine.__init__(self)
        base.disableMouse()
        wp = WindowProperties()
        wp.setSize(1920,1080)
        wp.setFullscreen(True)
        wp.setUndecorated(True)
        base.win.requestProperties(wp)

        self.sub_id = str(id)
        self.sess_id = str(session)
        self.hand = str(hand)
        self.block = str(block)
        self.mode = str(mode)
        self.wrist = str(wrist)
        
        self.prev_blk = os.path.join(self.DATA_DIR,'exp_2',self.sub_id,self.sess_id,self.wrist,self.hand,"B0")
        self.exp_blk0 = os.path.join(self.DATA_DIR,'exp_1',self.sub_id,self.sess_id,self.wrist,self.hand,"B0")
        self.table = np.loadtxt('src/tunnel_pinch_task/trialtable_flex.csv',dtype='str',delimiter=',',skiprows=1)

        indices = {}
        try:
            self.prev_table = np.loadtxt(os.path.join(self.prev_blk, 'final_targets.csv'),dtype='str',delimiter=',',skiprows=1)
        except:
            try:
                self.prev_table = np.loadtxt(os.path.join(self.exp_blk0, 'final_targets.csv'),dtype='str',delimiter=',',skiprows=1)
            except:
                print('Previous target file not found, results may be suboptimal')
        try:
            for i in range(self.prev_table.shape[0]):
                indices[self.prev_table[i,1]] = int(self.prev_table[i,0])-1
            for i in range(self.table.shape[0]):
                self.table[i,11] = self.prev_table[indices[self.table[i,1].strip()],11]
                self.table[i,12] = self.prev_table[indices[self.table[i,1].strip()],12]
                self.table[i,13] = self.prev_table[indices[self.table[i,1].strip()],13]
        except:
            print('Invalid target file')
        
        self.table = np.array([[item.strip() for item in s] for s in self.table])

        ###################################################
        #only use rows relevant to this block
        #HARDCODED! NOTE IN LOG SHEET
        spec_table = []
        for i in range(self.table.shape[0]):
            if int(self.block)%5 == 0: #block 0 to adjust positions
                if "(p)" in self.table[i,2]:
                    spec_table.append(self.table[i])
            elif int(self.block)%5 == 1:
                if "(L)" in self.table[i,2]:
                    spec_table.append(self.table[i])
            elif int(self.block)%5 == 2:
                if "(L+t)" in self.table[i,2]:
                    spec_table.append(self.table[i])
            elif int(self.block)%5 == 3:
                if "(S)" in self.table[i,2]:
                    spec_table.append(self.table[i])
            elif int(self.block)%5 == 4:
                if "(S+t)" in self.table[i,2]:
                    spec_table.append(self.table[i])
        ###################################################
        self.table = np.array(spec_table)

        self.session_dir = os.path.join(self.DATA_DIR,'exp_2',self.sub_id,self.sess_id,self.wrist,self.hand)
        self.subjinfo = self.sub_id + '_' + self.sess_id + '_' + self.hand + '_log.yml'
        self.p_x,self.p_y,self.p_a = GET_POS(self.session_dir,self.subjinfo,self.hand,self.wrist)

        self.rotmat = ROT_MAT(self.p_a,self.hand)

        self.setup_text()
        self.setup_lights()
        self.setup_camera()
        
        self.trial_counter = 0
        self.load_models()
        self.load_audio()
        self.update_trial_command()
        self.countdown_timer = CountdownTimer()
        self.hold_timer = CountdownTimer()

        self.cTrav = CollisionTraverser()
        self.chandler = CollisionHandlerEvent()
        self.chandler.addInPattern('%fn-into-%in')
        self.chandler.addOutPattern('%fn-outof-%in')
        self.chandler.addAgainPattern('%fn-again-%in')
        self.attachcollnodes()

        taskMgr.add(self.read_data, 'read')
        for i in range(5):
            taskMgr.add(self.move_player, 'move%d' % i, extraArgs = [i], appendTask=True)
        taskMgr.add(self.log_data, 'log_data')
        taskMgr.add(self.update_state, 'update_state', sort=1)

        self.accept('space', self.space_on)
        self.accept('escape', self.clean_up)
        self.space = False
        self.statenum = list()

        self.max_time = 20
        self.med_data = None

        self.grip_dir = os.path.join(self.DATA_DIR,'exp_2',self.sub_id,self.sess_id,self.wrist,self.hand,"B"+self.block)
        if not os.path.exists(self.grip_dir):
           print('Making new folders: ' + self.grip_dir)
           os.makedirs(self.grip_dir)

        self.dev = MpDevice(RightHand(calibration_files=['calibs/cal_mat_70_v2.mat',
                                                'calibs/cal_mat_73_v2.mat',
                                                'calibs/cal_mat_56.mat',
                                                'calibs/cal_mat_58_v2.mat',
                                                'calibs/cal_mat_50.mat'], clock=mono_clock.get_time))

    ############
    #SET UP HUD#
    ############
    def setup_text(self):
        self.bgtext = OnscreenText(text='Not recording.', pos=(-0.8, 0.8),
                                 scale=0.08, fg=(0, 0, 0, 1),
                                 bg=(1, 1, 1, 1), frame=(0.2, 0.2, 0.8, 1),
                                 align=TextNode.ACenter)
        self.bgtext.reparentTo(self.aspect2d)

        self.dirtext = OnscreenText( pos=(-0.6, 0.65),
                                 scale=0.08, fg=(0, 0, 0, 1),
                                 bg=(1, 1, 1, 1), frame=(0.2, 0.2, 0.8, 1),
                                 align=TextNode.ACenter)
        self.dirtext.reparentTo(self.aspect2d)
    
    ##########################
    #SET UP SCENE AND PLAYERS#
    ##########################
    def setup_lights(self):
        pl = PointLight('pl')
        pl.setColor((1, 1, 1, 1))
        plNP = self.render.attachNewNode(pl)
        plNP.setPos(-10, -10, 10)
        self.render.setLight(plNP)
        pos = [[[0, 0, 50], [0, 0, -10]],
               [[0, -50, 0], [0, 10, 0]],
               [[-50, 0, 0], [10, 0, 0]]]
        for i in pos:
            dl = Spotlight('dl')
            dl.setColor((1, 1, 1, 1))
            dlNP = self.render.attachNewNode(dl)
            dlNP.setPos(*i[0])
            dlNP.lookAt(*i[1])
            dlNP.node().setShadowCaster(False)
            self.render.setLight(dlNP)

    def setup_camera(self):
        self.cam.setPos(0, 0, 12)
        self.cam.lookAt(0, 2, 0)
        self.camLens.setFov(90)

    def load_models(self):
        self.back_model = self.loader.loadModel('models/back')
        self.back_model.setScale(10, 10, 10)
        if self.hand == "Left":
            self.back_model.setH(90)
        self.back_model.reparentTo(self.render)

        self.player_offsets = [[self.p_x[0]-5, self.p_y[0]+3, 0], [self.p_x[1]-2.5, self.p_y[1]+4.5, 0], [self.p_x[2], self.p_y[2]+5, 0],
                                [self.p_x[3]+2.5, self.p_y[3]+4.5, 0], [self.p_x[4]+5, self.p_y[4]+3, 0]]
        self.p_col =[[0,0,250],[50,0,200],[125,0,125],[200,0,50],[250,0,0]]
        if self.hand == 'Left':
            self.p_col = self.p_col[::-1]

        self.players = list()
        self.contacts = list()        
        for counter, value in enumerate(self.player_offsets):
            self.players.append(self.loader.loadModel('models/target'))
            self.contacts.append(False)

            self.players[counter].setPos(*value)
            self.players[counter].setScale(0.2, 0.2, 0.2)
            self.players[counter].setColorScale(
                self.p_col[counter][0]/255, self.p_col[counter][1]/255, self.p_col[counter][2]/255, 1)
            self.players[counter].reparentTo(self.render)
            self.players[counter].show()

        self.target_select()

    def load_audio(self):
        self.pop = self.loader.loadSfx('audio/Blop.wav')
        self.buzz = self.loader.loadSfx('audio/Buzzer.wav')


    ############################
    #SET UP COLLISION MECHANICS#
    ############################
    def attachcollnodes(self):
        self.inside = [False]*5
        for i in range(5):
            self.fromObject = self.players[i].attachNewNode(CollisionNode('colfromNode'+str(i)))
            self.fromObject.node().addSolid(CollisionSphere(0,0,0,1))
            self.cTrav.addCollider(self.fromObject, self.chandler)

        for i in range(5):
            self.accept('colfromNode%d-into-colintoNode' % i, self.collide1,[i])
            self.accept('colfromNode%d-again-colintoNode' % i, self.collide2,[i])
            self.accept('colfromNode%d-outof-colintoNode' % i, self.collide3,[i])

    def collide1(self,f,collEntry):
        if f in self.highlighted_indices:
            self.players[f].setColorScale(0,1,0,1)
            self.tar.setColorScale(0.2,0.2,0.2,1)
            self.tar.setAlphaScale(0.7)
            self.contacts[f] = True
            taskMgr.doMethodLater(self.delay,self.too_long,'too_long%d' % f,extraArgs = [f])
                
    def collide2(self,f,collEntry):
        for i in self.highlighted_indices:
            if self.contacts[i] == False:
                return
        taskMgr.remove('too_long%d' % f)

    def collide3(self,f,collEntry):
        taskMgr.remove('too_long%d' % f)
        self.reset_fing(f)
        self.tar.setColorScale(0.1,0.1,0.1,1)
        self.tar.setAlphaScale(0.7)

    def too_long(self,f):
        self.reset_fing(f)
        self.tar.setColorScale(0.5,0.2,0.2,1)
        self.tar.setAlphaScale(0.7)

    def reset_fing(self,f):
        self.players[f].setColorScale(
                self.p_col[f][0]/255, self.p_col[f][1]/255, self.p_col[f][2]/255, 1)
        self.contacts[f] = False

    ###############
    #TARGET THINGS#
    ###############
    def show_target(self):
        self.target_select()
        self.intoObject = self.tar.attachNewNode(CollisionNode('colintoNode'))

        if self.table[self.trial_counter,7] == "sphere":
            self.intoObject.node().addSolid(CollisionSphere(0,0,0,1))
        elif self.table[self.trial_counter,7] == "cylinder":
            self.intoObject.node().addSolid(CollisionTube(0,0,-2,0,0,2,1))
        else:
            raise NameError("No such collision type")

        self.tar.show()
        self.occSolid.show()
        self.occLines.show()

        for i in range(5):
            if i not in self.highlighted_indices:
                self.players[i].hide()

    def target_select(self):
        self.tgtscx=float(self.table[self.trial_counter,14])
        self.tgtscy=float(self.table[self.trial_counter,15])
        self.tgtscz=float(self.table[self.trial_counter,16])
        tgttsx=float(self.table[self.trial_counter,11])
        tgttsy=float(self.table[self.trial_counter,12])
        tgttsz=float(self.table[self.trial_counter,13])
        tgtrx=float(self.table[self.trial_counter,17])
        tgtry=float(self.table[self.trial_counter,18])
        tgtrz=float(self.table[self.trial_counter,19])
        if self.hand == 'Left':
            tgttsx *= -1
            tgtrx *= -1

        self.static_task = (str(self.table[self.trial_counter,5]) == "True")
        self.target_model = str(self.table[self.trial_counter,6])
        self.highlighted_indices=[int(s)-1 for s in self.table[self.trial_counter,4].split(' ')]
        if self.hand == 'Left':
            self.highlighted_indices=[4-i for i in self.highlighted_indices]

        self.tgtposx = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[-2,-1],0]) + tgttsx
        self.tgtposy = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[0,1],1]) + tgttsy
        if self.hand == 'Left':
            self.tgtposx = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[0,1],0]) + tgttsx
            self.tgtposy = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[-2,-1],1]) + tgttsy
        #self.tgtposx = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,0])
        #self.tgtposy = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,1])
        self.tgtposz = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,2]) + tgttsz
        
        self.tar = self.loader.loadModel(self.target_model)
        self.tar.setScale(self.tgtscx,self.tgtscy,self.tgtscz)
        self.tar.setPos(self.tgtposx,self.tgtposy,self.tgtposz)
        self.tar.setHpr(tgtrx,tgtry,tgtrz)
        self.tar.setColorScale(0.1, 0.1, 0.1, 1)
        self.tar.setAlphaScale(0.7)
        self.tar.setTransparency(TransparencyAttrib.MAlpha)
        self.tar.reparentTo(self.render)
        self.tar.hide()

        if len(self.highlighted_indices) == 2:
            dx = self.players[self.highlighted_indices[0]].getX() - self.players[self.highlighted_indices[1]].getX()
            dy = self.players[self.highlighted_indices[0]].getY() - self.players[self.highlighted_indices[1]].getY()
            angle = math.degrees(math.atan(dy/dx))
            self.table[self.trial_counter,9] =  str(angle) + ' ' + str(angle-180)
        
        self.angs=self.table[self.trial_counter,9].split(' ')
        self.angs = [float(a) for a in self.angs]
        self.tunn_width=float(self.table[self.trial_counter,10])
        self.r = 1.5
        if int(self.block) == 0:
            self.r = 0
        self.x = [self.r*math.cos(math.radians(a)) for a in self.angs]
        self.y = [self.r*math.sin(math.radians(a)) for a in self.angs]
        self.occ = draw_shape(self.angs,self.tunn_width,self.r)
        self.occSolid = render.attachNewNode(self.occ[0])
        self.occSolid.setPos(self.tgtposx,self.tgtposy,self.tgtposz)
        self.occSolid.setColorScale(0,1,1,0)
        self.occSolid.setTransparency(TransparencyAttrib.MAlpha)
        self.occSolid.setAlphaScale(0.6)
        self.occLines = render.attachNewNode(self.occ[1])
        self.occLines.setPos(self.tgtposx,self.tgtposy,self.tgtposz)
        self.occSolid.hide()
        self.occLines.hide()
        self.delay=float(self.table[self.trial_counter,8])

        self.distances = [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]]

        #change camera to be on top of target
        self.cam.setPos(self.tgtposx, self.tgtposy - 2, 12)
        self.back_model.setPos(self.tgtposx,self.tgtposy - 2,0)
        self.cam.lookAt(self.tgtposx, self.tgtposy, 0)

    ##############
    #MOVE FINGERS#
    ##############
    def read_data(self,task):
        error, data = self.dev.read()
        if data is not None:
            data *= 0.001
            self.ts = data.time
            data = np.dot(data,self.rotmat)
            self.data = data
            if self.med_data is None:
                self.med_data = np.median(data, axis=0)

            if self.space:
                self.statenum.extend(([self.checkstate()])*len(data.time))
                
        return task.cont
        
    def move_player(self,p,task):
        if self.data is not None :
            k = p*3
            new_x = 10*np.mean(self.data[-1,k]) + self.player_offsets[p][0] - 10*self.med_data[k]
            new_y = 10*np.mean(self.data[-1,k + 1]) + self.player_offsets[p][1] - 10*self.med_data[k + 1]
            new_z = 10*np.mean(self.data[-1,k + 2]) + self.player_offsets[p][2] - 10*self.med_data[k + 2]

            #make sure digits do not cross each other
            if ((p in range(1,3) and p+1 in self.highlighted_indices and new_x > self.players[p+1].getX())
                or (p in range(2,4) and p-1 in self.highlighted_indices and new_x < self.players[p-1].getX())):
                    new_x = self.players[p].getX()
            
            #make sure digits do not cross into target
            if self.space == True and p in self.highlighted_indices:
                self.distances[p][0] = new_x - self.tar.getX()
                self.distances[p][1] = new_y - self.tar.getY()
                self.distances[p][2] = new_z - self.tar.getZ()
                self.check_pos(p)
                
            self.players[p].setPos(new_x, new_y, new_z)
            
        return task.cont
    
    def check_pos(self, p):
        x = self.distances[p][0]
        y = self.distances[p][1]
        z = self.distances[p][2]
        hit = True
        for i in range(len(self.angs)):
            p_ang = math.acos((x*self.x[i]+y*self.y[i])/(self.r*(x**2+y**2)**0.5))
            if math.sin(p_ang)*(x**2+y**2)**0.5 < self.tunn_width and p_ang < math.pi/2:
                hit = False
                break
        if (abs(z) <= 1.2 #check z location
            and x**2 + y**2 <= self.r**2 #within radius of circle
            and hit == True):
                if self.inside[p] is False:
                    self.ignore('colfromNode%d-into-colintoNode' % p)
                    self.ignore('colfromNode%d-again-colintoNode' % p)
                    self.players[p].setColorScale(1,1,0,1)
                    self.inside[p] = True
        else:
            if self.inside[p] is True and x**2 + y**2 > self.r**2:
                self.accept('colfromNode%d-into-colintoNode' % p, self.collide1,[p])
                self.accept('colfromNode%d-again-colintoNode' % p, self.collide2,[p])
                self.players[p].setColorScale(
                    self.p_col[p][0]/255, self.p_col[p][1]/255, self.p_col[p][2]/255, 1)
                self.inside[p] = False

    ##################
    #CHECK COMPLETION#
    ##################
    def close_to_target(self):
        for i in self.highlighted_indices:
            if self.contacts[i] == False:
                return False

        self.tar.setColorScale(0,1,1,1)
        return True

    def check_hold(self):
        if not self.close_to_target():
            self.hold_timer.reset(0.5)
            return False
        return self.hold_timer.elapsed() < 0

    def adjust_targets(self):
        #no adjustment if more than 2 fingers or position is prone
        if len(self.highlighted_indices) > 2 or self.wrist == 'pron':
            return

        xadj,yadj,zadj = np.mean(np.asarray(self.distances)[self.highlighted_indices],0)
        #xadj = np.mean(np.asarray(self.distances)[self.highlighted_indices][0])
        #yadj = np.mean(np.asarray(self.distances)[self.highlighted_indices][1])
        #zadj = np.mean(np.asarray(self.distances)[self.highlighted_indices][2])

        #do adjustment on all tasks with same name
        if self.hand == 'Left':
            xadj = -xadj
        for i in range(self.trial_counter+1,self.table.shape[0]):
            if self.table[i,1] == self.table[self.trial_counter,1]:
                self.table[i,11] = float(self.table[i,11]) + xadj
                self.table[i,12] = float(self.table[i,12]) + yadj
                self.table[i,13] = float(self.table[i,13]) + zadj
    
    #########
    #LOGGING#
    #########
    def play_success(self):
        if int(self.block) == 0:
            self.adjust_targets()
        self.pop.play()
        self.tar.hide()
        self.highlighted_indices = [0,1,2,3,4]

    def log_text(self):
        self.bgtext.setText('Now logging...')

    def log_data(self, task):
        if (self.trial_counter + 1) <= self.table.shape[0]:
            if self.space:
                self.log_file_name = os.path.join(self.grip_dir,
                                          self.sub_id+"_"+self.sess_id+"_"+self.hand+"_"+
                                              str(self.table[self.trial_counter,1])+"_"+str(self.table[self.trial_counter,0])+".csv" )
                self.movvars = np.column_stack((self.ts, self.statenum, self.data))
                self.statenum = []
                if self.mode=='task':
                    with open(self.log_file_name, 'ab') as f:
                        np.savetxt(f, self.movvars, fmt='%10.5f', delimiter=',')
            return task.cont
        else:
            pass

    def stoplog_text(self):
        self.dirtext.clearText()
        self.bgtext.setText('Done logging!')
        for i in range(5):
            self.players[i].show()

    #######
    #RESET#
    #######
    def delete_file(self):
        if (self.trial_counter + 1) <= self.table.shape[0]:
            self.log_file_name = os.path.join(self.grip_dir,
                                      self.sub_id+"_"+self.sess_id+"_"+self.hand+"_"+
                                          str(self.table[self.trial_counter,1])+"_"+str(self.table[self.trial_counter,0])+".csv" )
            try:
                os.remove(self.log_file_name)
            except OSError:
                pass
        else:
            pass

    def reset_baseline(self):
       self.med_data = None
                   
    def reset_keyboard_bool(self):
        self.space = False

    def hide_target(self):
        self.tar.hide()
        self.occSolid.hide()
        self.occLines.hide()
        self.intoObject.removeNode()
        self.imageObject.destroy()

    def update_trial_command(self):
        self.dirtext.setText(str(self.table[self.trial_counter,2]))
        if self.hand == 'Left':
            xfac = -0.25
        else:
            xfac = 0.25
        self.imageObject = OnscreenImage(image = str(self.table[self.trial_counter,3]),scale=(xfac,0.25,0.25),pos=(-0.8, 0, 0.3))

    def increment_trial_counter(self):
        self.trial_counter += 1
        self.update_trial_command()

    ########
    #TIMERS#
    ########
    def start_trial_countdown(self):
        self.countdown_timer.reset(self.max_time)

    def start_hold_countdown(self):
        self.hold_timer.reset(0.5)

    def start_post_countdown(self):
        self.countdown_timer.reset(2)

    def time_elapsed(self):
        return self.countdown_timer.elapsed() < 0

    #########
    #MACHINE#
    #########
    def update_state(self, task):
        self.step()
        return task.cont

    def wait_for_space(self):
        return self.space

    def space_on(self):
        self.space = True

    #####
    #END#
    #####
    def trial_counter_exceeded(self):
        return (self.trial_counter+1) > self.table.shape[0]-1

    def clean_up(self):
        #write last known positions to 'final_targets' file
        f = open('src/pinch_task/trialtable_flex.csv')
        header = f.readline().rstrip()
        np.savetxt(self.grip_dir + '/final_targets.csv',self.table,fmt='%s',header = header, delimiter=',')
        f.close()
        sys.exit()
Ejemplo n.º 20
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)
Ejemplo n.º 21
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())
Ejemplo n.º 22
0
class CameraControl(DirectObject):
    def __init__(self, panda3d):
        # Inicialización de variables
        self.winsize = [0, 0]
        self.panda3d = panda3d
        self.panda3d.mouse_on_workspace = False

        # Desabilita el comportamiento por defecto de la camara
        self.panda3d.disable_mouse()

        # Llama a la función self.window_rezise_event cuando la ventana cambia de tamaño
        self.accept('window-event', self.window_rezise_event)
        # self.panda3d.accept('aspectRatioChanged', lambda: print("ss"))
        # Creamos el punto donde se centrará la cámara
        target_pos = Point3(0., 0., 0.)

        self.panda3d.cam_target = self.panda3d.render.attach_new_node("camera_target")
        self.panda3d.cam_target.set_pos(target_pos)
        self.panda3d.camera.reparent_to(self.panda3d.cam_target)
        self.panda3d.camera.set_y(-50.)
        
        # Definimos la cambinación de teclas para el control de la camara
        self.camera_active = False

        self.orbit_mouse_btn = "mouse2"
        self.orbit_keyboard_btn = "shift"
        self.orbit_mouse_reference = None
        self.orbit_camera_reference = None

        self.pan_mouse_btn = "mouse2"
        self.pan_keyboard_btn = "mouse2"
        self.pan_mouse_reference = None
        self.pan_camera_reference = None

        self.zoom_mouse_btn = "mouse2"
        self.zoom_keyboard_btn = "control"
        self.zoom_mouse_reference = None
        self.zoom_camera_reference = None

        # Establecemos los valores máximos y minimos para el zoom
        
        self.max_zoom = 10
        self.min_zoom = 0.1
        
        # Creamos la tarea de control de la camara
        self.panda3d.task_mgr.add(self.camera_control_task, "camera_control")

        # El movimiento de la rueda del mouse controla el zoom
        self.panda3d.accept("wheel_up", self.zoom_in)
        self.panda3d.accept("wheel_down", self.zoom_out)

        # Una fución de prueba para comprobar la posición del mouse en el modelo 3d
        # self.panda3d.accept("mouse1", self.entity_select)

        # Se establece la lente ortografica en lugar de la perspectiva
        self.lens_type = "OrthographicLens"
        self.set_lens(self.lens_type)

        # Agrega un indicador de ejes en la esquina inferior izquierda
        self.corner = self.panda3d.camera.attachNewNode("corner of screen")
        # self.axis = self.panda3d.loader.loadModel("data/geom/custom-axis")
        # self.axis = self.panda3d.loader.loadModel("data/geom/view_gizmo_F")
        self.view_gizmo = list()
        self.view_gizmo.append(self.panda3d.loader.loadModel("data/geom/view_gizmo_compass"))

        # self.view_gizmo.append(self.panda3d.loader.loadModel("data/geom/view_gizmo_L"))
        # self.view_cube = ViewGizmoZone()
        # self.view_cube.set_geom(self.axis)

        for gizmo_geom in self.view_gizmo:
            gizmo_geom.setLightOff(1)
            # gizmo_geom.setColorScale(1,1,1,1)
            gizmo_geom.setShaderInput("colorborders", LVecBase4(0, 0, 0, 0.25))

            gizmo = ViewGizmoZone()
            gizmo.set_geom(gizmo_geom)
            gizmo_geom.node().setBounds(BoundingSphere(Point3(0, 0, 0), 10))
            gizmo_geom.node().setFinal(True)

            #gizmo_geom.showTightBounds()
            # gizmo_geom.showBounds()



        self.show_view_gizmo()

        # Agregamos una luz puntual en la ubicación de la camara
        plight = DirectionalLight("camera_light")
        plight.setColor((1, 1, 1, 1))
        #plight.setAttenuation((1, 0, 0))
        #print("getMaxDistance {}".format(plight.getMaxDistance()))
        self.panda3d.plight_node = self.panda3d.render.attach_new_node(plight)
        self.panda3d.plight_node.setPos(0, -50, 0)
        self.panda3d.render.setLight(self.panda3d.plight_node)
        self.panda3d.plight_node.reparentTo(self.panda3d.camera)



        # Agregamos luz ambiental que disminuya las zonas oscuras
        alight = AmbientLight('alight')
        alight.setColor((0.3, 0.3, 0.3, 1))

        alnp = self.panda3d.render.attachNewNode(alight)
        self.panda3d.render.setLight(alnp)

        #def init_select_detection(self):
        self.traverser = CollisionTraverser("")
        # self.traverser.show_collisions(self.panda3d.render)
        self.picker_ray = CollisionRay()
        self.handler = CollisionHandlerQueue()

        self.picker_node = CollisionNode('mouseRay')
        self.picker_np = self.panda3d.camera.attachNewNode(self.picker_node)
        self.picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.picker_ray = CollisionRay()
        self.picker_node.addSolid(self.picker_ray)
        self.traverser.addCollider(self.picker_np, self.handler)

    def set_lens(self, lens_type="OrthographicLens"):
        """
        Permite cambiar la lente de la camara

        :param lens_type: El tipo de lente a utilizar: OrthographicLens/PerspectiveLens
        :return: None
        """

        self.lens_type = lens_type
        width = self.panda3d.win.getXSize()
        height = self.panda3d.win.getYSize()

        if lens_type is "OrthographicLens":
            lens = OrthographicLens()
            lens.setFilmSize(width, height )
        if lens_type is "PerspectiveLens":
            lens = PerspectiveLens()
            lens.setFilmSize(width , height )
        else:
            # Default value
            lens = OrthographicLens()
            lens.setFilmSize(width / 100, height / 100)

        print("new lens {}: {} {}".format(lens_type, width / 100, height / 100))
        print(lens)
        self.panda3d.cam.node().setLens(lens)

        shader_control = self.panda3d.shader_control
        if shader_control is not None:
            shader_control.update_camera_lens(lens)

    def window_rezise_event(self, window=None):
        """
        Se activa con cualquier evento de la ventana de windows, en caso de que haya
        cambiado de tamaño la ventana regenera la lente

        :param window: Información del evento
        :return: None
        """
        if window is not None:  # Window será igual a None si la aplicación panda3d no se inició
            wp = window.getProperties()
            newsize = [wp.getXSize(), wp.getYSize()]
            if self.winsize != newsize:
                self.winsize = newsize
                self.set_lens()
                self.show_view_gizmo()

    def mouse_is_over_workspace(self):
        """
        Detecta si el mouse se encuentra dentro del area de trabajo del modelo 3d

        :return: True/False
        """
        gui_objects = app.gui_objects
        is_over_workspace = False

        if self.panda3d.mouseWatcherNode.has_mouse() and app.workspace_active:
            is_over_workspace = True
            mouse_data = self.panda3d.win.getPointer(0)
            mouse_x, mouse_y = mouse_data.getX(), mouse_data.getY()

            for name, gui_obj in gui_objects.items():

                if gui_obj.isHidden():
                    continue

                pos = gui_obj.getPos(pixel2d)
                frame_size = list(gui_obj["frameSize"])

                x0 = pos[0] + frame_size[0]
                x1 = pos[0] + frame_size[1]
                y0 = -pos[2] - frame_size[2]
                y1 = -pos[2] - frame_size[3]

                x_left = min(x0, x1)
                x_right = max(x0, x1)
                y_top = min(y0, y1)
                y_bottom = max(y0, y1)

                #if name is "status_bar":
                #print(pos)
                #print("{} {} / {} {}".format(x_left, x_right, y_top, y_bottom))

                overmouse_x = (x_left <= mouse_x <= x_right)
                overmouse_y = (y_top <= mouse_y <= y_bottom)

                # Revisa si el mouse se encuentra sobre un elemento de interfaz
                if overmouse_x and overmouse_y:

                    # print("mouse is over {}".format(name))
                    is_over_workspace = False
                    break

        app.mouse_on_workspace = is_over_workspace
        if is_over_workspace:
            get_mouse_3d_coords_task()

        return is_over_workspace

    def camera_control_task(self, task):
        """
        Se ejecuta constantemente y realiza las tareas de movimiento de la camara según las teclas presionadas
        """

        # El codigo se ejecuta si el mouse está dentro del espacio de trabajo o si ya se está realizando alguna acción
        if self.mouse_is_over_workspace() or self.camera_active:
            # Desactivamos el espacio de trabajo
            app.workspace_active = False

            # El nodo mouseWatcherNode permite recibir la entrada de mouse y teclado
            btn = self.panda3d.mouseWatcherNode

            # Obtenemos la posición del cursor
            mouse_data = self.panda3d.win.getPointer(0)
            mouse_pos = mouse_data.getX(), mouse_data.getY()

            # En función de la combinación de teclas se ejecuta una acción
            cam_task = 0
            if btn.isButtonDown(self.orbit_mouse_btn) and btn.isButtonDown(self.orbit_keyboard_btn):
                cam_task = 1
            elif btn.isButtonDown(self.zoom_mouse_btn) and btn.isButtonDown(self.zoom_keyboard_btn):
                cam_task = 2
            elif btn.isButtonDown(self.pan_mouse_btn) and btn.isButtonDown(self.pan_keyboard_btn):
                cam_task = 3

            # Orbit
            if cam_task is 1:
                self.camera_orbit(mouse_pos)
                self.camera_active = True
            else:
                self.orbit_mouse_reference = None

            # Zoom
            if cam_task is 2:
                self.camera_zoom(mouse_pos)
                self.camera_active = True
            else:
                self.zoom_mouse_reference = None

            # Pan
            if cam_task is 3:
                self.camera_pan(mouse_pos)
                self.camera_active = True
            else:
                self.pan_mouse_reference = None

            # Si la combinación de teclas no coincide con niguna acción se establece la camara como inactiva
            if cam_task is 0:
                self.camera_active = False
                # Se reactiva el espacio de trabajo
                app.workspace_active = True
                self.entity_select()
            else:
                pass
                # Actualizamos la posición de la luz puntual
                #cam = self.panda3d.camera
                #self.panda3d.plight_node.setPos(cam.get_pos(self.panda3d.render))

            # Ejecutar  solo en windows
            """if os.name == 'nt':
                # Se coloca la camra en determinadas vistas (frontal, lateral, superior, etc) al apretar el
                # teclado numérico

                # Lista de teclas http://www.kbdedit.com/manual/low_level_vk_list.html

                target = self.panda3d.cam_target
                if win32api.GetAsyncKeyState(win32con.VK_NUMPAD1):
                    target.set_hpr(0, 0, 0.)
                elif win32api.GetAsyncKeyState(win32con.VK_NUMPAD3):
                    target.set_hpr(90, 0, 0.)
                elif win32api.GetAsyncKeyState(win32con.VK_NUMPAD7):
                    target.set_hpr(0, -90, 0.)"""

        return task.cont

    def camera_orbit(self, mouse_pos):

        """
        Orbita la camara alrededor del objetivo de ésta, según la posición del mouse
        respecto del punto donde se hizo click
        """

        target = self.panda3d.cam_target

        if self.orbit_mouse_reference is None:
            self.orbit_mouse_reference = mouse_pos
            self.orbit_camera_reference = target.get_hpr()

        x_diff = self.orbit_mouse_reference[0] - mouse_pos[0]
        y_diff = self.orbit_mouse_reference[1] - mouse_pos[1]

        new_h = self.orbit_camera_reference[0] + x_diff / 4
        new_p = self.orbit_camera_reference[1] + y_diff / 4

        target.set_hpr(new_h, new_p, 0.)

    def camera_pan(self, mouse_pos):
        """
        Panea la camara alrededor del objetivo de ésta, según la posición del mouse
        respecto del punto donde se hizo click
        """
        target = self.panda3d.camera

        if self.pan_mouse_reference is None:
            self.pan_mouse_reference = mouse_pos
            self.pan_camera_reference = target.get_pos()

        x_diff = self.pan_mouse_reference[0] - mouse_pos[0]
        y_diff = self.pan_mouse_reference[1] - mouse_pos[1]

        new_x = self.pan_camera_reference[0] + x_diff / 100
        new_y = self.pan_camera_reference[1]
        new_z = self.pan_camera_reference[2] - y_diff / 100

        target.set_pos(new_x, new_y, new_z)

    def camera_zoom(self, mouse_pos):

        """
        Orbita la camara alrededor del objetivo de ésta, según la posición del mouse
        respecto del punto donde se hizo click
        """

        target = self.panda3d.cam_target

        if self.zoom_mouse_reference is None:
            self.zoom_mouse_reference = mouse_pos
            self.zoom_camera_reference = target.getScale()[0]

        y_diff = self.zoom_mouse_reference[1] - mouse_pos[1]

        new_scale = self.zoom_camera_reference * math.exp(y_diff/100)

        new_scale = max(new_scale, 0.1)
        new_scale = min(new_scale, 10)

        target.setScale(new_scale, new_scale, new_scale)

    def zoom_in(self):
        if self.mouse_is_over_workspace():
            target = self.panda3d.cam_target
            old_scale = target.getScale()[0]
            new_scale = old_scale - 0.1 * old_scale
            new_scale = max(new_scale, self.min_zoom)
            target.setScale(new_scale, new_scale, new_scale)

    def zoom_out(self):
        if self.mouse_is_over_workspace():
            target = self.panda3d.cam_target
            old_scale = target.getScale()[0]
            new_scale = old_scale + 0.1 * old_scale
            new_scale = min(new_scale, self.max_zoom)
            target.setScale(new_scale, new_scale, new_scale)

    def show_view_gizmo(self):
        """
        Agrega un indicador de ejes en la esquina inferior izquierda
        """
        scale = 0.075
        width = self.panda3d.win.getXSize()/100
        height = self.panda3d.win.getYSize()/100

        #self.corner.setPos(width / 2 - 10 * scale, 5, height / 2 - 28 * scale)
        self.corner.setPos(width / 2-1, 5, height / 2 - 2.4)

        print("DEBUG SHOW VIEW CUBE")
        print(height)
        print(height / 2 - 28 * scale)

        # Dibujar por encima de todos los objetos

        for gizmo_geom in self.view_gizmo:
            gizmo_geom.setLightOff(1)
            # gizmo_geom.setBin("fixed", 0)

            # gizmo_geom.set_two_sided(True)

            """
            Tarea pendiente:
            
            Hay que corregir un error por el cual el indicador de ejes no se dubuja por encima de todos los objetos
            pudiendo intersectarse cona las geometrías del modelo
            
            Simplemente es un error visual, no afecta al funcionamiento
            
            axis.setDepthTest(False)
            
            https://discourse.panda3d.org/t/model-always-on-screen/8135/5
            """

            gizmo_geom.setScale(scale)
            # axis.setScale(1)
            gizmo_geom.reparentTo(self.corner)
            #
            gizmo_geom.setPos(0, 0, 0)
            gizmo_geom.setCompass()
            separation = 1
            # gizmo_geom.setShaderInput("showborders", LVecBase4(0))
            # gizmo_geom.setShaderInput("colorborders", LVecBase4(0, 0, 0, 0))
            # gizmo_geom.setShaderInput("separation", LVecBase4(separation, 0, separation, 0))

    def add_cube(self):
        """
        Función de prueba, coloca cubos en la ubicación del cursor
        """
        if self.panda3d.mouse_on_workspace:
            print("add_cube")
            pos = self.panda3d.work_plane_mouse
            cube = self.panda3d.loader.loadModel("models/box")
            # Reparent the model to render.
            cube.reparentTo(self.panda3d.render)
            # Apply scale and position transforms on the model.
            cube.setScale(0.25, 0.25, 0.25)
            cube.setPos(pos[0], pos[1], pos[2])



    def entity_select(self):
        if self.panda3d.mouseWatcherNode.hasMouse():
            """traverser = CollisionTraverser("")
            #traverser.show_collisions(render)
            picker_ray = CollisionRay()
            handler = CollisionHandlerQueue()

            picker_node = CollisionNode('mouseRay')
            picker_np = self.panda3d.camera.attachNewNode(picker_node)
            picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask())
            picker_ray = CollisionRay()
            picker_node.addSolid(picker_ray)
            traverser.addCollider(picker_np, handler)

            picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask())
            mpos = self.panda3d.mouseWatcherNode.getMouse()
            picker_ray.setFromLens(self.panda3d.camNode, mpos.getX(), mpos.getY())
            traverser.traverse(self.panda3d.render)"""


            self.picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask())
            mpos = self.panda3d.mouseWatcherNode.getMouse()
            self.picker_ray.setFromLens(self.panda3d.camNode, mpos.getX(), mpos.getY())
            self.traverser.traverse(self.panda3d.render)
            handler = self.handler

            # Assume for simplicity's sake that myHandler is a CollisionHandlerQueue.
            btn = self.panda3d.mouseWatcherNode

            if handler.getNumEntries() > 0:
                # This is so we get the closest object.
                handler.sortEntries()

                entity = handler.getEntry(0).getIntoNodePath()
                entity = entity.findNetTag('entity_id')
                if not entity.isEmpty():

                    #print("entity selected: {}".format(entity.getTag("entity_id")))

                    entity_id = entity.getTag("entity_id")
                    entity_type = entity.getTag("entity_type")
                    #print(entity_type)
                    model = app.model_reg

                    category_type = model.get(entity_type, dict())
                    entity = category_type.get(entity_id, None)


                    #print(entity)
                    if btn.isButtonDown("mouse1"):
                        entity.on_click()
                        if entity.is_editable:
                            prop_editor = app.main_ui.prop_editor
                            prop_editor.entity_read(entity)
                    elif entity.is_selectable:
                        status_bar = app.main_ui.status_bar
                        status_bar.entity_read(entity)

                else:
                    print("Hay {} entidades bajo el mouse".format(handler.getNumEntries()))
            else:
                if btn.isButtonDown("mouse1"):
                    entities = app.model_reg.get("View", {})

                    if entities is None or len(entities) is 0:
                        View()

                    entities = app.model_reg.get("View")
                    entity = list(entities.values())[0]
                    prop_editor = app.main_ui.prop_editor

                    prop_editor.entity_read(entity)
                else:
                    status_bar = app.main_ui.status_bar
                    status_bar.entity_read()
Ejemplo n.º 23
0
class Fighter():
    def __init__(self,characterPath , callOnDeath , side , name = None):
        #side indicates if the player is on the left or right side.
        #TODO: add collision tests against ring-out geometry in the arena, 
        

        self.fsm = FighterFsm(self,characterPath)    
        self.inputHandler = InputHandler(self.fsm,side)
        
        self.side = side
        
        self.wins = 0 #counting won rounds, a double-ko/draw counts as win for both.
        self.faceOpp = True  #looking at opponent
        self.callOnDeath = callOnDeath
        
        self.statusBitMask = BitMask32()
        self.defenseBitMask = BitMask32()    #active defense parts get a 1
        #the attack bitmask is generated by the fsm and passed to the attack method directly
    
        if not name:
            name = "player"+str(1+bool(side))
        
        self.healthBar = PlayerHud(side, name )
          
        self.fighterNP = render.attachNewNode(name)
        self.collTrav = CollisionTraverser(name)
        fromObject = self.fighterNP.attachNewNode(CollisionNode('colNode'+name))
        fromObject.node().addSolid(CollisionRay(0, 0, 2,0,0, -1))
        fromObject.node().setFromCollideMask(BitMask32.bit(1))
        fromObject.node().setIntoCollideMask(BitMask32.allOff())
        self.queue = CollisionHandlerQueue()
        self.collTrav.addCollider(fromObject, self.queue)
        
        self.fsm.getNP().reparentTo(self.fighterNP)
        #fromObject.show() #more debug collision visuals
        #self.collTrav.showCollisions(render) #debug visuals for collision     
        self.prepareFighter()
   
   
    def updateState(self,newState = None):
        if newState:
            if "enter" + state in dir(self.fsm):
                self.fsm.forceTransition(newState)
        else:
            self.inputHandler.pollEvents()          
        
    def prepareFighter(self):
        taskMgr.remove("player"+str(self.side))
        self.speed = (0,0)
        self.fsm.forceTransition("Idle")
        self.health= 100
        self.healthBar.setHealth(self.health)
        self.healthBar.setRoundIndicator('V'*self.wins)
        
        if self.side:
            self.fighterNP.setX(5)
        else:
            self.fighterNP.setX(-5)
        self.fighterNP.setY(0)
        taskMgr.add(self._playertask, "player"+str(self.side))
    
    def setStatusBitMask(self,bitmask):
        self.statusBitMask = bitmask
        
    def setDefenseBitMask(self,bitmask):
        self.defenseBitMask = bitmask 
   
    #getters and setters are a bit stupid here. properties from python 3 would be nice
    def fighterWin(self):
        #request a win-anim from the fsm if there are any
        self.wins += 1
        self.healthBar.setRoundIndicator('V'*self.wins)
    
    def getWins(self):
        return self.wins   
    
    def getHealth(self):
        return self.health
        
    def getNP(self):
        return self.fighterNP

    def setOpponent(self,opponent):
        self.opponent = opponent
        self.fighterNP.lookAt(self.opponent.getNP())
   
    def attack(self,attackBitMask,attackrange,damageHit,damageDodge=0,angle=30): #those variables will be supplied by the fsm states later on. 
                                                             #function is pretty redundant... for structure only, and for early days
        attackstatus = self.opponent.getAttacked(attackBitMask,attackrange,damageHit,damageDodge,angle)
        return attackstatus
    
    def _testHit(self,node1,node2,threshold=30, dist = 1):  #node1 which looks for a target , node2 is the target , threshold is the max-attack-angle, dist the dist
          dirVec = node1.getRelativePoint(node2,Vec3(0,0,0))
          dirVec = Vec3(dirVec[0],dirVec[1],dirVec[2])
          
          dirVec.normalize()
          angle = dirVec.angleDeg(Vec3(0,1,0))
          if angle < threshold and dist > node1.getDistance(node2):
            #print "hit at "+str(angle)+" degree!"
            return True
          else:
            #print angle,node1.getDistance(node2)
            return False
        
    def getAttacked(self,attackBitMask,attackrange,damageHit,damageDodge=0,angle = 30):
        """
        returns 0 if not hit, 1 if hit was blocked, 2 if hit, 3 for hit+KO 
        """
        if self.health <=0:
            return 4 #player is ko already
            

        if  not self._testHit(self.opponent.getNP(),self.fighterNP  ,angle,attackrange )  : #instead of 0, a sligtly positive values makes thinks look better.
            #attack misses due to out of range.
            return 0 

        if (self.statusBitMask & attackBitMask).getWord() == 0: # attak misses cause the player avoided it. went low or so.
            return 0
  
        if (self.defenseBitMask & attackBitMask).getWord():
            self.health -= damageDodge
            self.healthBar.setHealth(self.health)
            return 1 #hit,... but blocked so no combos 
            
        else:
            self.health -= damageHit
            self.healthBar.setHealth(self.health)
            if self.health <= 0 : #if KO
                taskMgr.remove("player"+str(self.side))
                self.fsm.forceTransition("Ko")
                #actually make the match.py allow the other player to KO (in case of doubleKO,befor calling round end.
                taskMgr.doMethodLater(0.5,self.callOnDeath,"RoundEnd") 
                return 3
            #TODO: requesting the same state as you are in doesnt work well.sorta need to re-enter the hit state
            if "Crouch" in self.fsm.state:
                self.fsm.forceTransition("CrouchHit")
            elif self.fsm.state:
                self.fsm.forceTransition("Hit")
            return 2 #regular hit
    
    def setSpeed(self,x,y):
        self.speed = (x,y)
    
    def faceOpponent(self,facing):
        self.faceOpp = facing #true if yuo look at the other player (usualy true unless attacking), so you can dodge an attack by evading.
    
    def _playertask(self,task):
        
        oldpos = self.fighterNP.getPos()
        
        dist = self.fighterNP.getY(self.opponent.getNP()) 

        if dist > 3 or self.speed[0]<0: #prevert players from walking throug each other , too troublesome atm
            self.fighterNP.setX(self.fighterNP,self.speed[1]*globalClock.getDt())
            self.fighterNP.setY(self.fighterNP,self.speed[0]*globalClock.getDt())
        else :
            self.speed = ( min(2,self.speed[0] ), self.speed[1])
            #also push back other player
            self.opponent.getNP().setY(self.opponent.getNP(),-self.speed[0]*globalClock.getDt() )
            
        self.collTrav.traverse(render)
        self.queue.sortEntries()
        for i in range(self.queue.getNumEntries()):
            entry = self.queue.getEntry(i)
            if "ground" in entry.getIntoNodePath().getName() :
                break
            if "out" in entry.getIntoNodePath().getName() :
                pass #ring out
                self.fighterNP.setPos(oldpos) #for now reset him as we have no ring-out anim yet #TODO: add ring out anim!
                break
            
        if self.queue.getNumEntries() == 0:
            #if there is no ground and no ring out, propably a wall or no thin like that. just reset the pos     
            self.fighterNP.setPos(oldpos)
            print "resetting fighter"
            
        if self.faceOpp:
            self.fighterNP.lookAt(self.opponent.getNP())      
                
        return task.cont
Ejemplo n.º 24
0
class HitscanWeapon(Weapon):
    def __init__(self, mask, damage, knockback, range=None):
        Weapon.__init__(self, mask, range, damage, knockback)

        if range is None:
            self.ray = CollisionRay(0, 0, 0, 0, 1, 0)
        else:
            self.ray = CollisionSegment(0, 0, 0, 1, 0, 0)

        rayNode = CollisionNode("playerRay")
        rayNode.addSolid(self.ray)

        rayNode.setFromCollideMask(mask)
        rayNode.setIntoCollideMask(0)

        self.rayNodePath = render.attachNewNode(rayNode)
        self.rayQueue = CollisionHandlerQueue()

        self.traverser = CollisionTraverser()
        self.traverser.addCollider(self.rayNodePath, self.rayQueue)

    def performRayCast(self, origin, direction):
        if isinstance(self.ray, CollisionRay):
            self.ray.setOrigin(origin)
            self.ray.setDirection(direction)
        else:
            self.ray.setPointA(origin)
            self.ray.setPointB(origin + direction * self.range)

        self.traverser.traverse(render)

        if self.rayQueue.getNumEntries() > 0:
            self.rayQueue.sortEntries()
            rayHit = self.rayQueue.getEntry(0)

            return True, rayHit
        else:
            return False, None

    def fire(self, owner, dt):
        Weapon.fire(self, owner, dt)
        rayDir = owner.weaponNP.getQuat(render).getForward()
        hit, hitEntry = self.performRayCast(owner.weaponNP.getPos(render),
                                            rayDir)

        if hit:
            hitNP = hitEntry.getIntoNodePath()
            if hitNP.hasPythonTag(TAG_OWNER):
                subject = hitNP.getPythonTag(TAG_OWNER)
                subject.alterHealth(-self.damage, rayDir * self.knockback,
                                    self.flinchValue)

    def cleanup(self):
        self.traverser.removeCollider(self.rayNodePath)
        self.traverser = None

        if self.rayNodePath is not None:
            self.rayNodePath.removeNode()
            self.rayNodePath = None

        Weapon.cleanup(self)
class FollowCamera(TerrainCamera):
    
    def __init__(self, fulcrum, terrain):
        TerrainCamera.__init__(self)

        self.terrain = terrain
        self.fulcrum = fulcrum
        # in behind Ralph regardless of ralph's movement.
        self.camNode.reparentTo(fulcrum)
        # How far should the camera be from Ralph
        self.cameraDistance = 30
        # Initialize the pitch of the camera
        self.cameraPitch = 10
        self.focus = self.fulcrum.attachNewNode("focus")
        
        self.maxDistance = 500.0
        self.minDistance = 2
        self.maxPitch = 80
        self.minPitch = -70
        
        # 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.
        # 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.cameraRay = CollisionSegment(self.fulcrum.getPos(), (0, 5, 5))
        self.cameraCol = CollisionNode('cameraRay')
        self.cameraCol.addSolid(self.cameraRay)
        self.cameraCol.setFromCollideMask(BitMask32.bit(0))
        self.cameraCol.setIntoCollideMask(BitMask32.allOff())
        self.cameraColNp = self.fulcrum.attachNewNode(self.cameraCol)
        self.cameraColHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.cameraColNp, self.cameraColHandler) 
        
    def zoom(self, zoomIn):
        if (zoomIn):
            self.cameraDistance += 0.1 * self.cameraDistance;
        else:
            self.cameraDistance -= 0.1 * self.cameraDistance;
        if self.cameraDistance < self.minDistance:
            self.cameraDistance = self.minDistance
        if self.cameraDistance > self.maxDistance:
            self.cameraDistance = self.maxDistance
        
    def update(self, x, y):
        
        # alter ralph's yaw by an amount proportionate to deltaX
        self.fulcrum.setH(self.fulcrum.getH() - 0.3 * x)
        # find the new camera pitch and clamp it to a reasonable range
        self.cameraPitch = self.cameraPitch + 0.1 * y
        if (self.cameraPitch < self.minPitch): 
            self.cameraPitch = self.minPitch
        if (self.cameraPitch > self.maxPitch): 
            self.cameraPitch = self.maxPitch
        self.camNode.setHpr(0, self.cameraPitch, 0)
        # set the camera at around ralph's middle
        # We should pivot around here instead of the view target which is noticebly higher
        self.camNode.setPos(0, 0, 0)
        # back the camera out to its proper distance
        self.camNode.setY(self.camNode, self.cameraDistance)
        self.fixHeight()
        correctedDistance = self.camNode.getPos().length()

        # point the camera at the view target

        forwardOffset = -math.sin(math.radians(self.cameraPitch))
        verticalOffset = 1- math.sin(math.radians(self.cameraPitch))
        self.focus.setPos(0, forwardOffset, verticalOffset + correctedDistance / 8.0)
        #keep camera from flipping over
        if self.focus.getY() > self.camNode.getY()*0.9:
            self.focus.setY(self.camNode.getY()*0.9)
        self.camNode.lookAt(self.focus)
        # reposition the end of the  camera's obstruction ray trace
        self.cameraRay.setPointB(self.camNode.getPos())
        
        # We will detect anything obstructing the camera via a ray trace
        # from the view target around the avatar's head, to the desired camera
        # podition. If the ray intersects anything, we move the camera to the
        # the first intersection point, This brings the camera in between its
        # ideal position, and any present obstructions.

#        entries = []
#        for i in range(self.cameraColHandler.getNumEntries()):
#            entry = self.cameraColHandler.getEntry(i)
#            entries.append(entry)
#        entries.sort(lambda x,y: cmp(-y.getSurfacePoint(self.ralph).getY(),
#                                     -x.getSurfacePoint(self.ralph).getY()))
#        if (len(entries)>0):
#            collisionPoint =  entries[0].getSurfacePoint(self.ralph)
#            collisionVec = ( viewTarget - collisionPoint)
#            if ( collisionVec.lengthSquared() < self.cameraDistance * self.cameraDistance ):
#                self.camNode.setPos(collisionPoint)
#                if (entries[0].getIntoNode().getName() == "terrain"):
#                    self.camNode.setZ(base.camera, 0.2)
#                self.camNode.setY(base.camera, 0.3)
#

    def fixHeight(self):
        pos = self.camNode.getPos(render)
        minZ = self.terrain.getElevation(pos.x, pos.y) + 1.2
        #logging.info( minZ)
        if pos.z < minZ:
            pos.z = minZ
        self.camNode.setPos(render, pos)
Ejemplo n.º 26
0
class Labryn(ShowBase):
    def setCamera(self, spin):
        # set camera spin state
        self.spin = spin

    def displayInformation(self):
        self.title = addTitle("Single Player")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[wasd]: Move")
        self.inst3 = addInstructions(0.85, "[q/e]: spin camera")
        self.inst4 = addInstructions(0.80, "[z/c]: zoom in/out")
        self.inst5 = addInstructions(0.75, "[shift]: hold and pan")
        self.inst6 = addInstructions(0.70, "[1/2/3]: use moves")
        self.inst7 = addInstructions(0.65, "[h]: hide instructions")
        self.insts = [self.title, self.inst1, self.inst2, self.inst3,
                      self.inst4, self.inst5, self.inst6, self.inst7]

    def hideInstructions(self):
        if self.instStatus == "show":
            self.instStatus = "hide"
            groupHide(self.insts)
        else: # instructions are hidden
            self.instStatus = "show"
            groupShow(self.insts)        
        
    def loadNextMusic(self, task):
        # random load background music
        if (self.music.status()!=self.music.PLAYING):
            # not playing
            self.musicCounter += 1
            index = self.musicCounter % len(_BGMUSIC)
            self.music = load_bgmusic(_BGMUSIC[index])
            self.music.play()
        return task.cont
        
    def spinCamera(self, task):
        # deal with spinning the camera
        # _FOCUS: focus point, changed by panning the camera
        # CAM_R: radius, changed by zooming
        # cameraSpinCount: amount of spinning, changed by spinning
        if self.spin == 1: # spin counter-clockwise
            self.cameraSpinCount += 1
            angleDegrees = self.cameraSpinCount
            angleRadians =  angleDegrees * (pi/ 180)
            self.CAM_RAD = angleRadians
            camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R) 
            camera.setHpr(angleDegrees,-65,0)
        elif self.spin == 2: # spin clockwise
            self.cameraSpinCount  -= 1
            angleDegrees = self.cameraSpinCount
            angleRadians =  angleDegrees * (pi/ 180)
            self.CAM_RAD = angleRadians
            camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
            camera.setHpr(angleDegrees,-65,0)
        elif self.spin == 3: # ZOOM IN not spin
            self.cameraZoomCount += 1
            deltaR = self.cameraZoomCount * 0.1
            new_R = 12-deltaR
            self.CAM_R = new_R
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*new_R)
        elif self.spin == 4: # ZOOM OUT
            self.cameraZoomCount -= 1
            deltaR = self.cameraZoomCount * 0.1
            new_R = 12-deltaR
            self.CAM_R = new_R
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
        return Task.cont

    def takeRecord(self):
        def myCMP(aString, bString):
            a = float(aString.split(',')[0])
            b = float(bString.split(',')[0])
            return int(10*(a - b))
        
        msg = "%.2f,%s\n" %(self.clock/100.0, time.ctime())
        with open('record.txt') as f:
            data = f.readlines()
        # if has no previous data
        if len(data) == 0:
            data.append(msg)
            with open('record.txt','w') as f:
                f.writelines(data)
        else:
            data.append(msg)
            processedData = sorted(data, myCMP)
            with open('record.txt', 'w') as f:
                f.writelines(processedData)

    def printResults(self):
        addEndMessage(self.clock)
        with open('record.txt') as f:
            data = f.readlines()
        for i in xrange(0, len(data)):
            if i < 5: # only print the top 5
                string = data[i]
                printRank(i, string)
        
    def checkForWin(self, task):
        if (checkWin(self.pikachu.getX(), self.pikachu.getY(),
                    self.ballRoot.getX(), self.ballRoot.getY()) and
            self.gameOver == False):
            self.takeRecord()
            self.printResults()
            self.gameOver = True
            # if top 10, if top 1,
            print "WIN"
            # print previous best 10 results
        return Task.cont
    
    def pikachuBark(self, task):
        if self.distance < 3:
            if random.randint(1,200) == 1:
            # randomly bark dangerous sound
                if self.dangerous.status() != self.dangerous.PLAYING:
                    self.dangerous.play()
        elif self.distance > 10:
            if random.randint(1,430) == 1:
                if self.safe.status() != self.safe.PLAYING:
                    self.safe.play()
        return Task.cont
            
    def checkMouse(self, task):
        # get mouse position 
        if base.mouseWatcherNode.hasMouse():
            self.mouseX=base.mouseWatcherNode.getMouseX()
            self.mouseY=base.mouseWatcherNode.getMouseY()
        return Task.cont

    def dropRock(self):
        # when the user clicks, rock is dropped
        if self.pokeMoveChoice == 1: # selected Geodude
            result = MAZE.canDropRock(self.rockX, self.rockY)
            if result != False: # can place rock here
                MAZE.dropRock(result[0],result[1])
                self.rock.setPos(self.rockX, self.rockY, 1)
                self.rockOnMaze = True
                self.pokeMoveChoice = None
                self.myPokeName.hide()
                self.myPokeName = None
                self.updateTwoD()
                self.playerCandyCount -= 1

    def restart(self):
        sys.exit()
                
    def useFlame(self):
        # use flame to Pikachu -> cannot move
        self.onFire = True # on fire
        self.playerCandyCount -= 1
        self.pokeStatus = 1
        self.flame = ParticleEffect()
        self.flame.loadConfig("fireish.ptf")
        self.flame.setPos(self.pikachu.getPos())
        self.flame.start(parent=render, renderParent=render)
        self.updateTwoD()

    def useStringShot(self):
        # use string shot -> speed goes down
        self.pokeStatus = 2
        self.updateTwoD()

    def useThunder(self):
        self.onThunder = True
        self.pokeCandyCount -= 1
        self.thunder = ParticleEffect()
        self.thunder.loadConfig("thunder.ptf")
        self.thunder.start(parent=render, renderParent=render)
        self.use.play()
                
    def placeRock(self, task):
        # rock moves with mouse cursor
        if self.pokeMoveChoice == 1: # selected Geodude
            dX,dY = ((self.mouseX-self.rockRefX),
                     (self.mouseY-self.rockRefY))
            self.rockX, self.rockY = MAZE.translateRockPosition(self.rockRefX,
                                                      self.rockRefY,
                                                      dX, dY)
            self.rock.show()
            self.rock.setPos(self.rockX, self.rockY, 1)
        self.updateTwoD()
        return Task.cont
    
    def placeRareCandy(self, task):
        # place rare candy with interval
        # needs to be improved
        if int(task.time) % 4 == 9 and self.candyOnBoard:
            self.candy.hide()
            self.candyOnBoard = False
            MAZE.clearCandy()
        if int(task.time) % 10 ==  0 and (self.candyOnBoard == False):
            # every 10 seconds
            self.candy.setPos(MAZE.generateCandyPos())
            self.candy.show()
            self.candyOnBoard = True
        return Task.cont

    def updateTwoD(self):
        # update player candy count
        self.playerCandyStatus.destroy()
        self.playerCandyStatus = candyStatus(0, self.playerCandyCount)
        self.pokeCandyStatus.destroy()
        self.pokeCandyStatus = candyStatus(1, self.pokeCandyCount)
        # update my pokes color     
        if self.playerCandyCount == 0 :
            groupHide(self.myPokesBright)
            groupShow(self.myPokesDark)
            # update name
            if self.myPokeName != None:
                self.myPokeName.destroy()

    def clearRock(self):
        # clear rock 
        self.rock.hide()
        self.rockOnMaze = False
        MAZE.clearRock() # clear it in 2D

    def clearFlame(self):
        # clear flame
        self.onFire = False
        self.flame.cleanup()
        self.pokeStatus = 0
        self.pokeMoveChoice = None
        try:
            self.myPokeName.destroy()
        except:
            pass
        self.myPokeName = None

    def clearString(self):
        # clear string shot
        self.pokeStatus = 0
        self.pokeMoveChoice = None
        try:
            self.myPokeName.destroy()
        except:
            pass
        self.myPokeName = None

    def clearThunder(self):
        self.onThunder = False
        try:
            self.thunder.cleanup()
        except:
            pass
        
    def timer(self, task): # deals with moves' lasting effects
        ##############################################################
        self.clock += 1
        if self.rockOnMaze: # rock on maze
            self.rockCounter += 1
        elif self.rockCounter != 1: # rock not on maze, counter not cleared
            self.rockCounter = 0

        if self.onFire:
            self.fireCounter += 1
        elif self.fireCounter != 1:
            self.fireCounter = 0

        if self.pokeStatus == 2: # string shot
            self.stringCounter += 1
        elif self.stringCounter != 1:
            self.stringCounter = 0

        if self.onThunder: # thunderbolt
            self.thunderCounter += 1
        elif self.thunderCounter != 1:
            self.thunderCounter = 0

        if self.gameOver == True: # game is over
            self.gameOverCounter += 1

        ##################################################################
        if self.rockCounter >= 100:
            self.clearRock()

        if self.fireCounter >= 80:
            self.clearFlame()

        if self.thunderCounter >= 150:
            self.clearThunder()
            
        if self.stringCounter >= 120:
            self.clearString()

        if self.gameOverCounter >= 800: # quit the game
            sys.exit()
            
        return Task.cont
    
    def usePokeMove(self, number):
        # use pokemon move
        if self.playerCandyCount > 0: # have more than one candy
            if number == 1 and self.rockOnMaze == False:
                if self.pokeMoveChoice == None: # no choice
                    # set to center position
                    centerx =  base.win.getProperties().getXSize()/2
                    centery =  base.win.getProperties().getYSize()/2
                    base.win.movePointer(0,centerx,centery)
                    self.pokeMoveChoice = 1 # placeRock called here
                    self.rockRefX, self.rockRefY = 0,0
                    self.rock.show()
                    self.rock.setPos(0,0,1)
                elif self.pokeMoveChoice != 1:
                    pass

                else: # self.pokeMoveChoice is already 1, cancel the choice
                    self.pokeMoveChoice = None
                    self.clearRock() # clear rock
            elif number == 2:
                if self.pokeMoveChoice == None:
                    self.pokeMoveChoice = 2
                    self.useFlame()
                elif self.pokeMoveChoice != 2:
                    pass
                else:
                    self.pokeMoveChoice = None

            elif number == 3:
                if self.pokeMoveChoice == None:
                    self.pokeMoveChoice = 3
                    self.useStringShot()
                elif self.pokeMoveChoice != 3:
                    pass
                else: # already 3
                    self.pokeMoveChoice = None

            if self.pokeMoveChoice == None: # no choice
                if self.myPokeName != None: # there is a name on board
                    self.myPokeName.destroy() # kill it
                else: # no name
                    pass
            else: # there is a choice
                if self.myPokeName != None:
                    self.myPokeName.destroy()
                self.myPokeName = writePokeName(self.pokeMoveChoice)
  
    def loadRareCandy(self):
        # load rare candy (a box)
        # needs to be improved
        self.candy = Model_Load.loadRareCandy()
        self.candy.reparentTo(render)
        self.candy.setScale(0.1)
        self.candy.hide()
        
    def eatRareCandy(self, task):
        # check who eats candy
        if self.candyOnBoard: # candy on board
            if checkEat(self.ballRoot.getX(), self.ballRoot.getY(),
                        self.candy.getX(), self.candy.getY()): # ball eats
                self.candy.hide() # eaten
                self.candyOnBoard = False
                if self.playerCandyCount < 3:
                    self.playerCandyCount += 1
                groupShow(self.myPokesBright)
                MAZE.clearCandy()
            elif checkEatPika(self.pikachu.getX(), self.pikachu.getY(),
                          self.candy.getX(), self.candy.getY()):
                self.candy.hide()
                self.candyOnBoard = False
                if self.pokeCandyCount < 3:
                    self.pokeCandyCount += 1
                MAZE.clearCandy()                
        return Task.cont

    def setFocus(self, changing):
        # set focus of the camera while panning
        self.changingFocus = changing
        if changing == True: # Just Pressed
            self.referenceX, self.referenceY = self.mouseX, self.mouseY
        else: # cursor moves up
            self.referenceX, self.referenceY = None, None

    def resetView(self):
        # reset the view to default
        self.CAM_R, self.CAM_RAD = 12, 0
        self.cameraSpinCount, self.cameraZoomCount = 0, 0
        # _FOCUS = [0,0,0] does not work WHY???
        _FOCUS[0], _FOCUS[1], _FOCUS[2] = 0,0,0
        self.changingFocus = False
        self.referenceX, self.referenceY = None, None
        camera.setPos(_FOCUS[0], _FOCUS[1]-self.CAM_R, 25)
        camera.setHpr(0, -65, 0)
        
    def changeFocus(self, task):
        # change focus with displacement of mouse cursor
        if (self.changingFocus == True and self.mouseX != None and
            self.mouseY != None ):
            dX, dY = ((self.mouseX - self.referenceX)*0.1,
                      (self.mouseY - self.referenceY)*0.1)
            _FOCUS[0] += dX
            _FOCUS[1] += dY
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
        return Task.cont

    def thunderbolt(self, task):
        if self.onThunder == True:
            self.thunder.setPos(self.ballRoot.getPos())
        return Task.cont

    def displayClock(self, task):
        msg = "Time: %.2f" %(self.clock/100.0)
        if self.clockMSG == None:
            self.clockMSG = OnscreenText(text=msg, style=1, fg=(1,1,1,1),
                                         pos=(1.3, .95), align=TextNode.ALeft,
                                         scale = .05)
        else:
            self.clockMSG.destroy()
            self.clockMSG = OnscreenText(text=msg, style=1, fg=(1,1,1,1),
                                         pos=(1.3, .95), align=TextNode.ALeft,
                                         scale = .05)
        return task.cont
    
    def initialize(self):
        taskMgr.stop()
        self.musicCounter, self.clock = 0, 0
        self.gameOverCounter = 0
        self.clockMSG = None
        self.music = load_bgmusic(_BGMUSIC[0])
        self.background = loadBackground()
        base.cam2dp.node().getDisplayRegion(0).setSort(-20)
        self.candyOnBoard = False
        self.playerCandyCount, self.pokeCandyCount = 0, 0
        self.gameOver = False
        self.displayInformation()
        self.instStatus = "show"
        ######################Rare Candy###############################
        pokes=['caterpie', 'charmander', 'geodude']
        self.myPokesDark = loadMyPokemon_Dark(pokes) # my pokemons
        self.myPokesBright = loadMyPokemon_Bright()
        groupHide(self.myPokesBright)
        self.loadRareCandy() # load rare candy
        ######################Camera Initialization####################
        self.CAM_R, self.CAM_RAD = 12, 0
        camera.setPos(_FOCUS[0],_FOCUS[1]-12,_FOCUS[2]+25)
        camera.setHpr(0, -65, 0)
        self.cameraSpinCount, self.cameraZoomCount = 0, 0
        self.changingFocus = False
        self.spin = 0
        #######################ICONS###################################
        self.myIcon = loadMyIcon()
        self.pokeIcon = loadPokeIcon()
        self.playerCandyStatus = candyStatus(0, self.playerCandyCount)
        self.pokeCandyStatus = candyStatus(1, self.pokeCandyCount)
        self.rareCandyImage = loadRareCandyImage()
        self.pokeRareCandyImage = loadRareCandyImage(pos=(-.3,0,-.75))
        #######################FLAMES##################################
        base.enableParticles()
        self.fireCounter = 0
        self.onFire = False
        #######################STRINGSHOT#############################
        self.stringCounter = 0
        #######################THUNDER################################
        self.thunderCounter = 0
        #######################SOUND##################################
        self.dangerous = load_sound("pikachu_d.wav")
        self.safe = load_sound("pikachu_s1.wav")
        self.use = load_sound("pikachu_u.wav")
        #######################"GLOBALS"##############################
        self.speedCounter = 0
        self.onThunder = False
        self.direction = 's'
        self.myDirection = ['zx', 'zy']
        self.rockCounter  = 0
        self.rockX, self.rockY = None, None
        self.rockOnMaze = False
        self.pokeMoveChoice = None
        self.myPokeName = None
        self.arrowKeyPressed = False
        self.pokemonDirection = 'd'
        self.mouseX, self.mouseY = None, None
        # direction the ball is going
        self.jerkDirection = None
        base.disableMouse()
        self.jerk = Vec3(0,0,0)
        self.MAZE = Model_Load.loadLabyrinth()
        Control.keyControl(self)
        self.loadPokemonLevel1()
        self.light()
        self.loadBall()
        self.pokeStatus = 0 # 0 is normal, 1 is burned, 2 is slow-speed
        ########################################ROCK###################
        self.rock = Model_Load.loadRock()
        self.rock.reparentTo(render)
        self.rock.hide() # Do not show, but load beforehand for performance
        
    def loadPokemonLevel1(self):
        self.pikachu = load_model("pikachu.egg")
        self.pikachu.reparentTo(render)
        self.pikachu.setScale(0.3)
        endPos = self.MAZE.find("**/end").getPos()
        self.pikachu.setPos(endPos)
        
    def light(self):
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def loadBall(self):
        self.ballRoot = render.attachNewNode("ballRoot")
        self.ball = load_model("ball")
        self.ball.reparentTo(self.ballRoot)
        self.ball_tex = load_tex("pokeball.png")
        self.ball.setTexture(self.ball_tex,1)
        self.ball.setScale(0.8)
        # Find the collision sphere for the ball in egg.
        self.ballSphere = self.ball.find("**/ball")
        self.ballSphere.node().setFromCollideMask(BitMask32.bit(0))
        self.ballSphere.node().setIntoCollideMask(BitMask32.allOff())
        #self.ballSphere.show()
        # Now we create a ray to cast down at the ball.
        self.ballGroundRay = CollisionRay()
        self.ballGroundRay.setOrigin(0,0,10)
        self.ballGroundRay.setDirection(0,0,-1)

        # Collision solids go in CollisionNode
        self.ballGroundCol =  CollisionNode('groundRay')
        self.ballGroundCol.addSolid(self.ballGroundRay)
        self.ballGroundCol.setFromCollideMask(BitMask32.bit(1))
        self.ballGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ballGroundColNp = self.ballRoot.attachNewNode(self.ballGroundCol)
        
        # light
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.55, .55, .55, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0,0,-1))
        directionalLight.setColor(Vec4(0.375,0.375,0.375,1))
        directionalLight.setSpecularColor(Vec4(1,1,1,1))
        self.ballRoot.setLight(render.attachNewNode(ambientLight))
        self.ballRoot.setLight(render.attachNewNode(directionalLight))
        # material to the ball
        m = Material()
        m.setSpecular(Vec4(1,1,1,1))
        m.setShininess(96)
        self.ball.setMaterial(m,1)
        
    def __init__(self):

        self.initialize()
        self.WALLS = self.MAZE.find("**/Wall.004")
        self.WALLS.node().setIntoCollideMask(BitMask32.bit(0))
        # collision with the ground. different bit mask
        #self.mazeGround = self.maze.find("**/ground_collide")
        #self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1))
        self.MAZEGROUND = self.MAZE.find("**/Cube.004")
        self.MAZEGROUND.node().setIntoCollideMask(BitMask32.bit(1))

        # add collision to the rock
        cs = CollisionSphere(0, 0, 0, 0.5)
        self.cnodePath = self.rock.attachNewNode(CollisionNode('cnode'))
        self.cnodePath.node().addSolid(cs)
        self.cnodePath.node().setIntoCollideMask(BitMask32.bit(0))
        
        # CollisionTraversers calculate collisions
        self.cTrav = CollisionTraverser()
        #self.cTrav.showCollisions(render)
        #self.cTrav.showCollisions(render)
        # A list collision handler queue
        self.cHandler = CollisionHandlerQueue()
        # add collision nodes to the traverse.
        # maximum nodes per traverser: 32
        self.cTrav.addCollider(self.ballSphere,self.cHandler)
        self.cTrav.addCollider(self.ballGroundColNp,self.cHandler)
        self.cTrav.addCollider(self.cnodePath, self.cHandler)
        # collision traversers have a built-in tool to visualize collisons
        #self.cTrav.showCollisions(render)
        self.start()

    def pokemonTurn(self, pokemon, direction):
        if direction  == 'l' and self.pokemonDirection != 'l':
            self.pokemonDirection = 'l'
            pokemon.setH(-90)
        if direction  == 'r' and self.pokemonDirection != 'r':
            self.pokemonDirection = 'r'
            pokemon.setH(90)
        if direction  == 'd' and self.pokemonDirection != 'd':
            self.pokemonDirection = 'd'
            pokemon.setH(0)
        if direction  == 'u' and self.pokemonDirection != 'u':
            self.pokemonDirection = 'u'
            pokemon.setH(180)
                        
    def pokemonMove(self, pokemon, direction):
        self.pokemonTurn(pokemon, direction)
        if self.pokeStatus == 0: speed = _SPEED
        elif self.pokeStatus == 1: speed = 0
        else: # self.pokeStatus == 2
            speed = _SPEED/2.0
        if direction == 'l':
            newX = pokemon.getX() - speed
            pokemon.setX(newX)
        elif direction == 'r':
            newX = pokemon.getX() + speed
            pokemon.setX(newX)
        elif direction == 'u':
            newY = pokemon.getY() + speed
            pokemon.setY(newY)
        elif direction == 'd':
            newY = pokemon.getY() - speed
            pokemon.setY(newY)
        elif direction == "s": # stop
            pass
        
    def whereToGo(self, task):
        # this returns the direction pokemon should go
        # tell MAZE pokemon and ball's board position
        self.pokemonMove(self.pikachu, self.direction)
        MAZE.setPokeCoord(self.pikachu.getX(), self.pikachu.getY(),
                          self.pokemonDirection)
        MAZE.setBallCoord(self.ballRoot.getX(), self.ballRoot.getY())
        MAZE.sendInformation(self.myDirection, self.rockOnMaze,
                             self.onThunder, self.playerCandyCount,
                             self.pokeCandyCount, self.distance)
        # find out which direction to go
        self.direction = MAZE.getDecision()
        self.pokemonMove(self.pikachu,self.direction)
        return Task.cont

    def whatToDo(self, task):
        # determines when to use thunder
        if self.pokeCandyCount > 0: # Pikachu has candies
            decision = MAZE.useThunderDecision()
            if decision == True:
                self.useThunder()
        return Task.cont
    
    def getInformation(self, task):
        # get information on the board
        self.speedCounter += 1 # sample every other call to avoid 
        if self.speedCounter % 2 == 0:
            dX = self.ballRoot.getX() - self.oldPos[0]
            dY = self.ballRoot.getY() - self.oldPos[1]
            if dX < 0 :
                # print "going left"
                self.myDirection[0] = 'l'
            elif abs(dX) < _EPSILON:
                # print "not moving horiz"
                self.myDirection[0] = 'zx'
            else:
                # print "going right"
                self.myDirection[0] = 'r'
            if dY < 0 :
                # print "going down"
                self.myDirection[1] = 'd'
            elif abs(dY) < _EPSILON:
                # print "not moving verti"
                self.myDirection[1] = 'zy'
            else:
                # print "going up"
                self.myDirection[1] = 'u'
            self.oldPos = self.ballRoot.getPos()
        # calculate distance
        self.distance = MAZE.getDistance()
        return Task.cont
    
    def start(self):
        # maze model has a locator in it
        # self.ballRoot.show()
        self.startPos = self.MAZE.find("**/start").getPos()
        self.oldPos = self.MAZE.find("**/start").getPos()
        self.ballRoot.setPos(self.startPos) # set the ball in the pos
        self.ballV = Vec3(0,0,0) # initial velocity
        self.accelV = Vec3(0,0,0) # initial acceleration

        # for a traverser to work, need to call traverser.traverse()
        # base has a task that does this once a frame
        base.cTrav = self.cTrav

        # create the movement task, make sure its not already running
        taskMgr.remove("rollTask")
        taskMgr.add(self.placeRock, "placeRock")
        taskMgr.add(self.displayClock, "displayClock")
        taskMgr.add(self.timer, "timer")
        taskMgr.add(self.loadNextMusic, "loadNextMusic")
        taskMgr.add(self.getInformation, "getInformation")
        taskMgr.add(self.eatRareCandy, "eatRareCandy")
        taskMgr.add(self.placeRareCandy, "placeRareCandy")
        taskMgr.add(self.checkMouse, "checkMouse")
        taskMgr.add(self.spinCamera, "spinCamera")
        taskMgr.add(self.changeFocus, "changeFocus")
        taskMgr.add(self.whereToGo, "whereToGo")
        taskMgr.add(self.whatToDo, "whatToDo")
        taskMgr.add(self.moveBall, "moveBall")
        taskMgr.add(self.thunderbolt, "thunderbolt")
        taskMgr.add(self.checkForWin, "checkForWin")
        taskMgr.add(self.pikachuBark, "pikachuBark")
        self.mainLoop = taskMgr.add(self.rollTask, "rollTask")
        self.mainLoop.last = 0

    def moveBallWrapper(self, direction):
        # wrapper for moving the ball
        # needs to be improved
        if direction == False:
            self.arrowKeyPressed = False
        else:
            self.arrowKeyPressed = True
            self.jerkDirection = direction
    
    def moveBall(self, task):
        # move the ball
        # a key press changes the jerk
        direction = self.jerkDirection
        if self.arrowKeyPressed == True and self.onThunder == False:
            if direction == "u":
                self.jerk = Vec3(0,_JERK,0)
            elif direction == "d":
                self.jerk = Vec3(0,-_JERK,0)
            elif direction == "l":
                self.jerk = Vec3(-_JERK,0,0)
            elif direction == "r":
                self.jerk = Vec3(_JERK,0,0)
        elif self.onThunder == True:
            self.jerk = self.jerk
        return Task.cont        

    # collision between ray and ground
    # info about the interaction is passed in colEntry
    
    def groundCollideHandler(self,colEntry):
        # set the ball to the appropriate Z for it to be on the ground
        newZ = colEntry.getSurfacePoint(render).getZ()
        self.ballRoot.setZ(newZ+.4)

        # up vector X normal vector
        norm = colEntry.getSurfaceNormal(render)
        accelSide = norm.cross(UP)
        self.accelV = norm.cross(accelSide)

    # collision between the ball and a wall
    def wallCollideHandler(self,colEntry):
        # some vectors needed to do the calculation
        norm = colEntry.getSurfaceNormal(render) * -1
        norm.normalize()
        curSpeed = self.ballV.length()
        inVec = self.ballV/curSpeed
        velAngle = norm.dot(inVec) # angle of incidance
        hitDir = colEntry.getSurfacePoint(render) - self.ballRoot.getPos()
        hitDir.normalize()
        hitAngle = norm.dot(hitDir)
    # deal with collision cases
        if velAngle > 0 and hitAngle >.995:
            # standard reflection equation
            reflectVec = (norm * norm.dot(inVec*-1)*2) + inVec
            # makes velocity half of hitting dead-on
            self.ballV = reflectVec * (curSpeed * (((1-velAngle)*.5)+.5))
            # a collision means the ball is already a little bit buried in
            # move it so exactly touching the wall
            disp = (colEntry.getSurfacePoint(render) -
                    colEntry.getInteriorPoint(render))
            newPos = self.ballRoot.getPos() + disp
            self.ballRoot.setPos(newPos)
            
    def rollTask(self,task):
        # standard technique for finding the amount of time
        # since the last frame
        dt = task.time - task.last
        task.last = task.time
        # If dt is large, then there is a HICCUP
        # ignore the frame
        if dt > .2: return Task.cont
        # dispatch which function to handle the collision based on name
        for i in range(self.cHandler.getNumEntries()):
            entry = self.cHandler.getEntry(i)
            name = entry.getIntoNode().getName()
            if name == "Wall.004":
                self.wallCollideHandler(entry)
            elif name=="Cube.004":
                self.groundCollideHandler(entry)
            else:
                if self.rockOnMaze == True:
                    self.wallCollideHandler(entry)
                    
        self.accelV += self.jerk
        # move the ball, update the velocity based on accel
        self.ballV += self.accelV * dt * ACCELERATION
        # clamp the velocity to the max speed
        if self.ballV.lengthSquared() > MAX_SPEED_SQ:
            self.ballV.normalize()
            self.ballV *= MAX_SPEED
        # update the position
        self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV*dt))

        # uses quaternion to rotate the ball
        prevRot = LRotationf(self.ball.getQuat())
        axis = UP.cross(self.ballV)
        newRot = LRotationf(axis, 45.5 * dt * self.ballV.length())
        self.ball.setQuat(prevRot * newRot)
        return Task.cont # continue the task     
Ejemplo n.º 27
0
class Physics:
    def __init__(self):
        self.rayCTrav = CollisionTraverser("collision traverser for ray tests")
        #self.pusher = PhysicsCollisionHandler()
        self.pusher = CollisionHandlerPusher()
        self.pusher.addInPattern('%fn-in-%in')
        self.pusher.addOutPattern('%fn-out-%in')
        self.pusher.addInPattern('%fn-in')
        self.pusher.addOutPattern('%fn-out')

    def startPhysics(self):
        #self.actorNode = ActorNode("playerPhysicsControler")
        #base.physicsMgr.attachPhysicalNode(self.actorNode)
        #self.actorNode.getPhysicsObject().setMass(self.player_mass)
        #self.mainNode = render.attachNewNode(self.actorNode)
        self.mainNode = render.attachNewNode("CharacterColliders")
        self.reparentTo(self.mainNode)

        charCollisions = self.mainNode.attachNewNode(CollisionNode(self.char_collision_name))
        #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0, self.player_height/4.0))
        #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0*3.05, self.player_height/4.0))
        charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/2.0, self.player_height/4.0))
        charCollisions.node().setIntoCollideMask(BitMask32(0x80))  # 1000 0000
        if self.show_collisions:
            charCollisions.show()
        self.pusher.addCollider(charCollisions, self.mainNode)
        base.cTrav.addCollider(charCollisions, self.pusher)

        charFFootCollisions = self.attachNewNode(CollisionNode("floor_ray"))
        charFFootCollisions.node().addSolid(CollisionRay(0, 0, 0.5, 0, 0, -1))
        #charFFootCollisions.node().addSolid(CollisionSegment((0, 0, 0.2), (0, 0, -1)))
        charFFootCollisions.node().setIntoCollideMask(BitMask32.allOff())
        charFFootCollisions.node().setFromCollideMask(BitMask32(0x7f))  # 0111 1111
        if self.show_collisions:
            charFFootCollisions.show()

        self.floor_handler = CollisionHandlerFloor()
        self.floor_handler.addCollider(charFFootCollisions, self.mainNode)
        #self.floor_handler.setOffset(0)
        self.floor_handler.setMaxVelocity(5)
        base.cTrav.addCollider(charFFootCollisions, self.floor_handler)

        self.accept("{}-in".format(self.char_collision_name), self.checkCharCollisions)

        self.raytest_segment = CollisionSegment(0, 1)
        self.raytest_np = render.attachNewNode(CollisionNode("testRay"))
        self.raytest_np.node().addSolid(self.raytest_segment)
        self.raytest_np.node().setIntoCollideMask(BitMask32.allOff())
        self.raytest_np.node().setFromCollideMask(BitMask32(0x7f))  # 0111 1111
        if self.show_collisions:
            self.raytest_np.show()

        self.raytest_queue = CollisionHandlerQueue()
        self.rayCTrav.addCollider(self.raytest_np, self.raytest_queue)

    def stopPhysics(self):
        self.raytest_segment.removeNode()
        self.pusher.clearColliders()
        self.floor_handler.clearColliders()
        self.rayCTrav.clearColliders()

    def updatePlayerPos(self, speed, heading, dt):
        if heading is not None:
            self.mainNode.setH(camera, heading)
            self.mainNode.setP(0)
            self.mainNode.setR(0)
        self.mainNode.setFluidPos(self.mainNode, speed)
        self.doStep()

    def checkCharCollisions(self, args):
        self.doStep()

    def doStep(self):
        # do the step height check
        tmpNP = self.mainNode.attachNewNode("temporary")
        tmpNP.setPos(self.mainNode, 0, 0, -self.stepheight)
        pointA = self.mainNode.getPos(render)
        pointA.setZ(pointA.getZ() + self.player_height/1.8)
        pointB = tmpNP.getPos(render)
        if pointA == pointB: return
        char_step_collision = self.getFirstCollisionInLine(pointA, pointB)
        tmpNP.removeNode()
        if char_step_collision is not None:
            self.mainNode.setFluidZ(char_step_collision.getZ())
            return True
        return False

    def getFirstCollisionInLine(self, pointA, pointB):
        """A simple raycast check which will return the first collision point as
        seen from point A towards pointB"""
        self.raytest_segment.setPointA(pointA)
        self.raytest_segment.setPointB(pointB)
        self.rayCTrav.traverse(render)
        self.raytest_queue.sortEntries()
        pos = None
        if self.raytest_queue.getNumEntries() > 0:
            pos = self.raytest_queue.getEntry(0).getSurfacePoint(render)
        return pos
Ejemplo n.º 28
0
class MyApp(ShowBase):

    def __init__(self):

        ShowBase.__init__(self)

        ################
        #Terrain
        ################

        #######
        #self.environ = GeoMipTerrain("terrain")
        #self.environ.setHeightfield("../terrain/first.png")
        #self.environ.setColorMap("../terrain/first-c.png")
        #self.environ.generate()
        #self.environ.getRoot().setScale(1, 1, 100)
        #self.environ.getRoot().setPos(0, 0, 0)
        #self.environ.getRoot().reparentTo(render)
        #self.environ.getRoot().setName("terrain")
        #self.environ.getRoot().setCollideMask(BitMask32.bit(0))
        #######


        self.environ = loader.loadModel("models/environment")
        self.environ.setScale(.25, .25, .25)
        self.environ.reparentTo(render)
        self.environ.setCollideMask(BitMask32.bit(0))

        ################
        #Game objects 
        ################

        self.pandaActor = Actor("models/panda",
                                {"walk": "models/panda-walk"})
        self.pandaActor.setScale(.5, .5, .5)
        self.pandaActor.setHpr(180, 0, 0)
        #self.pandaActor.setPos(50, 50, 50)
        self.pandaActor.setPythonTag("moving", False)
        self.pandaActor.setCollideMask(BitMask32.allOff())
        self.avatarYawRot = 0
        self.avatarPitchRot = 0

        #self.teapot = loader.loadModel("models/teapot")
        #self.teapot.setScale(1, 1, 1)
        #self.teapot.setPos(60, 60, 50)
        #self.teapot.reparentTo(render)

        self.last_mouse_y = self.win.getPointer(0).getY()

        ################
        #Physics
        ################


        base.enableParticles()

        self.avatarNP=base.render.attachNewNode(ActorNode("actor"))
        # Sets up the mass. Note that in this scenario, mass is not taken into consideration.
        self.avatarNP.node().getPhysicsObject().setMass(100.)
        self.avatarNP.setPos(0,0,0)
        # Parent our avatar to the ready to go physics node
        self.pandaActor.reparentTo(self.avatarNP)

        gravityFN=ForceNode('world-forces')
        gravityFNP=render.attachNewNode(gravityFN)
        gravityForce=LinearVectorForce(0,0,-.1)
        gravityForce.setMassDependent(False)
        gravityFN.addForce(gravityForce)
        # Attach it to the global physics manager
        base.physicsMgr.addLinearForce(gravityForce)

        base.physicsMgr.attachPhysicalNode(self.avatarNP.node())

        ################
        #Collisions
        ################

        self.cTrav = CollisionTraverser()
        self.cTrav.showCollisions(base.render)

        self.pandaGroundRay = CollisionSphere(0,0,0,1)
        self.pandaGroundRayNode = CollisionNode('pandaGroundRay')
        self.pandaGroundRayNode.addSolid(self.pandaGroundRay)
        self.pandaGroundRayNode.setFromCollideMask(BitMask32.bit(0))
        self.pandaGroundRayNode.setIntoCollideMask(BitMask32.allOff())
        self.pandaGroundRayNodepath = self.avatarNP.attachNewNode(self.pandaGroundRayNode)
        self.pandaGroundRayNodepath.show()
        self.pandaGroundCollisionHandler = PhysicsCollisionHandler()
        self.pandaGroundCollisionHandler.addCollider(self.pandaGroundRayNodepath, self.avatarNP)
        self.cTrav.addCollider(self.pandaGroundRayNodepath, self.pandaGroundCollisionHandler)

        #self.teapotRay = CollisionSphere(0,0,0,5)
        #self.teapotGroundCol = CollisionNode('teapotRay')
        #self.teapotGroundCol.addSolid(self.teapotRay)
        #self.teapotGroundCol.setFromCollideMask(BitMask32.allOff())
        #self.teapotGroundCol.setIntoCollideMask(BitMask32.bit(0))
        #self.teapotGroundColNp = self.teapot.attachNewNode(self.teapotGroundCol)
        #self.teapotGroundHandler = CollisionHandlerQueue()
        #self.cTrav.addCollider(self.teapotGroundColNp, self.teapotGroundHandler)

        ################
        #Camera
        ################

        self.disableMouse()

        self.cam_away = 20
        self.cam_elevation = 0
        self.rot_rate = .5

        self.cam_dist = (self.cam_away**2 + self.cam_elevation**2) ** .5

        self.cam.setHpr(0, 0, 0)

        ################
        #Events
        ################

        self.taskMgr.add(self.gameLoop, "gameLoop", priority = 35)

        self.keys = {"w" : 0, "s" : 0, "a" : 0, "d" : 0}

        self.accept("w", self.setKey, ["w", 1])
        self.accept("w-up", self.setKey, ["w", 0])
        self.accept("s", self.setKey, ["s", 1])
        self.accept("s-up", self.setKey, ["s", 0])
        self.accept("a", self.setKey, ["a", 1])
        self.accept("a-up", self.setKey, ["a", 0])
        self.accept("d", self.setKey, ["d", 1])
        self.accept("d-up", self.setKey, ["d", 0])
        self.accept("wheel_up", self.zoomCamera, [-1])
        self.accept("wheel_down", self.zoomCamera, [1])

        self.accept('window-event', self.handleWindowEvent)

        props = WindowProperties()
        props.setCursorHidden(True) 
        base.win.requestProperties(props)

        self.last_mouse_x = self.win.getPointer(0).getX()

    def setKey(self, key, value):

        self.keys[key] = value

    def handleWindowEvent(self, window=None):

        wp = window.getProperties()

        self.win_center_x = wp.getXSize() / 2
        self.win_center_y = wp.getYSize() / 2

    def zoomCamera(self, direction):

        self.cam_away += direction

    def gameLoop(self, task):

        dt = globalClock.getDt()

        #self.avatarNP.setY(self.avatarNP, 10 * dt)

        if self.keys["w"]: self.avatarNP.setZ(self.avatarNP, 5 * dt)

        if self.keys["s"]: self.avatarNP.setZ(self.avatarNP, -5 * dt)

        if self.keys["a"]: self.avatarNP.setX(self.avatarNP, -5 * dt)

        if self.keys["d"]: self.avatarNP.setX(self.avatarNP, 5 * dt)

        #Mouse-based viewpoint rotation

        mouse_pos = self.win.getPointer(0)

        current_mouse_x = mouse_pos.getX()
        current_mouse_y = mouse_pos.getY()

        mouse_shift_x = current_mouse_x - self.last_mouse_x
        mouse_shift_y = current_mouse_y - self.last_mouse_y

        self.last_mouse_x = current_mouse_x
        self.last_mouse_y = current_mouse_y

        if current_mouse_x == 0 or current_mouse_x >= (self.win_center_x * 1.5):

            base.win.movePointer(0, self.win_center_x, self.win_center_y)
            self.last_mouse_x = self.win_center_x

        if current_mouse_y == 0 or current_mouse_y >= (self.win_center_y * 1.5):

            base.win.movePointer(0, self.win_center_x, self.win_center_y)
            self.last_mouse_y = self.win_center_y

        #self.cam.setP(0)

        yaw_shift = -((mouse_shift_x) * self.rot_rate)
        pitch_shift = -((mouse_shift_y) * self.rot_rate)

        self.avatarYawRot += yaw_shift
        self.avatarPitchRot += pitch_shift

        self.avatarNP.setH(self.avatarYawRot)
        self.cam.setH(self.avatarYawRot)
        self.cam.setP(-self.avatarPitchRot)

        xy_plane_cam_dist = self.cam_away*cos(radians(self.avatarPitchRot))

        cam_x_adjust = xy_plane_cam_dist*sin(radians(self.avatarYawRot))  
        cam_y_adjust = xy_plane_cam_dist*cos(radians(self.avatarYawRot))
        cam_z_adjust = self.cam_away*sin(radians(self.avatarPitchRot))

        print self.camera.getPos()
        self.cam.setPos(self.avatarNP.getX() + cam_x_adjust, self.avatarNP.getY() - cam_y_adjust, 
                        self.avatarNP.getZ() + cam_z_adjust)

        print self.avatarNP.getPos()

        #self.cam.setP(self.x)
        #self.x += .01

        #self.cTrav.traverse(render)

        #entries = []

        #for i in range(self.pandaGroundCollisionHandler.getNumEntries()):

        #    entry = self.pandaGroundCollisionHandler.getEntry(i)
        #    entries.append(entry)

        #for entry in entries:

        #    print entry.getIntoNode().getName()

        #    if entry.getIntoNode().getName() == "terrain":

        #        print "shiet"

        #        self.pandaActor.setZ(entry.getSurfacePoint(render).getZ())

        return Task.cont
Ejemplo n.º 29
0
class World(ShowBase):

    def __init__(self):

        # Load the default configuration.prc. This is recommended, as it
        # contains some important panda options
        loadPrcFile("../../Config/configuration.prc")

        ShowBase.__init__(self)

        # Create a new pipeline instance
        self.renderPipeline = RenderingPipeline(self)

        # Set the base path for the pipeline. This is required as we are in
        # a subdirectory
        self.renderPipeline.getMountManager().setBasePath("../../")

        # Also set the write path
        self.renderPipeline.getMountManager().setWritePath("../../Temp/")

        # Load the default settings
        self.renderPipeline.loadSettings("../../Config/pipeline.ini")

        # Now create the pipeline
        self.renderPipeline.create()

        # Add a directional light
        dPos = Vec3(40, 40, 15)
        dirLight = DirectionalLight()
        dirLight.setPos(dPos * 1000000.0)
        dirLight.setShadowMapResolution(1024)
        dirLight.setCastsShadows(True)
        dirLight.setColor(Vec3(8))
        self.renderPipeline.addLight(dirLight)
        self.renderPipeline.setScatteringSource(dirLight)
        self.dirLight = dirLight



        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0}
        base.win.setClearColor(Vec4(0, 0, 0, 1))

        # Post the instructions

        self.title = addTitle(
            "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward")
        self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left")
        self.inst7 = addInstructions(0.65, "[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.environ.setPos(0, 0, 0)

        self.environ.find("**/wall").removeNode()

        # 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)

        self.renderPipeline.setEffect(self.ralph, "Effects/Default/Default.effect", {
                "dynamic": True
            })

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

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

        # NOTICE: It is important that your update tasks have a lower priority
        # than -10000
        taskMgr.add(self.move, "moveTask", priority=-20000)

        self.accept("r", self.reloadShader)

        # Game state variables
        self.isMoving = False

        # Set up the camera

        base.disableMouse()
        base.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 1.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, 1000)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.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, 1000)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.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 ocean
        self.water = ProjectedWaterGrid(self.renderPipeline)
        self.water.setWaterLevel(-4.0)

        # Create the skybox
        self.skybox = self.renderPipeline.getDefaultSkybox()
        self.skybox.reparentTo(render)

        self.prepareSRGB(render)
        self.reloadShader()
        self.renderPipeline.onSceneInitialized()

        # Add demo slider to move the sun position
        if self.renderPipeline.settings.displayOnscreenDebugger:
            self.renderPipeline.guiManager.demoSlider.node[
                "command"] = self.setSunPos
            self.renderPipeline.guiManager.demoSlider.node[
                "value"] = 50

    def setSunPos(self):
        rawValue = self.renderPipeline.guiManager.demoSlider.node["value"]
        dPos = Vec3(100, 100, rawValue - 20)
        self.dirLight.setPos(dPos * 100000000.0)

        
    def reloadShader(self):
        self.renderPipeline.reloadShaders()

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

    def prepareSRGB(self, np):
        """ Sets the correct texture format for all textures found in <np> """
        for tex in np.findAllTextures():

            baseFormat = tex.getFormat()

            if baseFormat == Texture.FRgb:
                tex.setFormat(Texture.FSrgb)
            elif baseFormat == Texture.FRgba:
                tex.setFormat(Texture.FSrgbAlpha)
            else:
                print "Unkown texture format:", baseFormat
                print "\tTexture:", tex

            # tex.setMinfilter(Texture.FTLinearMipmapLinear)
            # tex.setMagfilter(Texture.FTLinear)
            tex.setAnisotropicDegree(16)

    # 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 the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        base.camera.lookAt(self.ralph)
        if (self.keyMap["cam-left"] != 0):
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["cam-right"] != 0):
            base.camera.setX(base.camera, +20 * globalClock.getDt())

        # 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"] != 0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        if (self.keyMap["right"] != 0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"] != 0):
            self.ralph.setY(self.ralph, -25 * globalClock.getDt())

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

        if (self.keyMap["forward"] != 0) or (self.keyMap["left"] != 0) or (self.keyMap["right"] != 0):
            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() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 7.0):
            base.camera.setPos(base.camera.getPos() + camvec * (camdist - 7))
            camdist = 7.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec * (5 - camdist))
            camdist = 5.0

        # Now check for collisions.

        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 = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(),
                                      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 = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(),
                                      x.getSurfacePoint(render).getZ()))
        if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.5):
            base.camera.setZ(self.ralph.getZ() + 2.5)

        # 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.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + 2.0)
        base.camera.lookAt(self.floater)

        return task.cont
Ejemplo n.º 30
0
class Main(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        global picture_names
        picture_names = [f for f in listdir('images') if isfile(join('images', f))]
        
        self.handScale = 1
        self.handV=ZERO
        self.scale = 20 / self.handScale
        self.ex = Vec3(1,0,0)
        self.ez = Vec3(0,0,-1)
        
        self.leap = Leap.Controller()
        self.title = OnscreenText(text="Wen-Jye's Panda3D Leap Motion",
                              style=1, fg=(1,1,0,1),
                              pos=(0.7,-0.95), scale = .07)
        self.score = OnscreenText(text="",
                                     pos = (-1.3, .75), fg=(1,1,0,1),
                                     align = TextNode.ALeft, scale = .1)
        self.timer = OnscreenText(text="",
                                     pos = (-1.3, .85), fg=(1,1,0,1),
                                     align = TextNode.ALeft, scale = .1)
    
        
        self.cTrav = CollisionTraverser()
        self.cHandler = CollisionHandlerQueue()
        self.handLoader()
        
        self.tracks = self.loader.loadModel("models/tracks")
        self.tracks.setScale(1,1.5,1)
        self.tracks.setPosHpr(-3, STAGE_HEIGHT, 12, 90, 90, 90)
        
        self.train = self.loader.loadModel("models/train")
        self.train.setScale(1,0.5,0.5)
        self.train.setPosHpr(16, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
        
        
        self.stage = self.loader.loadModel("models/stage")
        self.stage.setScale(0.55,0.50,0.25)
        self.stage.setPosHpr(0, STAGE_HEIGHT-0.5, 2, 90, 180, 90)
        self.mesh = self.stage.find("**/mesh_stage")
        self.floor = self.stage.find("**/floor")
        self.floor.node().setIntoCollideMask(BitMask32.bit(0))
        self.wall_B = self.stage.find("**/wall_B")
        self.wall_B.node().setIntoCollideMask(BitMask32.bit(0))
        self.wall_F = self.stage.find("**/wall_F")
        self.wall_F.node().setIntoCollideMask(BitMask32.bit(0))
        self.wall_R = self.stage.find("**/wall_R")
        self.wall_R.node().setIntoCollideMask(BitMask32.bit(0))
        self.wall_L = self.stage.find("**/wall_L")
        self.wall_L.node().setIntoCollideMask(BitMask32.bit(0))
        
        self.buttonList = [render.attachNewNode("button_%i"  % (i+1)) for i in range(3)] # @UndefinedVariable
        for i in range(len(self.buttonList)):
            self.buttonCreator(i) 
            self.buttonList[i].detachNode()
        self.setLight()        
        self.errorMsg = OnscreenText(text="", pos = (0,0), fg=(1,1,0,1), align = TextNode.ACenter, scale = .1)
        self.taskMgr.add(self.spinCameraTask, "SpinCameraTask")
        
        self.menuBG = self.loadImageAsPlane("tex/startScreen.jpg" )
        self.menuBG.setScale(12.5,9,8.5)
        self.menuBG.reparentTo(self.render)
        self.menuBG.setPosHpr(0,STAGE_HEIGHT+1.5,-2, 0, -105, 0)
        self.menuBG.setTransparency(TransparencyAttrib.MAlpha)
        self.menuBG.setAlphaScale(1)
        self.taskMgr.add(self.deviceChecker, "deviceChecker")
    def spinCameraTask(self, task):
        self.camera.setPos(0,STAGE_HEIGHT+10,30)
        self.camera.setHpr(0,255,0)
        self.camLens.setFov(65)
        return Task.cont
    def loadImageAsPlane(self, filepath, yresolution = 600):
        tex = loader.loadTexture(filepath) # @UndefinedVariable
        tex.setBorderColor(Vec4(0,0,0,0))
        tex.setWrapU(Texture.WMBorderColor)
        tex.setWrapV(Texture.WMBorderColor)
        cm = CardMaker(filepath + ' card')
        cm.setFrame(-tex.getOrigFileXSize(), tex.getOrigFileXSize(), -tex.getOrigFileYSize(), tex.getOrigFileYSize())
        card = NodePath(cm.generate())
        card.setTexture(tex)
        card.setScale(card.getScale()/ yresolution)
        card.flattenLight() # apply scale
        return card
    def handLoader(self):
        self.palm_R = self.loader.loadModel("%s/palm_R" % LOAD_HAND_FROM) # @UndefinedVariable
        self.palm_R_collider = self.palm_R.find("**/palm_R_collider")
        self.palm_R_collider.node().setIntoCollideMask(BitMask32.bit(0))
        self.fing_R = [self.loader.loadModel("%s/fing%i_R" % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.midd_R = [self.loader.loadModel("%s/m%i_R"    % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.base_R = [self.loader.loadModel("%s/b%i_R"    % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.fing_R_collider = [self.fing_R[i].find("**/fing%i_R_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        self.midd_R_collider = [self.midd_R[i].find("**/m%i_R_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        self.base_R_collider = [self.base_R[i].find("**/b%i_R_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        self.palm_L = self.loader.loadModel("%s/palm_L" % LOAD_HAND_FROM) # @UndefinedVariable
        self.palm_R_collider = self.palm_L.find("**/palm_L_collider")
        self.palm_R_collider.node().setIntoCollideMask(BitMask32.bit(0))
        self.fing_L = [self.loader.loadModel("%s/fing%i_L" % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.midd_L = [self.loader.loadModel("%s/m%i_L"    % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.base_L = [self.loader.loadModel("%s/b%i_L"    % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.fing_L_collider = [self.fing_L[i].find("**/fing%i_L_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        self.midd_L_collider = [self.midd_L[i].find("**/m%i_L_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        self.base_L_collider = [self.base_L[i].find("**/b%i_L_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        
        self.palm_R.setScale(self.handScale, self.handScale, self.handScale*1.5)
        self.palm_L.setScale(self.handScale, self.handScale, self.handScale*1.5)
        for f in self.fing_R: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.midd_R: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.base_R: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.fing_L: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.midd_L: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.base_L: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.fing_R_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
        for f in self.midd_R_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
        for f in self.base_R_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
        for f in self.fing_L_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
        for f in self.midd_L_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
        for f in self.base_L_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
    def deviceChecker(self, task):
        if self.leap.is_connected: 
            if len(self.leap.frame().hands) is 0:
                self.errorMsg.setText("please place the hand above the device to start")
                return Task.cont
            else:
                base.cTrav = self.cTrav # @UndefinedVariable
                self.errorMsg.setText("")
                self.menuBG.detachNode()
                taskMgr.remove("handUpdater")  # @UndefinedVariable
                self.handLoop = taskMgr.add(self.handUpdater, "handUpdater") # @UndefinedVariable
                self.handLoop.last = 0
                self.homeInitial()
                return Task.done
        else: 
            self.errorMsg.setText("please connect device")
            return Task.cont
    def buttonCreator(self, buttonRoot):
        button = loader.loadModel("models/button") # @UndefinedVariable
        button.setScale(0.3,0.4,0.25)
        button.reparentTo(self.buttonList[buttonRoot]) # @UndefinedVariable
        buttonMesh = button.find("**/mesh_button")
        myTexture = self.loader.loadTexture('tex/start_%i.png' %(buttonRoot+1))
        buttonMesh.setTexture(myTexture,1)
        buttonCollider = button.find("**/collider_button")
        buttonCollider.node().setFromCollideMask(BitMask32.bit(0))
        self.cTrav.addCollider(buttonCollider, self.cHandler)
    def cubeCreator(self, i, cubeRoot):
        global tempCubeList
        cube = loader.loadModel("models/cube") # @UndefinedVariable
        print(i)
        cube.reparentTo(tempCubeList[i][0]) # @UndefinedVariable
        cubeMesh = cube.find("**/mesh_cube")
        myTexture = self.loader.loadTexture('cubes/tex_%i.jpg' %(cubeRoot))
        cubeMesh.setTexture(myTexture,1)
        cubeSphere = cube.find("**/collider_cube")
        cubeSphere.node().setFromCollideMask(BitMask32.bit(0))
        self.cTrav.addCollider(cubeSphere, self.cHandler)
    def clamp(self, i, mn=0, mx=1):
        return min(max(i, mn), mx)    
    def setLight(self):
        #self.ambientText = self.makeStatusLabel(0)
        self.ambientLight = self.render.attachNewNode(AmbientLight("ambientLight")) 
        # Set the color of the ambient light
        self.ambientLight.node().setColor((1, 1, 1, 1))
        self.render.setLight(self.ambientLight)
        
        self.directionalLight = self.render.attachNewNode(
            DirectionalLight("directionalLight"))
        self.directionalLight.node().setColor((.35, .35, .35, 1))
        # The direction of a directional light is set as a 3D vector
        self.directionalLight.node().setDirection(Vec3(1, 1, -2))
        # These settings are necessary for shadows to work correctly
        self.directionalLight.setY(6)
        dlens = self.directionalLight.node().getLens()
        dlens.setFilmSize(41, 21)
        dlens.setNearFar(50, 75)
        self.render.setLight(self.directionalLight)
        self.color = self.directionalLight.node().getColor()
        h, s, b = colorsys.rgb_to_hsv(self.color[0], self.color[1], self.color[2])
        brightness = self.clamp(b + 0)
        r, g, b = colorsys.hsv_to_rgb(h, s, brightness)
        self.directionalLight.node().setColor((r, g, b, 1))
        
        self.lightSourceSphere = self.loader.loadModel('models/sphere')
        self.lightSourceSphere.setColor((1, 1, 1, 1))
        self.lightSourceSphere.setPos(0,STAGE_HEIGHT+4,3)
        self.lightSourceSphere.setScale(.25)
        self.lightSource = self.lightSourceSphere.attachNewNode(PointLight("lightSource"))
        self.lightSource.node().setAttenuation(Vec3(1, 0.04, 0.1))
        self.lightSource.node().setColor((1, 1, 1, 1))
        self.lightSource.node().setSpecularColor((1, 1, 1, 1))
        self.render.setLight(self.lightSource)
        
    def homeInitial(self):
        global gameStart
        global returnHome
        global tryAgain
        gameStart = False
        tryAgain = False
        returnHome = False
        
        self.menuBG.reparentTo(self.render)
        myTexture = self.loader.loadTexture('tex/home.jpg')
        self.menuBG.setTexture(myTexture,1)
        
        self.buttonList[0].reparentTo(self.render)
        self.buttonList[0].setPosHpr(-6, STAGE_HEIGHT-1, 0, -90, 0, -105)
        
        taskMgr.remove("homeTask")  # @UndefinedVariable
        self.menu = taskMgr.add(self.homeTask, "homeTask") # @UndefinedVariable
        self.menu.last = 0
    def homeTask(self, task):
        global gameStart
        if pointable_finger is None: return Task.cont
        for i in range(len(self.buttonList)):
            buttonPressed = Vec3(1,1,1)
            for f in range(self.cHandler.getNumEntries()):
                entry = self.cHandler.getEntry(f)
                tipName = entry.getIntoNode().getName()
                name = entry.getFromNode().getName()
                if name == "collider_button" and tipName == fingerTip[pointable_finger.type]: 
                    if self.buttonPress(entry, i): buttonPressed= (Vec3(1.1,1.1,1.1))
            self.buttonList[i].setScale(buttonPressed)
        if gameStart: 
            self.stage.reparentTo(self.render)
            self.buttonList[0].detachNode()
            self.menuBG.detachNode()
            self.gameInitial(len(picture_names), True)
            taskMgr.remove("inGameTask") # @UndefinedVariable
            self.inGameTaskLoop = taskMgr.add(self.inGameTask, "inGameTask") # @UndefinedVariable
            self.inGameTaskLoop.last = 0
            gameStart = False        
            return Task.done
        else: return Task.cont
    def scoreInitial(self):
        global gameStart
        global returnHome
        global tryAgain
        global answer
        global renderedCube
        global score
        global question_list
        question_list.clear()
        gameStart = False
        tryAgain = False
        returnHome = False
        scoreCubes = []
        for i in range(len(renderedCube)): 
            taskMgr.remove("physicsTask_%i" % (i)) # @UndefinedVariable
            if len(answer)>i: self.cargos[i][0].removeNode()
            tempCubeList[i][0].removeNode()
        self.image.removeNode()
        self.cargos.clear()
        renderedCube.clear()
        tempCubeList.clear()
        answer.clear()
        self.train.setPosHpr(16, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
        self.train.detachNode()
        self.stage.detachNode()
        self.tracks.detachNode()
        self.timer.setText("")
        self.score.setText("")
        
        self.menuBG.reparentTo(self.render)
        myTexture = self.loader.loadTexture('tex/score.jpg')
        self.menuBG.setTexture(myTexture,1)
        
        for i in range(len(str(score))):        
            temp = cubeList.index(str(score)[i])
            scoreCubes.append(loader.loadModel("models/cube"))# @UndefinedVariable
            scoreCubes[i].reparentTo(self.render) # @UndefinedVariable
            scoreCubes[i].setPos(3.5+(int(i)*2.4),STAGE_HEIGHT+2.5-(i*0.1),-1)
            scoreCubes[i].setHpr(0,-2,-15)
            cubeMesh = scoreCubes[i].find("**/mesh_cube")
            myTexture = self.loader.loadTexture('cubes/tex_%i.jpg' %(temp))
            cubeMesh.setTexture(myTexture,1)
        
        self.buttonList[1].reparentTo(self.render)
        self.buttonList[1].setPosHpr(-7, STAGE_HEIGHT-5, 0, -90, 0, -105)
        
        self.buttonList[2].reparentTo(self.render)
        self.buttonList[2].setPosHpr(8.5, STAGE_HEIGHT-5, 0, -90, 0, -105)
        
        taskMgr.remove("scoreTask")  # @UndefinedVariable
        self.scoreLoop = taskMgr.add(self.scoreTask, "scoreTask", extraArgs = [scoreCubes], appendTask=True) # @UndefinedVariable
        self.scoreLoop.last = 0   
        score = 0     
    def scoreTask(self, scoreCubes, task):
        global tryAgain
        global returnHome
        for i in range(len(self.buttonList)):
            buttonPressed = Vec3(1,1,1)
            for f in range(self.cHandler.getNumEntries()):
                entry = self.cHandler.getEntry(f)
                tipName = entry.getIntoNode().getName()
                name = entry.getFromNode().getName()
                if name == "collider_button" and tipName == fingerTip[pointable_finger.type]: 
                    if self.buttonPress(entry, i): buttonPressed= (Vec3(1.1,1.1,1.1))
            self.buttonList[i].setScale(buttonPressed)
        if tryAgain: 
            self.stage.reparentTo(self.render)
            for f in scoreCubes: f.removeNode()
            scoreCubes.clear()
            self.buttonList[1].detachNode()
            self.buttonList[2].detachNode()
            self.menuBG.detachNode()
            self.gameInitial(len(picture_names),True)
            taskMgr.remove("inGameTask") # @UndefinedVariable
            self.inGameTaskLoop = taskMgr.add(self.inGameTask, "inGameTask") # @UndefinedVariable
            self.inGameTaskLoop.last = 0
            return task.done
        elif returnHome:
            for f in scoreCubes: f.removeNode()
            scoreCubes.clear()
            self.menuBG.detachNode()
            self.buttonList[1].detachNode()
            self.buttonList[2].detachNode()
            self.homeInitial()
            return task.done            
        else: return task.cont
    def gameInitial(self, question, englishGame):
        global answer
        global gameStart
        global returnHome
        global tryAgain
        global score
        global question_list
        gameStart = False
        tryAgain = False
        returnHome = False
        tempQuestion= ""
        
        self.score.setText("Score: %i" % (score))
        self.ballAccelV = GRAVITY
        self.tracks.reparentTo(self.render)
        self.trainV = Vec3(0,0,0)
        self.train.reparentTo(self.render)
        self.trainV = Vec3(-5,0,0)
        if(englishGame):
            temp = randint(0, question-1)
            while temp in question_list: temp = randint(0, question-1)
            tempQuestion = picture_names[temp][:picture_names[temp].index('.')]
            print(tempQuestion)
            question_list.append(temp)
            self.image = self.loadImageAsPlane("images/%s" % (picture_names[temp]))
            self.image.reparentTo(self.render)
            self.image.setScale(self.image.getScale()*1.2)
            self.image.setPosHpr(0,STAGE_HEIGHT+3.5,-11, 90, 270, 90)
            self.image.setTransparency(TransparencyAttrib.MAlpha)
            self.image.setAlphaScale(1)
            self.cargos = [[self.loader.loadModel("models/cargo"), -1] for i in range(len(tempQuestion))] # @UndefinedVariable
            for i in range(len(self.cargos)):
                self.cargos[i][0].reparentTo(self.render)
                self.cargos[i][0].setScale(1,0.3,0.3)
                self.cargos[i][0].setScale(1,0.32,0.32)
                if i == 0:self.cargos[i][0].setPosHpr(self.train.getX()+2.5, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
                else: self.cargos[i][0].setPosHpr(self.cargos[i-1][0].getX()+2, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
    
            taskMgr.remove("trainMovingTask") # @UndefinedVariable
            self.trainEnter = taskMgr.add(self.trainMovingTask, "trainMovingTask", extraArgs = [True], appendTask=True ) # @UndefinedVariable
            self.trainEnter.last = 0
            
            usedPos = random.sample(range(0, 10), 10)
            for i in range(10):
                if i<len(tempQuestion):
                    temp = cubeList.index(tempQuestion[i])
                    answer.append(temp)
                    self.assignCube(temp, i, usedPos)
                else: 
                    temp = randint(10,35)
                    while temp in answer: temp = randint(10,35)
                    self.assignCube(temp, i, usedPos)
        else:
            temp = randint(0, question-1)
            while temp in question_list: temp = randint(0, question-1)
            tempQuestion = picture_names[temp][:picture_names[temp].index('.')]
            question_list.append(temp)
            self.image = self.loadImageAsPlane("images/%s" % (picture_names[temp]))
            self.image.reparentTo(self.render)
            self.image.setScale(self.image.getScale()*1.2)
            self.image.setPosHpr(0,STAGE_HEIGHT+3.5,-11, 90, 270, 90)
            self.image.setTransparency(TransparencyAttrib.MAlpha)
            self.image.setAlphaScale(1)
            self.cargos = [[self.loader.loadModel("models/cargo"), -1] for i in range(len(tempQuestion))] # @UndefinedVariable
            for i in range(len(self.cargos)):
                self.cargos[i][0].reparentTo(self.render)
                self.cargos[i][0].setScale(1,0.3,0.3)
                self.cargos[i][0].setScale(1,0.32,0.32)
                if i == 0:self.cargos[i][0].setPosHpr(self.train.getX()+2.5, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
                else: self.cargos[i][0].setPosHpr(self.cargos[i-1][0].getX()+2, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
    
            taskMgr.remove("trainMovingTask") # @UndefinedVariable
            self.trainEnter = taskMgr.add(self.trainMovingTask, "trainMovingTask", extraArgs = [True], appendTask=True ) # @UndefinedVariable
            self.trainEnter.last = 0
            
            usedPos = random.sample(range(0, 10), 10)
            for i in range(10):
                if i<len(tempQuestion):
                    temp = cubeList.index(tempQuestion[i])
                    answer.append(temp)
                    self.assignCube(temp, i, usedPos)
                else: 
                    temp = randint(10,35)
                    while temp in answer: temp = randint(10,35)
                    self.assignCube(temp, i, usedPos)
    def assignCube(self, temp, i, usedPos):
        global renderedCube   
        global tempCubeList
        pos = len(tempCubeList)
        renderedCube.append(temp) 
        tempCubeList.append([render.attachNewNode("cubeRoot_%i"  % (temp)), Vec3(randint(-3, 3),7,randint(-3, 3))]) # @UndefinedVariable
        self.cubeCreator(pos,temp) 
            
        tempCubeList[pos][0].reparentTo(self.render)
        tempCubeList[pos][0].setPos(cubesPosList[usedPos[i]])
        tempCubeList[pos][0].setHpr(0,0,0)
        taskMgr.remove("physicsTask_%i" % (i)) # @UndefinedVariable
        self.physicsTaskLoop = taskMgr.add(self.physicsTask, "physicsTask_%i" % (i),extraArgs = [pos], appendTask=True) # @UndefinedVariable
        self.physicsTaskLoop.last = 0 
    
    def inGameTask(self, task):
        global gameSuccess
        global score
        global gameInter
        global timer
        secs = timer - int(task.time)
        mins = int(secs/60)
        self.timer.setText('{:02d}:{:02d}'.format(mins, secs%60))
            
        if secs <= -1:
            #score= score+22
            gameInter= False
            self.errorMsg.setText("")
            taskMgr.remove("trainMovingTask")  # @UndefinedVariable
            self.scoreInitial()
            return Task.done
        if gameInter: return Task.cont
        fail = True
        gameSuccess = True
        for i in range(len(answer)):
            if self.cargos[i][1] == -1: fail = False
            if answer[i] != renderedCube[self.cargos[i][1]]:
                gameSuccess = False
        if gameSuccess: 
            self.errorMsg.setText("Success")
            score = score +1
            self.score.setText("Score: %i" % (score))
            gameInter = True
            taskMgr.remove("trainMovingTask") # @UndefinedVariable
            self.trainLeaving = taskMgr.add(self.trainMovingTask, "trainMovingTask", extraArgs = [False], appendTask=True ) # @UndefinedVariable
            self.trainLeaving.last = 0
            
        elif fail: self.errorMsg.setText("FAIL")
        else: self.errorMsg.setText("")
        return Task.cont
    def buttonPress(self, colEntry, button):
        global gameStart
        global returnHome
        global tryAgain
        if colEntry.getFromNodePath().getPos(self.buttonList[button]).length() == 0:
            norm = colEntry.getSurfaceNormal(render) * -1 # The normal of the hand # @UndefinedVariable
            handCurSpeed = self.handV.length()                # The current hand speed
            hitDir = colEntry.getSurfacePoint(render) - self.buttonList[button].getPos() # @UndefinedVariable
            hitDir.normalize()                            
            hitAngle = self.dotProduct(norm, hitDir)
            if hitAngle > 0 and handCurSpeed>100 and self.handV[2]<-1: 
                if button == 0: gameStart = True
                elif button == 1: returnHome = True
                elif button == 2: tryAgain = True
            return True
        else: return False
    def trainMovingTask(self, arriving, task):
        global tempCubeList
        global answer
        global renderedCube
        global gameInter
        dt = task.time - task.last
        task.last = task.time
        if dt > .1: return Task.cont 
        if arriving:
            if self.train.getX()<0:  self.trainV += Vec3(1,0,0)* dt * trainAccel[len(answer)]
            self.train.setPos(self.train.getPos() + (self.trainV * dt))
            for f in self.cargos: f[0].setPos(f[0].getPos() + (self.trainV * dt))
            if self.trainV[0]>0:
                self.trainV = Vec3(0,0,0)
                return Task.done
        else: 
            self.trainV += Vec3(-1,0,0)* dt * trainAccel[len(answer)]
            self.train.setPos(self.train.getPos() + (self.trainV * dt))
            for i in range(len(answer)): 
                newPos = self.cargos[i][0].getPos() + (self.trainV * dt)
                self.cargos[i][0].setPos(newPos)
                tempCubeList[self.cargos[i][1]][0].setPos(newPos+Vec3(0,1.4,0))
            if self.cargos[len(answer)-1][0].getX()<-16:
                for i in range(len(renderedCube)): 
                    if len(answer)>i: self.cargos[i][0].remove_node()
                    tempCubeList[i][0].removeNode()
                self.image.removeNode()
                tempCubeList.clear()
                renderedCube.clear()
                self.cargos.clear()
                answer.clear()
                gameInter = False
                self.train.setPosHpr(16, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
                self.gameInitial(len(picture_names),True)
                return task.done
        return Task.cont            
    def physicsTask(self, cube, task):
        global trigger_pinch
        global trigger_pinch_threshold
        global lastPinchFrame
        global pinch_cube
        if gameInter: return task.done
        isLoaded = False
        dt = task.time - task.last
        task.last = task.time
        if dt > .1: return Task.cont 
        df = 0
        if trigger_pinch and cube == pinch_cube: 
            lastPinchFrame = task.time
            trigger_pinch_threshold = True
        else: df = task.time - lastPinchFrame
        
        if cube == pinch_cube:
            if df < 0.1  and trigger_pinch_threshold is True and trigger_pinch is False: 
                cubeP = tempCubeList[pinch_cube][0].getPos()
                for f in self.cargos:
                    cargoP = f[0].getPos()
                    if cubeP[0]>cargoP[0]-1 and cubeP[0]<cargoP[0]+1 and cubeP[1] > cargoP[1] and cubeP[1] < cargoP[1]+4 and cubeP[2]>cargoP[2]-3 and cubeP[2]<cargoP[2]+3:
                        tempCubeList[pinch_cube][0].setPos(cargoP+Vec3(0,1.4,0))
                        lastPinchFrame = 0
                        trigger_pinch_threshold = False
                        f[1] = pinch_cube
                        pinch_cube = -1
                
                if trigger_pinch_threshold:
                    currentPos = self.thowingTask(False)
                    if currentPos.length() >0:
                        tempCubeList[cube][0].setPos(currentPos)
                    else: 
                        lastPinchFrame = 0
                        trigger_pinch_threshold = False
            
            elif df >= 0.1  and trigger_pinch_threshold is True: 
                lastPinchFrame = 0
                trigger_pinch_threshold = False
                pinch_cube = -1
                tempCubeList[cube][1] = self.thowingTask(True)
        for f in self.cargos:
            if f[1] == cube: 
                isLoaded=True
                
        if isLoaded : return Task.cont
        elif cube == pinch_cube and trigger_pinch_threshold: return Task.cont
        
        #if trigger_pinch_threshold is False:
        for i in range(self.cHandler.getNumEntries()):
            entry = self.cHandler.getEntry(i)
            name = entry.getIntoNode().getName()
            if name == "palm_L_collider": self.handCollideHandler(entry, cube)
            elif name == "palm_R_collider": self.handCollideHandler(entry, cube)
            elif name == "floor": self.wallCollideHandler(entry, cube)
            elif name == "wall_B": self.wallCollideHandler(entry, cube)
            elif name == "wall_F": self.wallCollideHandler(entry, cube)
            elif name == "wall_R": self.wallCollideHandler(entry, cube)
            elif name == "wall_L": self.wallCollideHandler(entry, cube)
            elif name == "collider_cube": self.cubeCollideHandler(entry, cube)
            elif trigger_pinch_threshold is False: self.handCollideHandler(entry, cube)
        
        tempCubeList[cube][1] += self.ballAccelV * dt * ACCEL
        if tempCubeList[cube][1].lengthSquared() > MAX_SPEED_SQ:
            tempCubeList[cube][1].normalize()
            tempCubeList[cube][1] *= MAX_SPEED
        tempCubeList[cube][0].setPos(tempCubeList[cube][0].getPos() + (tempCubeList[cube][1] * dt))
        return Task.cont
    def thowingTask(self, thowing):
        global pinch_position
        global pinch_finger
        self.frame = self.leap.frame()
        temp = self.frame.hands[pinch_finger[0]].palm_velocity
        releaseHandV = Vec3((temp[0], temp[1], temp[2]))/self.scale
        thumb_tip = self.frame.hands[pinch_finger[0]].fingers[0].bone(3).next_joint
        joint_position = self.frame.hands[pinch_finger[0]].fingers[pinch_finger[1]].bone(3).next_joint
        distance = thumb_tip - joint_position
        release_position = joint_position + Vector(distance[0]/2, distance[1]/2, distance[2]/2)
        release_position = Vec3((release_position[0], release_position[1], release_position[2]))/self.scale
        if thowing is True: 
            thowingV = release_position-pinch_position
            pinch_finger = [-1,-1]
            return releaseHandV
        else: 
            return release_position
    def dotProduct(self, pos1, pos2):
        v1 = (round(pos1[0], 8),round(pos1[1], 8),round(pos1[2], 8))
        v2 = (round(pos2[0], 8),round(pos2[1], 8),round(pos2[2], 8))
        v1_u = v1 / numpy.linalg.norm(v1)
        v2_u = v2 / numpy.linalg.norm(v2)
        return numpy.dot(v1_u, v2_u)
    def cubeCollideHandler(self, colEntry, cube):
        if colEntry.getFromNodePath().getPos(tempCubeList[cube][0]).length() == 0:
            ballV=Vec3(0,0,0)
            tempCubeList[cube][1] = ballV
            disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) # @UndefinedVariable
            newPos = tempCubeList[cube][0].getPos() + disp
            tempCubeList[cube][0].setPos(newPos)        
    def handCollideHandler(self, colEntry, cube):
        if colEntry.getFromNodePath().getPos(tempCubeList[cube][0]).length() == 0:
            norm = colEntry.getSurfaceNormal(render) * -1               # The normal of the hand # @UndefinedVariable
            curSpeed = tempCubeList[cube][1].length()                 # The current ball speed
            inVec = tempCubeList[cube][1] / curSpeed                  # The direction of ball travel
            velAngle = self.dotProduct(norm, inVec)     
            totalV = Vec3(tempCubeList[cube][1][0]+self.handV[0],tempCubeList[cube][1][1]+self.handV[1],tempCubeList[cube][1][2]+self.handV[2])
            ballV=Vec3(totalV[0]/10,totalV[1]/10,totalV[2]/10)
            if velAngle > 0:
                tempCubeList[cube][1] = ballV
                disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) # @UndefinedVariable
                newPos = tempCubeList[cube][0].getPos() + disp
                tempCubeList[cube][0].setPos(newPos)        
    def wallCollideHandler(self, colEntry, cube):
        if colEntry.getFromNodePath().getPos(tempCubeList[cube][0]).length() == 0:
            ballV=Vec3(-tempCubeList[cube][1][0],tempCubeList[cube][1][1],tempCubeList[cube][1][2])
            if colEntry.getIntoNode().getName() == "wall_F" or colEntry.getIntoNode().getName() == "wall_B":
                ballV=Vec3(tempCubeList[cube][1][0],tempCubeList[cube][1][1],-tempCubeList[cube][1][2])
            elif colEntry.getIntoNode().getName() == "floor": 
                ballV=Vec3(tempCubeList[cube][1][0]/2,-tempCubeList[cube][1][1]/2,tempCubeList[cube][1][2]/2)
                if ballV[2]<0.01: ballV[2] =0
            tempCubeList[cube][1] = ballV
            disp = (colEntry.getSurfacePoint(render)- colEntry.getInteriorPoint(render)) # @UndefinedVariable
            newPos = tempCubeList[cube][0].getPos() + disp
            tempCubeList[cube][0].setPos(newPos)
    def handUpdater(self, task):
        self.frame = self.leap.frame()
        global trigger_pinch
        pointables = self.frame.pointables
        trigger_pinch = False
        rightHand=None
        if len(self.frame.hands)>0:  
            front_pointable = pointables.frontmost
            for hand in self.frame.hands:
                if(hand.is_left and rightHand==None):
                    self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, self.frame.hands[0], 0, front_pointable)
                    rightHand=False
                elif(hand.is_right and rightHand==None):
                    self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, self.frame.hands[0], 0, front_pointable)
                    rightHand=True
                if(len(self.frame.hands)>1):
                    if(rightHand):
                        self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, self.frame.hands[1], 0, front_pointable)
                    else:
                        self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, self.frame.hands[1], 0, front_pointable)
                else:
                    if(rightHand):
                        self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, None, None, front_pointable)
                    else:
                        self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, None, None, front_pointable)
        else:
            self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, None, None, None)
            self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, None, None, None)
            rightHand=None
        return Task.cont
    def plotHand(self, palm, fingerTips, fingerMiddles, fingerbases, leapHand, pinchHand, front_pointable):
        global pinch_finger
        global pointable_position
        global pointable_finger
        usedFingers = 0
        palmValid = False
        if(leapHand and leapHand.is_valid):
            palmValid = True
            palm_position, palm_quat = self.calcTrafo(leapHand.palm_position, -leapHand.palm_normal, self.ez, self.scale)
            palm.setPos(palm_position)
            #print(palm_position[2])
            palm.setQuat(palm_quat)
            thumb_tip = leapHand.fingers[0].bone(3).next_joint
            self.handV=Vec3(leapHand.palm_velocity[0], leapHand.palm_velocity[1], leapHand.palm_velocity[2])
            for i in range(len(leapHand.fingers)):
                lf = leapHand.fingers[i]                
                if lf.is_valid:
                    if i>0 and len(answer) >0: self.updatePinch(leapHand, thumb_tip, lf)
                    if trigger_pinch is True: 
                        pinch_finger[0] = pinchHand
                        pinch_finger[1] = i
                    bf = fingerTips[usedFingers]
                    bm = fingerMiddles[usedFingers]
                    bb = fingerbases [usedFingers]
                    usedFingers += 1
                    
                    bf.reparentTo(self.render)
                    tip_position, tip_quat = self.calcTrafo(lf.bone(3).next_joint, -lf.bone(3).direction, self.ex, self.scale)
                    bf.setPos(tip_position)
                    bf.setQuat(tip_quat)
                    
                    if str(front_pointable) == str(lf):
                        pointable_position = tip_position
                        pointable_finger = lf
                    
                    bm.reparentTo(self.render)
                    m1 = lf.bone(3).next_joint+lf.bone(3).direction*30
                    m2 = lf.bone(2).next_joint-m1
                    mid_position, mid_quat = self.calcTrafo(m1, lf.bone(2).direction, self.ex, self.scale)
                    #mid_position, mid_quat = self.calcTrafo(m1, m2, self.ex, self.scale)
                    bm.setPos(mid_position)
                    bm.setQuat(mid_quat)
                    
                    
                    bb.reparentTo(self.render)
                    b1 = lf.bone(2).next_joint+lf.bone(2).direction*30
                    b2 = leapHand.palm_position-b1
                    #base_position, base_quat = self.calcTrafo(b1, lf.bone(1).direction, self.ex, self.scale)
                    base_position, base_quat = self.calcTrafo(b1, b2, self.ex, self.scale)
                    bb.setPos(base_position)
                    bb.setQuat(base_quat)
                    
        if palmValid: palm.reparentTo(self.render)
        else: palm.detachNode()
        for i in range(usedFingers,5):
            fingerTips[i].detachNode()
            fingerMiddles[i].detachNode()
            fingerbases[i].detachNode()            
    def updatePinch(self, hand, tip, finger):
        global tempCubeList
        global trigger_pinch
        global pinch_position
        global pinch_cube
        joint_position = finger.bone(3).next_joint
        distance = tip - joint_position
        if distance.magnitude < 35:
            trigger_pinch = True
            pinch_position = joint_position + Vector(distance[0]/2, distance[1]/2, distance[2]/2)
            pinch_position = Vec3((pinch_position[0], pinch_position[1], pinch_position[2]))/self.scale
            
        if trigger_pinch is True:
            temp = 1.5
            for i in range(len(tempCubeList)):
                distance = pinch_position - tempCubeList[i][0].getPos()
                distance = Vector(distance[0], distance[1], distance[2])
                if distance.magnitude<temp: 
                    temp = distance.magnitude
                    self.unLoadedCube(i) 
                    pinch_cube = i
            if temp < 1.5: 
                tempCubeList[pinch_cube][0].setPos(pinch_position)
                trigger_pinch = True
            else: trigger_pinch = False
    def unLoadedCube(self, cube):
        for f in self.cargos:
            if f[1] == cube: 
                f[1]=-1
    def calcTrafo(self, leapPosition, leapDirection, e_i, scale):
        position = Vec3((leapPosition[0], leapPosition[1], leapPosition[2]))/scale
        direction = Vec3((leapDirection[0], leapDirection[1], leapDirection[2])).normalized()
        ang  = e_i.angleDeg(direction)
        axis = e_i.cross(direction).normalized()
        return position, LRotationf(axis, ang)
Ejemplo n.º 31
0
class App(ShowBase):
	def __init__(self):
		ShowBase.__init__(self)

		base.disableMouse()

		#Carrega o terreno
		self.terrain = loadCharEnvir().loadEnvir()


		#Declaracao de variaveis
		self.isMoving = False
		self.getClick = 0			#Quantos objetos foram clicados
		self.clickedObj = None
		self.terrainSize = 1024
		self.numLizards = 5
		self.numMaleLizards = 0
		self.numFemaleLizards = 0
		#self.contChamGetMed = 0		#Contador para saber se atualiza o ponto medio


		#Carrega os lagartos iniciais
		self.lizards = []
		for i in range(self.numLizards):
			randNum = random.randint(10,20)
			randNum2 = random.randint(10,20)
			lizard = loadCharEnvir().loadLizard(100 + (randNum+randNum2)*i,150 + (randNum+randNum2)*i,3)
			lizard.setTag("ID",str(i))
			self.lizards.append(lizard)
			if (lizard.getTag("femaleOrMale") == "1"):
				self.numMaleLizards = self.numMaleLizards + 1
			else:
				self.numFemaleLizards = self.numFemaleLizards + 1



		#Calcula o ponto medio dos lagartos, tanto femeas quantos machos
		self.getMedianGenderPoints()
		#taskMgr.add(self.getCloserToMedian, "Aproxima os lagartos do ponto medio dos generos")



 

		#Adiciona as tasks e as funcoes de teclado e mouse
		self.taskMgr.add(self.updateTask, "update")
		self.keyboardSetup()


		#CAMERAS:
		#Faz a camera seguir o lagarto
		#self.followcam = FollowCam(self.camera, self.lizards[0])

		#Faz a camera visualizar como um deus
		self.MoveCam = MoveCam(self.camera)


		#Ativa as colisoes
		self.setupMouseCollision()


	#Funcao que ajusta o angulo
	def clampAngle(self, angle):
		while angle < -180:
			angle = angle + 360
		while angle > 180:
			angle = angle -360

		return angle


	#Atribui um valor especifico para uma chave
	def keyboardSetup(self):
		self.keyMap = {"left":0, "right":0, "forward":0, "backward":0}
		self.accept("escape", sys.exit)
		self.accept("arrow_left", self.setKey, ["left", 1])
		self.accept("arrow_left-up", self.setKey, ["left", 0])
		self.accept("arrow_right", self.setKey, ["right", 1])
		self.accept("arrow_right-up", self.setKey, ["right", 0])
		self.accept("arrow_up", self.setKey, ["forward", 1])
		self.accept("arrow_up-up", self.setKey, ["forward", 0])
		self.accept("arrow_down", self.setKey, ["backward", 1])
		self.accept("arrow_down-up", self.setKey, ["backward", 0])
		self.accept("mouse1", self.leftMouseCommands)	#Pode ser adicionado um drag aqui
		self.accept("mouse3", self.rightMouseCommands)


	#Funcao que calcula o ponto medio da densidade de lagartos de cada genero
	def getMedianGenderPoints(self):
			self.medianMalePoint = (0,0,0)
			self.medianFemalePoint = (0,0,0)

			#Calculo do somatorio dos pontos para cada genero
			for i in range(self.numLizards):
				if (self.lizards[i].getTag("femaleOrMale") == "1"):
					self.medianMalePoint = self.lizards[i].getPos() + self.medianMalePoint
				else:
					self.medianFemalePoint = self.lizards[i].getPos() + self.medianFemalePoint

			#Calculo do ponto medio de cada genero
			if (self.numMaleLizards != 0):
				self.medianMalePoint = (self.medianMalePoint[0]/self.numMaleLizards, self.medianMalePoint[1]/self.numMaleLizards, self.medianMalePoint[2]/self.numMaleLizards)
			if (self.numFemaleLizards != 0):
				self.medianFemalePoint = (self.medianFemalePoint[0]/self.numFemaleLizards, self.medianFemalePoint[1]/self.numFemaleLizards, self.medianFemalePoint[2]/self.numFemaleLizards)



#=====================================================================================
	#NAO ESTA PRONTA // NAO FUNCIONA
	#Funcao que faz com que os lagartos, dependendo do genero, aproximem-se
#=====================================================================================

	"""
	def getCloserToMedian(self, task):

		maleMedianPoint = render.attachNewNode("male median point")
		maleMedianPoint.setPos(self.medianMalePoint)
		femaleMedianPoint = render.attachNewNode("female median point")
		femaleMedianPoint.setPos(self.medianFemalePoint)

		for i in range(self.numLizards):
			#Se for macho, procura for femeas
			if (self.lizards[i].getTag("femaleOrMale") == 1):
				lizardAuxPoint = render.attachNewNode("ponto auxiliar para obter heading")
				lizardAuxPoint.setPos(self.lizards[i].getPos())
				lizardAuxPoint.lookAt(femaleMedianPoint)
				self.lizards[i].setH(self.clampAngle(lizardAuxPoint.getH() + 180))
				self.lizards[i].setPos(self.lizards[i], self.lizards[i].getRelativeVector(femaleMedianPoint, Vec3(0.1,-0.1,0)))	
				print self.lizards[i].getRelativeVector(femaleMedianPoint, Vec3(0.1,-0.1,0))
				
				#Respeitando os limites do terreno
				if (self.lizards[i].getX() < 0):
					self.lizards[i].setX(0)
				elif (self.lizards[i].getX() > self.terrainSize):
					self.lizards[i].setX(self.terrainSize)
				if (self.lizards[i].getY() < 0):
					self.lizards[i].setY(0)
				elif (self.lizards[i].getY() > self.terrainSize):
					self.lizards[i].setY(self.terrainSize)
	
			#Se for femea, procura por machos
			else:
				self.lizards[i].lookAt(maleMedianPoint)
				self.lizards[i].setPos(self.lizards[i], self.lizards[i].getRelativeVector(maleMedianPoint, Vec3(0.1,-0.1,0)))
				
				#Respeitando os limites do terreno
				if (self.lizards[i].getX() < 0):
					self.lizards[i].setX(0)
				elif (self.lizards[i].getX() > self.terrainSize):
					self.lizards[i].setX(self.terrainSize)
				if (self.lizards[i].getY() < 0):
					self.lizards[i].setY(0)
				elif (self.lizards[i].getY() > self.terrainSize):
					self.lizards[i].setY(self.terrainSize)

			#Faz uma atualizacao pra saber se deve atualizar o ponto medio
			self.contChamGetMed = self.contChamGetMed + 1
			if (self.contChamGetMed == 1000):
				self.contChamGetMed = 0
				self.getMedianGenderPoints()

		return task.cont"""
				

#=====================================================================================
#A ATRIBUICAO DO BOTAO DIREITO SERA COMPLETAMENTE REFEITA, E ESTA SERVE APENAS PARA ILUSTRAR A IDEIA
#ESTA ATRIBUICAO ESTA ERRADA
#=====================================================================================
	def rightMouseCommands(self):
		if self.mouseWatcherNode.hasMouse():
			mpos = base.mouseWatcherNode.getMouse()
			if (self.clickedObj != None):
				self.moveCharacter(mpos.getX(), mpos.getY())


	#FUNCAO PROVISORIA:
	#FALTA AJUSTAR - COMO FAZER PARA OPERAR AS ENTRADAS SEPARADAMENTE?
	def moveCharacter(self, posX, posY):
		self.mClickRay.setFromLens(self.camNode, posX, posY)
		self.mClicker.traverse(self.render)
		if (self.mCollisionQue.getNumEntries() > 0):
			self.mCollisionQue.sortEntries()
			entry = self.mCollisionQue.getEntry(0)

			self.target = render.attachNewNode("target point")
			self.target.setPos(2*self.clickedObj.getX() - entry.getSurfacePoint(render).getX(), 2*self.clickedObj.getY() - entry.getSurfacePoint(render).getY(), entry.getSurfacePoint(render).getZ())
			self.finalPosY = self.target.getY()
			self.finalPosX = self.target.getX()

			finalHeading = render.attachNewNode("final heading")
			finalHeading.setPos(self.clickedObj.getPos())
			finalHeading.lookAt(self.target.getPos())
			self.Heading = finalHeading.getH()
			self.Heading = self.clampAngle(self.Heading)

			if (self.Heading-self.clickedObj.getH() > 150):
				turnTime = 4
			else:
				if (self.Heading-self.clickedObj.getH() > 100):
					turnTime = 3
				else:
					if (self.Heading-self.clickedObj.getH() > 50):
						turnTime = 2
					else:
						if (self.Heading-self.clickedObj.getH() < -50):
							turnTime = 2
						else:
							if (self.Heading-self.clickedObj.getH() < -100):
								turnTime = 3
							else:
								if (self.Heading-self.clickedObj.getH() < -150):
									turnTime = 4
								else:
									turnTime = 1
			self.deltaSX = self.target.getX()-self.clickedObj.getX()
			self.deltaSY = self.target.getY()-self.clickedObj.getY()
			self.deltaS = sqrt((self.target.getY()-self.clickedObj.getY())*(self.target.getY()-self.clickedObj.getY()) + (self.target.getX()-self.clickedObj.getX())*(self.target.getX()-self.clickedObj.getX()))
			t = self.deltaS/3
			changeHeading = self.clickedObj.hprInterval(turnTime, (self.Heading,0,0), (self.clickedObj.getH(),0,0))
			changePos = self.clickedObj.posInterval(t, self.target.getPos(), self.clickedObj.getPos())
			self.clickedObj.loop("walk", restart = 0)
			self.counter = 0
			moveInterv = Sequence(changeHeading, Func(self.stopAnimation))
			moveInterv.start()
			
	def stopAnimation(self):
		taskMgr.add(self.movingCharacter, "moving character")

	def movingCharacter(self,task):
		if self.counter < 130:
			self.clickedObj.setX(self.clickedObj.getX() - self.deltaSX/130)
			self.clickedObj.setY(self.clickedObj.getY() - self.deltaSY/130)
			self.counter = self.counter + 1
			return task.cont
		else:
			self.clickedObj.stop()
			taskMgr.remove("moving character")	


#=====================================================================================
#=====================================================================================
#=====================================================================================


	#Atribui valor a uma chave
	def setKey(self, key, value):
		self.keyMap[key] = value



	#Atualiza o game
	def updateTask(self, task):
		self.updateLizard()
		return Task.cont



	#Funcao do botao esquerdo do mouse
	def leftMouseCommands(self):
		if self.mouseWatcherNode.hasMouse():
			mpos = base.mouseWatcherNode.getMouse()

			self.mClickRay.setFromLens(self.camNode, mpos.getX(), mpos.getY())

			self.mClicker.traverse(self.render)

			if (self.mCollisionQue.getNumEntries() > 0):
				self.mCollisionQue.sortEntries()
				entry = self.mCollisionQue.getEntry(0)
				clickedObject = entry.getIntoNodePath()

				clickedObject = clickedObject.findNetTag("clickable")
				if not clickedObject.isEmpty():
					pos = entry.getSurfacePoint(self.render)
					self.getClick = 1
					clickedObjectId = clickedObject.findNetTag("ID")
					self.clickedObjId = clickedObjectId
					#Procura o lagarto clicado
					for i in range(self.numLizards):
						if (self.lizards[i].getTag("ID") == self.clickedObjId.getTag("ID")):
							self.clickedObj = self.lizards[i]
					return
				else:
					#Zera se nao houverem objetos clicaveis proximos
					self.getClick = 0




	#Define a colisao do mouse com objetos no terreno
	def setupMouseCollision(self):

		self.mClicker = CollisionTraverser()          
		self.mCollisionQue    = CollisionHandlerQueue()

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

		self.mClickNode = CollisionNode('clickRay')
		self.mClickNode.addSolid(self.mClickRay)

		self.mClickNP = self.camera.attachNewNode(self.mClickNode)

		self.mClickNode.setFromCollideMask(GeomNode.getDefaultCollideMask())

		self.mClicker.addCollider(self.mClickNP, self.mCollisionQue)



	#Atualiza o personagem se algum botao foi pressionado
	#POSTERIORMENTE SERA RETIRADA - ESTA AQUI APENAS PARA DEBUG/EXEMPLIFICACAO
	def updateLizard(self):
		speedFactor = 3

		if (self.getClick != 0):

			#Se o personagem esta se mexendo, rode a animacao
			#BUG - Se o jogador estiver pressionando o botao de andar enquanto muda de personagem, trava a animacao
			if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0) or (self.keyMap["backward"]!=0): 
				if self.isMoving is False: 
					self.clickedObj.loop("walk", restart = 0) 
					self.isMoving = True 
			else: 
				if self.isMoving: 
					self.clickedObj.stop() 
					self.isMoving = False 

			#if (self.clicked != None):
			if (self.keyMap["left"]!=0):
				self.clickedObj.setH(self.clickedObj.getH()+1)
			elif (self.keyMap["right"]!=0):
				self.clickedObj.setH(self.clickedObj.getH()-1)
			if (self.keyMap["forward"]!=0):
				self.clickedObj.setY(self.clickedObj, -speedFactor)
			elif (self.keyMap["backward"]!=0):
				self.clickedObj.setY(self.clickedObj, speedFactor)

			#Respeitando os limites do terreno
			if (self.clickedObj.getX() < 0):
				self.clickedObj.setX(0)
			elif (self.clickedObj.getX() > self.terrainSize):
				self.clickedObj.setX(self.terrainSize)
			if (self.clickedObj.getY() < 0):
				self.clickedObj.setY(0)
			elif (self.clickedObj.getY() > self.terrainSize):
				self.clickedObj.setY(self.terrainSize)
Ejemplo n.º 32
0
class GameApp:

    def __init__(self):
        self.gameEventHandler = GameEventHandler(self)
        self.camLimits = ((-5, 5), (-6.5, 5), (1, 10))
        self.gameReady = False
        self.hovered = None
        self.clicked = None
        self.modelToFigure = {}
        self.modelToField = {}
        self.modelToSeaField = {}
        self.modelToBuildingField = {}
        self.modelToBuilding = {}
        # self.highlightableObjects = render.attachNewNode('highlightables')
        self.setupColisionForHighlight()
        self.songMenu = None
        self.buildMenu = None

    def setupColisionForHighlight(self):
        # Since we are using collision detection to do picking, we set it up like
        # any other collision detection system with a traverser and a handler
        self.picker = CollisionTraverser()  # Make a traverser
        self.pq = CollisionHandlerQueue()  # Make a handler
        # Make a collision node for our picker ray
        self.pickerNode = CollisionNode('mouseRay')
        # Attach that node to the camera since the ray will need to be positioned
        # relative to it
        self.pickerNP = self.camera.attachNewNode(self.pickerNode)
        # Everything to be picked will use bit 1. This way if we were doing other
        # collision we could seperate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()  # Make our ray
        # Add it to the collision node
        self.pickerNode.addSolid(self.pickerRay)
        # Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.pq)

    def getCameraCoords(self):
        return self.camera.getPos()

    def setCameraCoords(self, x, y, z):
        self.camera.setPos(x, y, z)

    def getMouseCoords(self):
        if self.mouseWatcherNode.hasMouse():
            return self.mouseWatcherNode.getMouse()
        return None

    def drawIsland(self, island, suppressRot=False):
        island.model.setPos(island.pos[0], island.pos[1], 0.001)
        island.model.setScale(0.05, 0.05, 0.05)
        island.model.reparentTo(self.render)
        for f in range(0, 6):
            circle = self.loader.loadModel('models/circle')
            pos = (island.fields[f].x, island.fields[f].y, 0.4)
            circle.setPos(pos)
            circle.setScale(0.4)
            circle.reparentTo(island.model)
            circle.setTag('clickable', 'true')
            cs = CollisionSphere(0, 0, 0, 1)
            cnodePath = circle.attachNewNode(CollisionNode('cnode'))
            cnodePath.node().addSolid(cs)
            island.fields[f].model = circle
            self.modelToField[circle.getKey()] = island.fields[f]

        for i in range(0, 3):
            buildingField = island.buildingFields[i]
            circle = self.loader.loadModel('models/circle')
            pos = (buildingField.x, buildingField.y, 0.1)
            circle.setPos(pos)
            circle.setScale(0.6)
            circle.reparentTo(island.model)
            circle.setTag('clickable', 'true')
            cs = CollisionSphere(0, 0, 0, 1)
            cnodePath = circle.attachNewNode(CollisionNode('cnode'))
            cnodePath.node().addSolid(cs)
            buildingField.model = circle
            self.modelToBuildingField[circle.getKey()] = buildingField

        # put the bay field
        circle = self.loader.loadModel('models/circle')
        pos = (island.bay.x, island.bay.y, 0.2)
        circle.setPos(pos)
        circle.setScale(0.6)
        circle.reparentTo(island.model)
        circle.setTag('clickable', 'true')
        cs = CollisionSphere(0, 0, 0, 1)
        cnodePath = circle.attachNewNode(CollisionNode('cnode'))
        cnodePath.node().addSolid(cs)
        island.bay.model = circle
        self.modelToSeaField[circle.getKey()] = island.bay
        degree = angle((0, 1), island.pos) * 180 / math.pi
        if island.pos[0] > 0:
            degree *= -1
        if not suppressRot:
            island.model.setHpr(degree, 0, 0)

    def drawFigures(self):
        for player in self.game.players:
            for figure in player.figures:
                if hasattr(figure, 'model'):
                    continue
                if type(figure) == Ship:
                    field = figure.field
                    figure.model = self.loader.loadModel('models/ship')
                    figure.model.reparentTo(field.model)
                    cs = CollisionSphere(1.5, 0, 1, 1.3)
                    cnodePath = figure.model.attachNewNode(
                        CollisionNode('cnode'))
                    cnodePath.node().addSolid(cs)
                    # cnodePath.show()
                    cs = CollisionSphere(0, 0, 1.4, 1.3)
                    cnodePath = figure.model.attachNewNode(
                        CollisionNode('cnode'))
                    cnodePath.node().addSolid(cs)
                    # cnodePath.show()
                    cs = CollisionSphere(-1.8, 0, 1, 1)
                    cnodePath = figure.model.attachNewNode(
                        CollisionNode('cnode'))
                    cnodePath.node().addSolid(cs)
                    # cnodePath.show()
                    figure.model.setScale(1.4)
                    figure.model.setHpr(90, 0, 0)
                    # figure.model.setTag('highlightable', 'true')
                    figure.model.setTag('clickable', 'true')
                    self.modelToFigure[figure.model.getKey()] = figure
                else:
                    field = figure.field
                    figure.model = self.loader.loadModel('models/warrior100')
                    figure.model.reparentTo(field.model)
                    cs = CollisionSphere(0, -.35, 7, 1)
                    cnodePath = figure.model.attachNewNode(
                        CollisionNode('cnode'))
                    cnodePath.node().addSolid(cs)
                    figure.model.setScale(0.35)
                    figure.model.setTag('highlightable', 'true')
                    figure.model.setTag('clickable', 'true')
                    self.modelToFigure[figure.model.getKey()] = figure

                col = 256 * int(player.color)
                # set figure title
                title = TextNode(str(figure.model.getKey()) + '_title')
                title.setText(type(figure).__name__)
                title.setCardColor(col, col, col, 1)
                title.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
                title.setCardDecal(True)
                titleNode = self.render.attachNewNode(title)
                titleNode.reparentTo(figure.model)
                titleNode.setScale(3)
                titleNode.setPos(0, 3, 10)
                if type(figure) == Ship:
                    titleNode.setScale(1.5)
                    titleNode.setPos(-1.5, 0, 3)
                titleNode.setBillboardPointEye()

    def drawSeaways(self):
        for field in self.game.board.seawayFields:
            circle = self.loader.loadModel('models/circle')
            pos = (field.x, field.y, 0)
            circle.setPos(pos)
            circle.setScale(0.04)
            circle.setHpr(-90, 0, 0)
            circle.reparentTo(self.render)
            circle.setTag('clickable', 'true')
            cs = CollisionSphere(0, 0, 0, 1)
            cnodePath = circle.attachNewNode(CollisionNode('cnode'))
            cnodePath.node().addSolid(cs)
            field.model = circle
            self.modelToSeaField[circle.getKey()] = field

    def drawBuilding(self, building, field):
        model = self.loader.loadModel('models/house')
        # model.setScale(0.05)
        model.reparentTo(field.model)
        building.model = model
        self.modelToBuilding[model.getKey()] = building
        player = self.game.currentPlayer()
        model.setTag('clickable', 'true')
        cs = CollisionSphere(0, 0, 0, 2)
        cnodePath = model.attachNewNode(CollisionNode('cnode'))
        cnodePath.node().addSolid(cs)
        # cnodePath.show()

        col = 256 * int(player.color)
        # set building title
        title = TextNode(str(building.model.getKey()) + '_title')
        title.setText(building.building)
        title.setCardColor(col, col, col, 1)
        title.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
        title.setCardDecal(True)
        titleNode = self.render.attachNewNode(title)
        titleNode.reparentTo(building.model)
        titleNode.setScale(1.5)
        titleNode.setPos(0, 0, 3)
        titleNode.setBillboardPointEye()

    def drawGame(self, game):
        if not self.gameReady:
            self.game = game
            # menu = OnscreenImage(image = 'textures/menu.png', pos = (1.53, 0, 0), scale=(0.35, 1, 1))
            # menu.setTransparency(TransparencyAttrib.MAlpha)

            # setup the background of the board
            self.environ = self.loader.loadModel('models/plane')
            sea = self.loader.loadTexture('textures/sea.png')
            self.environ.setTexture(sea)
            self.environ.setPos(0, 1, 0)
            self.environ.setScale(1.1)
            sea.setWrapU(Texture.WM_repeat)
            sea.setWrapV(Texture.WM_repeat)
            self.environ.reparentTo(self.render)

            # setup camera
            self.camera.setPos(0, 0, 10)
            self.camera.setHpr(0, -70, 0)
            self.camLens.setNear(0.85)

            # setup lighting
            plight = PointLight('plight')
            plight.setColor(VBase4(1, 1, 1, 3))
            plnp = self.render.attachNewNode(plight)
            plnp.setPos(10, 0, 10)
            self.render.setLight(plnp)
            ambientLight = AmbientLight('ambientLight')
            ambientLight.setColor(Vec4(0.25, 0.25, 0.25, .3))
            ambientLightNP = self.render.attachNewNode(ambientLight)
            self.render.setLight(ambientLightNP)

            # place islands
            first = True
            for island in game.board.islands:
                island.drawable = True
                island.model = self.loader.loadModel('models/island2_104')
                self.drawIsland(island, first)
                first = False

            self.drawFigures()
            self.drawSeaways()

            self.turn = OnscreenText(text='Black\'s turn.',
                                     pos=(0.06, -0.1),
                                     align=TextNode.ALeft,
                                     parent=base.a2dTopLeft,
                                     scale=0.06)
            self.resources = OnscreenText(text='Resources: ',
                                          pos=(0.08, -0.2),
                                          align=TextNode.ALeft,
                                          parent=base.a2dTopLeft,
                                          scale=0.06)
            self.gameReady = True

        player = 'Black'
        if game.turn == 1:
            player = 'White'
        self.turn.setText(player + '\'s turn.')
        resourcesText = 'Resources: ' + \
            str(self.game.currentPlayer().resources)
        self.resources.setText(resourcesText)
        if self.game.loosers != None:
            message = OnscreenText(text='End of the game',
                                   align=TextNode.ACenter,
                                   pos=(0, 0),
                                   scale=0.1)
            if self.game.loosers == 'black':
                message.setText('White wins!')
            elif self.game.loosers == 'white':
                message.setText('Black wins!')
            else:
                message.setText('Nobody wins!')

    def destroyGame(self):
        children = self.render.getChildren()
        for child in children:
            child.removeNode()

    def cameraSpeed(self, height, speedRange):
        # Figure out how 'wide' each range is
        leftSpan = self.camLimits[2][1] - self.camLimits[2][0]
        rightSpan = speedRange[1] - speedRange[0]

        # Convert the left range into a 0-1 range (float)
        valueScaled = float(height - self.camLimits[2][0]) / float(leftSpan)

        # Convert the 0-1 range into a value in the right range.
        return speedRange[0] + (valueScaled * rightSpan)

    def moveCamera(self):
        mousePos = self.getMouseCoords()
        if mousePos == None:
            return
        x, y = mousePos
        camX, camY, camZ = self.getCameraCoords()
        transformX, transformY = 0, 0
        speed = self.cameraSpeed(camZ, (0.01, 0.2))
        if x < -0.7 and y < -0.7:
            transformX -= speed
            transformY -= speed
        elif x > 0.7 and y < -0.7:
            transformX += speed
            transformY -= speed
        elif x < -0.7 and y > 0.7:
            transformX -= speed
            transformY += speed
        elif x > 0.7 and y > 0.7:
            transformX += speed
            transformY += speed
        else:
            if x < -0.7:
                transformX -= speed
            elif x > 0.7:
                transformX += speed
            if y < -0.7:
                transformY -= speed
            elif y > 0.7:
                transformY += speed
        newX = camX + transformX
        newY = camY + transformY
        if newX < self.camLimits[0][0] or newX > self.camLimits[0][1]:
            newX = camX
        if newY < self.camLimits[1][0] or newY > self.camLimits[1][1]:
            newY = camY
        self.setCameraCoords(newX, newY, camZ)

    def highlight(self):
        if self.mouseWatcherNode.hasMouse():
            mPos = self.mouseWatcherNode.getMouse()

            # Set the position of the ray based on the mouse position
            self.pickerRay.setFromLens(self.camNode, mPos.getX(), mPos.getY())

            self.picker.traverse(self.render)
            if self.pq.getNumEntries() > 0:
                # This is so we get the closest object.
                self.pq.sortEntries()
                pickedObj = self.pq.getEntry(0).getIntoNodePath()
                # pick the model and not the cnode
                pickedObj = pickedObj.findNetTag('clickable')
                if not pickedObj.isEmpty():
                    return pickedObj

    @staticmethod
    def boardingTransformations(figure, pos):
        figure.model.setScale(0.2)
        figure.model.setPos(1 + pos, 0, 1)

    @staticmethod
    def unboardingTransformations(figure):
        figure.model.setScale(0.35)
        figure.model.setPos(0, 0, 0)

    def drawSongsMenu(self, songs, field):
        if self.songMenu:
            return
        self.songMenu = [(OnscreenText(text='Choose song:',
                                       pos=(-0.7, -0.1),
                                       align=TextNode.ALeft,
                                       parent=base.a2dTopRight,
                                       scale=0.06), field)]
        i = 1
        for song in songs:
            item = OnscreenText(text=str(i) + ') Song of ' + song,
                                pos=(-0.7, -0.1 - i * 0.1),
                                align=TextNode.ALeft,
                                parent=base.a2dTopRight,
                                scale=0.06)
            i += 1
            self.songMenu.append((item, song))

    def destroySongMenu(self):
        if self.songMenu:
            for item in self.songMenu:
                item[0].destroy()
            self.songMenu = None

    def drawBuildMenu(self, buildings, field):
        self.buildMenu = [(OnscreenText(text='Choose building:',
                                        pos=(-0.7, -0.1),
                                        align=TextNode.ALeft,
                                        parent=base.a2dTopRight,
                                        scale=0.06), field)]
        i = 1
        for building in buildings:
            price = Building.buildingPrice(building)
            text = '{0}) {1} ({2})'.format(str(i), building, price)
            item = OnscreenText(text=text,
                                pos=(-0.7, -0.1 - i * 0.1),
                                align=TextNode.ALeft,
                                parent=base.a2dTopRight,
                                scale=0.06)
            i += 1
            self.buildMenu.append((item, building))

    def destroyBuildMenu(self):
        if self.buildMenu:
            for item in self.buildMenu:
                item[0].destroy()
            self.buildMenu = None

    def clickFigure(self, figure):
        print('figure')
        if type(figure) == Ship:
            ship = figure
            figure = self.clicked
            if isinstance(figure, Figure) and type(figure) != Ship:
                if figure.hasMoved:
                    self.clicked = ship
                    return
                if (figure.field.island == ship.field.island and
                        figure.player == ship.player and
                        None in ship.fields):
                    figure.field.put(None)
                    pos = 0
                    if ship.fields[0] == None:
                        ship.fields[0] = figure
                    else:
                        ship.fields[1] = figure
                        pos = 1
                    figure.field = ship
                    figure.model.reparentTo(ship.model)
                    self.boardingTransformations(figure, pos)
                    figure.hasMoved = True
            if ship.player == self.game.currentPlayer():
                self.clicked = ship
        else:
            if figure.player == self.game.currentPlayer():
                self.clicked = figure

    def initiateBattle(self, blackTroops, whiteTroops):
        self.blackTroops = blackTroops
        self.whiteTroops = whiteTroops
        battle = self.game.newBattle()
        self.push(battle)
        self.gameEventHandler.ignoreAll()

    def clickField(self, field):
        print(self.clicked)
        if type(self.clicked) == Ship:
            return
        if self.clicked and isinstance(self.clicked, Figure):
            figure = self.clicked
            board = self.game.board
            if figure.hasMoved:
                return
            if type(figure.field) == Ship:
                if field in board.possibleMoves(figure.field):
                    figure.field.removeFigure(figure)
                    player = self.game.currentPlayer()
                    battle = field.figure != None and field.figure.player != player
                    whiteTroops = field.figure
                    field.put(figure)
                    figure.model.reparentTo(field.model)
                    self.unboardingTransformations(figure)
                    figure.hasMoved = True
                    self.initiateBattle(figure, whiteTroops)
            if field in board.possibleMoves(self.clicked):
                initiateBattle = field.figure != None
                whiteTroops = field.figure
                figure.field.put(None)
                field.put(figure)
                figure.model.reparentTo(field.model)
                figure.hasMoved = True
                if initiateBattle:
                    self.initiateBattle(figure, whiteTroops)
        if isinstance(self.clicked, Building):
            building = self.clicked
            player = self.game.currentPlayer()
            if not field.figure or field.figure.player != player:
                if field.island != building.field.island:
                    return
                figure = None
                battle = field.figure != None and field.figure.player != player
                whiteTroops = field.figure
                if building.building == 'House':
                    figure = self.game.giveBirthToPeasant(field)
                elif building.building == 'Barracks':
                    figure = self.game.giveBirthToWarrior(field)
                if figure == None:
                    return
                if figure:
                    self.drawFigures()
                if battle:
                    self.initiateBattle(figure, whiteTroops)
                else:
                    print('Not enough resources!')

    def clickSeaField(self, field):
        if type(self.clicked) == Ship:
            figure = self.clicked
            if figure.hasMoved:
                return
            if field.figure != None:
                return
            if field in figure.field.linked:
                figure.field.put(None)
                field.put(figure)
                figure.model.reparentTo(field.model)
                figure.hasMoved = True
        if type(self.clicked) == Building:
            player = self.game.currentPlayer()
            building = self.clicked
            if building.building == 'Harbor':
                if building.field.island.bay != field:
                    return

                player = self.game.currentPlayer()
                if not field.figure or field.figure.player != player:
                    ship = self.game.buildShip(field)
                    if ship:
                        self.drawFigures()
                    else:
                        print('Not enough resources')

    def clickBuildingField(self, field):
        print("Gonna build, huh?")
        player = self.game.currentPlayer()
        print(self.game.possibleBuildings(field.island))
        self.drawSongsMenu(self.game.possibleSongs(field.island), field)

    def handle(self, event, *args):
        print(event)
        if type(self.current()) != Game:
            return
        if event == 'wheel_up':
            x, y, z = self.getCameraCoords()
            if z > self.camLimits[2][0]:
                self.setCameraCoords(x, y, z - 1)
        elif event == 'wheel_down':
            x, y, z = self.getCameraCoords()
            if z < self.camLimits[2][1]:
                self.setCameraCoords(x, y, z + 1)
        elif event == 'enter':
            if self.game.loosers != None:
                self.pop()
            self.game.changeTurn()
        elif event == 'left_click':
            obj = self.highlight()
            if obj != None:
                key = obj.getKey()
                # if it's a figure
                if key in self.modelToFigure:
                    figure = self.modelToFigure[key]
                    self.clickFigure(figure)
                # if it's a figure field
                if key in self.modelToField:
                    field = self.modelToField[key]
                    self.clickField(field)
                # if it's a building field
                if key in self.modelToBuildingField:
                    field = self.modelToBuildingField[key]
                    self.clickBuildingField(field)
                # if it's a sea field
                if key in self.modelToSeaField:
                    field = self.modelToSeaField[key]
                    self.clickSeaField(field)
                # if it's a building
                if key in self.modelToBuilding:
                    self.clicked = self.modelToBuilding[key]
            else:
                self.clicked = None
            if self.songMenu != None:
                if obj == None or obj.getKey() not in self.modelToBuildingField:
                    self.destroySongMenu()
        elif event in [str(i) for i in range(1, 10)]:
            if self.songMenu:
                if self.songMenu[0][1] != self.game.board.islands[0]:
                    song = self.songMenu[int(event)][1]
                    buildings = self.game.buildings[song]
                    self.drawBuildMenu(buildings, self.songMenu[0][1])
                else:
                    print('CHANGE OBJECTIVES!')
                self.destroySongMenu()
                return
            if self.buildMenu:
                building = self.buildMenu[int(event)][1]
                field = self.buildMenu[0][1]
                building = self.game.build(building, field)
                if building:
                    self.drawBuilding(building, field)
                else:
                    print('Not enough resources or field is taken!!>@')
                self.destroyBuildMenu()

    def hoverFigure(self, hovered):
        if self.hovered != None:
            reverseFactor = self.hovered.getScale()[0]
            reverseFactor *= REVERSE_HIGHLIGHT_SCALE
            self.hovered.setScale(reverseFactor)
        self.hovered = None
        if hovered != None:
            figure = self.modelToFigure[hovered.getKey()]
            if figure.player.color != str(self.current().turn):
                return
            self.hovered = hovered
            factor = HIGHLIGHT_SCALE * hovered.getScale()[0]
            hovered.setScale(factor)
Ejemplo n.º 33
0
class DistributedLevel(DistributedObject):
    """ An instance of these is created and placed in the middle of
    the zone.  It serves to illustrate the creation of AI-side objects
    to populate the world, and a general mechanism for making them
    react to the avatars. """
    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        #self.model = loader.loadModel('environment')
        #self.model.setZ(0)
        #self.builder = Builder(self, "map.txt", "development")

        plane = CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, 0)))
        cnode = CollisionNode('cnode')
        cnode.setIntoCollideMask(BitMask32.bit(1))
        cnode.setFromCollideMask(BitMask32.bit(1))
        cnode.addSolid(plane)
        self.planeNP = self.model.attachNewNode(cnode)
        self.planeNP.show()

        # Setup a traverser for the picking collisions
        self.picker = CollisionTraverser()
        # Setup mouse ray
        self.pq = CollisionHandlerQueue()
        # Create a collision Node
        pickerNode = CollisionNode('MouseRay')
        # set the nodes collision bitmask
        pickerNode.setFromCollideMask(BitMask32.bit(1))
        # create a collision ray
        self.pickerRay = CollisionRay()
        # add the ray as a solid to the picker node
        pickerNode.addSolid(self.pickerRay)
        # create a nodepath with the camera to the picker node
        self.pickerNP = base.camera.attachNewNode(pickerNode)
        # add the nodepath to the base traverser
        self.picker.addCollider(self.pickerNP, self.pq)

        print "model loaded"
        #TODO: check how to load multiple levels and set players in specific levels!
        self.accept("mouse1", self.mouseClick)

    def announceGenerate(self):
        """ This method is called after generate(), after all of the
        required fields have been filled in.  At the time of this call,
        the distributed object is ready for use. """
        DistributedObject.announceGenerate(self)

        # Now that the object has been fully manifested, we can parent
        # it into the scene.
        print "render the model"
        self.model.reparentTo(render)

    def disable(self):
        # Take it out of the scene graph.
        self.detachNode()

        DistributedObject.disable(self)

    def checkMousePos(self, mpos, camPos, camHpr):
        lens = LenseNode.copyLens(base.camNode)
        lens.setPos(camPos)
        lens.setHpr(camHpr)
        help(mpos)
        mpos = Point2(mpos.x, mpos.y)
        pos = self.getClickPosition(mpos, lens)
        print "mouse clicked at:", pos

    def mouseClick(self):
        """Send an event to the server that will check where the mouse
        will hit and what action needs to be done"""
        hitPos = (0, 0, 0)
        # check if we have a mouse on the window
        if base.mouseWatcherNode.hasMouse():
            # get the mouse position on the screen
            mpos = base.mouseWatcherNode.getMouse()
            print mpos
            # set the ray's position
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            # Now call the traverse function to let the traverser check for collisions
            # with the added colliders and the levelNP
            self.picker.traverse(self.planeNP)
            # check if we have a collision
            if self.pq.getNumEntries() > 0:
                # sort the entries to get the closest first
                self.pq.sortEntries()
                # This is the point at where the mouse ray and the level plane intersect
                hitPos = self.pq.getEntry(0).getSurfacePoint(render)
        base.messenger.send("clickPosition", [hitPos])
Ejemplo n.º 34
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        #Background sound (does not play infinitely)
        self.backgroundSound = base.loader.loadSfx("sounds/DireDireDocks.mp3")

        taskMgr.add(self.update, "moveTask")
        
        #Disable the mouse so that we may use it for our control scheme.
        self.props = WindowProperties()
        self.props.setSize(1920, 1080)
        self.props.setFullscreen(True)
        self.props.setCursorHidden(True)
        base.win.requestProperties(self.props)
        base.disableMouse()
        
        self.buildKeyMap()
        self.inMenu = True
        self.menuScreen = OnscreenImage("titlescreen.png", (0, .01, 0))
        self.menu()

    def initialize(self):
        self.timer = 0
        base.enableParticles()
        #base.setFrameRateMeter(True)

        ##########
        #
        # SETUP COLLISION HANDLERS AND FLAMIE'S MODEL
        #
        ##########
        
        #Create the collision handlers in order to build the level.
        WALL_MASK = BitMask32.bit(2)
        FLOOR_MASK = BitMask32.bit(1)
        
        #Start up the collision system
        self.cTrav = CollisionTraverser()

        #Determine how collisions with walls will be handled
        self.wallHandler = CollisionHandlerPusher()
        self.bobbing = False

        #Setup flamie's model
        self.flamieNP = base.render.attachNewNode(ActorNode('flamieNP'))
        self.flamieNP.reparentTo(base.render)
        self.flamie = loader.loadModel('models/Flame/body')
        self.flamie.setScale(.5)
        self.flamie.setTransparency(TransparencyAttrib.MAlpha)
        self.flamie.setAlphaScale(0)
        self.flamie.reparentTo(self.flamieNP)
        self.flamie.setCollideMask(BitMask32.allOff())
        flameLight = DirectionalLight("flameLight")
        fl = self.flamie.attachNewNode(flameLight)
        fl.setColor(255, 255, 255, 1)
        flameLight.setDirection((-5, -5, -5))
        self.flamie.setLight(fl)


        self.flamie2 = loader.loadModel("models/p.obj")
        self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f7.png"))
        self.flamie2.reparentTo(self.flamieNP)
        self.flamie2.setScale(4)
        self.flamie2OriZ = 2
        self.flamie2.setPos(-6.5, 0, self.flamie2OriZ) #(length, depth, height)
        self.flamie2.setLight(fl)
        self.flamie2.setTransparency(TransparencyAttrib.MAlpha)
        self.flamieFire = PointLight('fire')
        self.flamieFire.setColor(VBase4(1,1,1,1))
        self.flamieFire.setAttenuation((1,0,1))
        plnp = render.attachNewNode(self.flamieFire)
        plnp.setPos(self.flamieNP.getPos())
        self.flamielight = AmbientLight('light')
        self.flamielight.setColor(VBase4(1, 0.5, 0.6, 1))

        self.flamielight = self.flamie2.attachNewNode(self.flamielight)
        self.flamie2.setLight(self.flamielight)
        self.flamie2.setLight(plnp)
        self.mayFlamieBob = True

        #self.flamie2.setAlphaScale(0.5)

        '''self.tree = loader.loadModel("models/p2.obj")
        self.tree.setTexture(loader.loadTexture("deadTree.png"))
        self.tree.reparentTo(render)
        self.tree.setScale(4)
        self.tree.setPos(25,25,0) #(length, depth, height)
        self.tree.setLight(fl)
        self.tree.setTransparency(TransparencyAttrib.MAlpha)
        self.treelight = AmbientLight('light')
        self.treelight.setColor(VBase4(0.9, 0.9, 0.6, 1))
        self.treelight = self.tree.attachNewNode(self.treelight)
        self.tree.setLight(self.treelight)'''

        x = 150
        y = 20
        offset1 = 0
        treeList2 = [loader.loadModel("models/p2.obj") for i in range(7)]
        for j in treeList2:
            k = random.randint(1, 100)
            if k%5 is 1 or k%5 is 2:
                j.setTexture(loader.loadTexture("deadTree.png"))
            else:
                j.setTexture(loader.loadTexture("tree.png"))
            j.reparentTo(render)
            j.setScale(random.randint(4,7))
            j.setTransparency(TransparencyAttrib.MAlpha)
            j.setPos(x + 3*offset1, y + 4*offset1, 0)
            treelight = AmbientLight('light')
            treelight = j.attachNewNode(treelight)
            j.setLight(treelight)
            offset1 = offset1 + random.randint(4, 10)

        x = 4
        y = 90
        offset1 = 0
        treeList2 = [loader.loadModel("models/p2.obj") for i in range(6)]
        for j in treeList2:
            k = random.randint(1, 100)
            if k%5 is 1 or k%5 is 2:
                j.setTexture(loader.loadTexture("deadTree.png"))
            else:
                j.setTexture(loader.loadTexture("tree.png"))
            j.reparentTo(render)
            j.setScale(random.randint(4,7))
            j.setTransparency(TransparencyAttrib.MAlpha)
            j.setPos(x + 3*offset1, y + 4*offset1, 0)
            treelight = AmbientLight('light')
            treelight = j.attachNewNode(treelight)
            j.setLight(treelight)
            offset1 = offset1 + random.randint(4, 10)

        x = 3
        y = 120
        offset1 = 0
        treeList2 = [loader.loadModel("models/p2.obj") for i in range(4)]
        for j in treeList2:
            k = random.randint(1, 100)
            if k%5 is 1 or k%5 is 2:
                j.setTexture(loader.loadTexture("deadTree.png"))
            else:
                j.setTexture(loader.loadTexture("tree.png"))
            j.reparentTo(render)
            j.setScale(random.randint(4,7))
            j.setTransparency(TransparencyAttrib.MAlpha)
            j.setPos(x + 3*offset1, y + 4*offset1, 0)
            treelight = AmbientLight('light')
            treelight = j.attachNewNode(treelight)
            j.setLight(treelight)
            offset1 = offset1 + random.randint(4, 10)

        x = 200
        y = 20
        offset1 = 0
        treeList2 = [loader.loadModel("models/p2.obj") for i in range(4)]
        for j in treeList2:
            k = random.randint(1, 100)
            if k%5 is 1 or k%5 is 2:
                j.setTexture(loader.loadTexture("deadTree.png"))
            else:
                j.setTexture(loader.loadTexture("tree.png"))
            j.reparentTo(render)
            j.setScale(random.randint(4,7))
            j.setTransparency(TransparencyAttrib.MAlpha)
            j.setPos(x + 3*offset1, y + 4*offset1, 0)
            treelight = AmbientLight('light')
            treelight = j.attachNewNode(treelight)
            j.setLight(treelight)
            offset1 = offset1 + random.randint(4, 10)

        ### Something that should look like water ###
        w = loader.loadModel("models/flatP.obj")
        w.setTexture(loader.loadTexture("ice.png"))
        w.reparentTo(render)
        w.setScale(75)
        w.setTransparency(TransparencyAttrib.MAlpha)
        w.setAlphaScale(.7)
        w.setLight(treelight)
        w.setPos(-200, 0, -10)

        self.waterOrigiZ = -10
        self.waterSecZ = -95
        self.waterThirdZ = -120
        self.water = w

        ### Reskying the sky ###
        w = loader.loadModel("models/biggerFlatP.obj")
        w.setTexture(loader.loadTexture("models/n2.jpg"))
        w.reparentTo(self.flamie2)
        w.setScale(15)
        w.setLight(treelight)
        w.setPos(-200, 450, -200) #(length, depth, height)

        #Give flamie gravity
        self.floorHandler = CollisionHandlerGravity()
        self.floorHandler.setGravity(9.81+100)
        self.floorHandler.setMaxVelocity(100)
        

        ##########
        #
        # GENERATING LEVEL PARTS
        #
        ##########
        self.ice_reset = ()
        self.start = PlatformSeg(LVector3(0,0,0))
        self.start.generateAllParts(render)
        self.checkpointCreator(70, 90, self.start.pos.z, 10)
        self.floater = False
        
        for p in self.start.parts:
            if isinstance(p, Prism):
                self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, p.dep, 'terraincollision', 'wallcollision')
            if isinstance(p, Square):
                self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, 3,  'terraincollision', 'wallcollision')
            if isinstance(p, IceCube):
                p.model.setCollideMask(BitMask32.allOff())
                self.ice_reset += (p,)
                iceCubefloor= p.model.find("**/iceFloor")
                iceCubewall = p.model.find("**/iceWall")
                iceCubefloor.node().setIntoCollideMask(FLOOR_MASK)
                iceCubewall.node().setIntoCollideMask(WALL_MASK)

        
        self.lostWood = LostWood(LVector3(self.start.pos.x + 750, self.start.parts[0].pos.y + self.start.parts[0].wid, self.start.pos.z))
        self.lostWood.generateAllParts(render)
        self.checkpointCreator(self.lostWood.pos.x+120, self.lostWood.pos.y+150, self.lostWood.pos.z,20)
        self.checkpointCreator(self.lostWood.parts[6].pos.x + self.lostWood.parts[6].len/2, self.lostWood.parts[6].pos.y + self.lostWood.parts[6].wid/2, self.lostWood.pos.z, 40)
        
        for p in self.lostWood.parts:
            if isinstance(p, Prism):
                self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, p.dep, 'terraincollision', 'wallcollision')
            if isinstance(p, Square):
                self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, 3,  'terraincollision', 'wallcollision')
            if isinstance(p, IceCube):
                p.model.setCollideMask(BitMask32.allOff())
                self.ice_reset += (p,)
                iceCubefloor= p.model.find("**/iceFloor")
                iceCubewall = p.model.find("**/iceWall")
                iceCubefloor.node().setIntoCollideMask(FLOOR_MASK)
                iceCubewall.node().setIntoCollideMask(WALL_MASK)
            
        self.cave = Cave(LVector3(self.lostWood.pos.x + 1100, self.lostWood.pos.y + 2000, self.lostWood.pos.z - 50))
        self.cave.generateAllParts(render)
        self.checkpointCreator(self.cave.thirdRoomParts[5].pos.x + self.cave.thirdRoomParts[5].len/2,
                               self.cave.thirdRoomParts[5].pos.y + self.cave.thirdRoomParts[5].wid/2,
                               self.cave.thirdRoomParts[5].pos.z, 30)
        
        for p in self.cave.parts:
            if isinstance(p, Prism):
                self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, p.dep, 'terraincollision', 'wallcollision')
            if isinstance(p, Square):
                self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, 3,  'terraincollision', 'wallcollision')
            if isinstance(p, IceCube):
                p.model.setCollideMask(BitMask32.allOff())
                self.ice_reset += (p,)
                iceCubefloor= p.model.find("**/iceFloor")
                iceCubewall = p.model.find("**/iceWall")
                iceCubefloor.node().setIntoCollideMask(FLOOR_MASK)
                iceCubewall.node().setIntoCollideMask(WALL_MASK)

        self.end = End(LVector3(self.cave.thirdRoomParts[8].pos.x - 200,
                       self.cave.thirdRoomParts[8].pos.y + self.cave.thirdRoomParts[8].wid,
                       self.cave.thirdRoomParts[8].pos.z))
        self.end.generate(render)
        self.collisionBoxCreator(self.end.floor.pos.x, self.end.floor.pos.y, self.end.floor.pos.z,
                                 self.end.floor.len, self.end.floor.wid, self.end.floor.dep,
                                 'terraincollision', 'wallcollision')
        #########
        # DRAWING THE CABIN AND FINAL CAMPFIRE
        #########
        self.checkpointCreator(self.end.floor.pos.x + self.end.floor.len/2,
                               self.end.floor.pos.y + self.end.floor.wid/2,
                               self.end.floor.pos.z, 30)
        self.cabin = loader.loadModel("models/p2.obj")
        self.cabin.setTexture(loader.loadTexture("models/cabin.png"))
        self.cabin.setScale(50)
        self.cabin.reparentTo(render)
        self.cabin.setPos(self.end.floor.pos.x + self.end.floor.len/2,
                          self.end.floor.pos.y + self.end.floor.wid/1.1,
                          self.end.floor.pos.z)
        self.cabin.setTransparency(TransparencyAttrib.MAlpha)
        

        #Manually creating starting position. Copy and paste the first three parameters of the checkpoint you want to start at.
        self.startPos = LVector3(70, 90, self.start.pos.z)
        self.flamieNP.setPos(self.startPos)


        '''#Testing the tree model
        self.tree = loader.loadModel('models/Tree/log')
        self.tree.reparentTo(render)
        self.tree.setPos(-50,0,100)
        self.tree.setScale(2)'''

        '''#Add sky background
        self.sky = loader.loadModel('models/sphere.obj')
        self.sky.reparentTo(self.camera)
        self.sky.set_two_sided(True)
        self.skyTexture = loader.loadTexture("models/n2.jpg")
        self.sky.setTexture(self.skyTexture)
        self.sky.set_bin('background', 0)
        self.sky.set_depth_write(False)
        self.sky.set_compass()'''

        ##########
        #
        # CREATE FLAMIE'S COLLISION GEOMETRY
        #
        ##########
        
        #Give flamie a collision sphere in order to collide with walls
        flamieCollider = self.flamie.attachNewNode(CollisionNode('flamiecnode'))
        flamieCollider.node().addSolid(CollisionSphere(0,0,0,5))
        flamieCollider.node().setFromCollideMask(WALL_MASK)
        flamieCollider.node().setIntoCollideMask(BitMask32.allOff())
        self.wallHandler.addCollider(flamieCollider, self.flamieNP)
        self.cTrav.addCollider(flamieCollider, self.wallHandler)

        #Give flamie a collision ray to collide with the floor
        flamieRay = self.flamie.attachNewNode(CollisionNode('flamieRay'))
        flamieRay.node().addSolid(CollisionRay(0,0,8,0,0,-1))
        flamieRay.node().setFromCollideMask(FLOOR_MASK)
        flamieRay.node().setIntoCollideMask(BitMask32.allOff())
        self.floorHandler.addCollider(flamieRay, self.flamieNP)
        self.cTrav.addCollider(flamieRay, self.floorHandler)

        #Add a sensor that lets us melt ice cubes without standing on the cube.
        meltSensor = self.flamie.attachNewNode(CollisionNode('meltSensor'))
        cs = CollisionSphere(-2,0,10, 50)
        meltSensor.node().addSolid(cs)
        meltSensor.node().setFromCollideMask(WALL_MASK)
        meltSensor.node().setIntoCollideMask(BitMask32.allOff())
        cs.setTangible(0)
        self.wallHandler.addCollider(meltSensor, self.flamieNP)
        self.cTrav.addCollider(meltSensor, self.wallHandler)
        self.wallHandler.addInPattern('%fn-into-%in')
        self.wallHandler.addAgainPattern('%fn-again-%in')
        self.accept('meltSensor-into-iceWall', self.melt)
        self.accept('meltSensor-again-iceWall', self.melt)
        self.accept('meltSensor-into-checkpointCol', self.newstart)
        
        #Add in an event handle to prevent the jumping glitch found on the bobbing ice cubes.
        self.floorHandler.addInPattern('%fn-into-%in')
        self.floorHandler.addAgainPattern('%fn-again-%in')
        self.floorHandler.addOutPattern('%fn-out-%in')
        self.accept('flamieRay-into-iceFloor', self.jittercancel)
        self.accept('flamieRay-again-iceFloor', self.jittercancel)
        self.accept('flamieRay-out-iceFloor', self.jittercanceloff)

        
        #Uncomment these lines to see flamie's collision geometry
        #flamieCollider.show()
        #flamieRay.show()
        #meltSensor.show()

        #Uncomment this line to see the actual collisions.
        #self.cTrav.showCollisions(render)
        
        #This plane is found at the very bottom of the level and adds global gravity.
        killfloor = CollisionPlane(Plane(Vec3(0,0,1), Point3(0,0,-1000)))
        killfloorCol = CollisionNode('kfcollision')
        killfloorCol.addSolid(killfloor)
        killfloorCol.setIntoCollideMask(BitMask32.bit(1))
        killfloorColNp = self.render.attachNewNode(killfloorCol)

        ####################
        #
        #   Setting light so that we could see the definition in the walls
        #
        ####################
        
        render.setShaderAuto()
        self.dlight = DirectionalLight('dlight')
        self.dlight.setColor(LVector4(0.3, 0.1, 0.7, 1))
        dlnp = render.attachNewNode(self.dlight)
        dlnp.setHpr(90, 20, 0)
        render.setLight(dlnp)

        self.alight = render.attachNewNode(AmbientLight("Ambient"))
        self.alight.node().setColor(LVector4(0.5, 0.5, 1, .1))
        render.setLight(self.alight)

        self.snow = loader.loadTexture("models/ground.jpg")

        #Create a floater object and have it float 2 units above fireball.
        #And use this as a target for the camera to focus on.
        #This idea is taken from the roaming ralph sample that came with the
        #Panda3D SDK.
        self.camFocus = NodePath(PandaNode("floater"))
        self.camFocus.reparentTo(render)
        self.camFocusCurrZ = self.flamie.getZ() + 10

        #The camera is locked to the avatar so it always follows regardless of movement.
        self.camera.reparentTo(render)
        self.cameraTargetHeight = 8.0
        self.cameraDistance = 100
        self.cameraHeightModes = (self.start.parts[0].pos.z + 45, self.start.parts[0].pos.z + 125, self.camFocus.getZ() + 10, self.camFocus.getZ() + 150,
                                  self.end.floor.pos.z + 10)
        self.cameraHeight = self.cameraHeightModes[0]

        
    #################
    #   Changes Camera orientation depending on where the player is in the stage to compensate for the fact that
    #   the player has no direct control of the camera.
    #   Checks using the arrays from the level parts.
    ##################
    def cameraModes(self, delta):
        #Is the fireball within the platforming section between the starting area and the lost woods?
        #Is the fireball near the simple platforming sections of the LostWoods?
        #Is the fireball near the drop off point into the cave?
        #Is the fireball near the entrance to the second room in the cave?
        #If yes to any of these, bring the camera up to give a bird's eye view of the platforming
        if ((self.flamieNP.getX() > self.start.parts[1].pos.x and self.flamieNP.getY() > self.start.parts[1].pos.y - self.start.parts[1].wid
            and self.flamieNP.getX() < self.lostWood.parts[0].pos.x)
            or (self.flamieNP.getX() > self.lostWood.parts[0].pos.x + self.lostWood.parts[0].len/1.1
                and self.flamieNP.getX() < self.lostWood.parts[2].pos.x + self.lostWood.parts[0].len/11
                and self.flamieNP.getY() < self.lostWood.parts[0].pos.y + self.lostWood.parts[0].wid)
            or (self.flamieNP.getY() > self.cave.parts[0].pos.y - 20 and self.flamieNP.getY() <= self.cave.parts[0].pos.y + self.cave.parts[0].wid/2)
            or (self.flamieNP.getX() < self.cave.parts[1].pos.x + self.cave.parts[1].wid/10 and self.flamieNP.getY() >= self.cave.parts[1].pos.x)):
                camMode = 1
        #Is the fireball in the beginning of the cave area?
        #If yes, bring the camera closer
        elif self.flamieNP.getY() > self.cave.parts[1].pos.y - self.cave.parts[0].wid/2 and self.flamieNP.getY() < self.cave.thirdRoomParts[5].pos.y:
            camMode = 2
        else:
            camMode = 0

        if self.flamieNP.getY() >= self.cave.thirdRoomParts[6].pos.y:
            self.cave.thirdRoomParts[0].hide()
            camMode = 3
        if self.flamieNP.getY() >= self.cave.thirdRoomParts[8].pos.y + self.cave.thirdRoomParts[8].wid/1.5:
            camMode = 4

        self.lerpCam(camMode, delta)

    def lerpCam(self, camMode, delta):
        CAMLERPSPEED = 25
        if camMode == 0:
            if not self.cameraHeight == self.cameraHeightModes[camMode]:
                if self.cameraHeight - CAMLERPSPEED * delta <= self.cameraHeightModes[camMode]:
                    self.cameraHeight = self.cameraHeightModes[camMode]
                else:
                    self.cameraHeight = self.cameraHeight - CAMLERPSPEED * delta
        elif camMode == 1:
            if not self.cameraHeight == self.cameraHeightModes[camMode]:
                if self.cameraHeight - CAMLERPSPEED * delta >= self.cameraHeightModes[camMode]:
                    self.cameraHeight = self.cameraHeightModes[camMode]
                else:
                    if self.cameraHeight < self.cameraHeightModes[camMode]:
                        self.cameraHeight = self.cameraHeight + CAMLERPSPEED * delta
                    else:
                        self.cameraHeight = self.cameraHeight - CAMLERPSPEED * delta
        elif camMode == 2:
            if not self.cameraHeight == self.cameraHeightModes[camMode]:
                if self.cameraHeight - CAMLERPSPEED * delta <= self.cameraHeightModes[camMode]:
                    self.cameraHeight = self.cameraHeightModes[camMode]
                    self.camFocusCurrZ = self.flamieNP.getZ() + 10
                else:
                    self.cameraHeight = self.cameraHeight - CAMLERPSPEED * delta
                    self.camFocusCurrZ = self.flamieNP.getZ() + 10
        elif camMode == 3:
            if not self.cameraHeight == self.cameraHeightModes[camMode]:
                if self.cameraHeight + CAMLERPSPEED * 3 * delta >= self.cameraHeightModes[camMode]:
                    self.cameraHeight = self.cameraHeightModes[camMode]
                else:
                    self.cameraHeight = self.cameraHeight + CAMLERPSPEED * 3 * delta
        elif camMode == 4:
            if not self.cameraHeight == self.cameraHeightModes[camMode]:
                if self.cameraHeight - CAMLERPSPEED * 3 * delta <= self.cameraHeightModes[camMode]:
                    self.cameraHeight = self.cameraHeightModes[camMode]
                else:
                    self.cameraHeight = self.cameraHeight - CAMLERPSPEED * 3 * delta

    def waterControl(self, delta):
        WATERLERPSPEED = .75
        if self.flamieNP.getY() <= self.lostWood.parts[6].pos.y + self.lostWood.parts[6].wid/2:
            if not self.water.getZ() == self.waterOrigiZ:
                if self.water.getZ() - WATERLERPSPEED * delta < self.waterOrigiZ and self.water.getZ() > self.waterOrigiZ:
                    self.water.setZ(self.waterOrigiZ)
                elif self.water.getZ() + WATERLERPSPEED * delta > self.waterOrigiZ and self.water.getZ() < self.waterOrigiZ:
                    self.water.setZ(self.waterOrigiZ)
                else:
                    if self.water.getZ() > self.waterOrigiZ:
                        self.water.setZ(self.water, - WATERLERPSPEED * delta)
                        if self.water.getZ() < self.waterOrigiZ:
                            self.water.setZ(self.waterOrigiZ)
                    else:
                        self.water.setZ(self.water, + WATERLERPSPEED * delta)
                        if self.water.getZ() > self.waterOrigiZ:
                            self.water.setZ(self.waterOrigiZ)
        elif self.flamieNP.getY() <= self.cave.parts[1].pos.y:
            if not self.water.getZ() == self.waterSecZ:
                if self.water.getZ() - WATERLERPSPEED * delta < self.waterSecZ:
                    self.water.setZ(self.waterSecZ)
                else:
                    self.water.setZ(self.water, - WATERLERPSPEED * delta)
        else:
            if not self.water.getZ() == self.waterThirdZ:
                if self.water.getZ() - WATERLERPSPEED * delta < self.waterThirdZ:
                    self.water.setZ(self.waterThirdZ)
                else:
                    self.water.setZ(self.water, - WATERLERPSPEED * delta)
        
        
    def reset(self):
        self.flamieNP.setPos(self.startPos)
        self.camFocusCurrZ = self.flamieNP.getZ() + 10
        for p in self.ice_reset:
            p.model.setScale(p.original_scale)
        
    def jump(self, dt):
        if self.bobbing:
            if self.floorHandler.getAirborneHeight() < 0.15:
                self.floorHandler.addVelocity(60) 
        elif self.floorHandler.isOnGround():
            self.floorHandler.addVelocity(60)

    def jittercancel(self, collEntry):
        model = collEntry.getIntoNodePath().getParent()
        modelRef = model.getPythonTag("iceRef")
        if model.getScale()[0] > 1.2:
            model.setScale(model.getScale()- modelRef.meltspeed)

        self.bobbing = True

    def jittercanceloff(self, collEntry):
        self.bobbing = False

    def melt(self, collEntry):
        model = collEntry.getIntoNodePath().getParent()
        modelRef = model.getPythonTag("iceRef")
        if model.getScale()[0] > 1.2 and self.bobbing != True:
            model.setScale(model.getScale()- modelRef.meltspeed)

    def newstart(self, collEntry):
        entry = collEntry.getInto().getCenter()
        self.startPos = (entry[0]+10, entry[1]+10, entry[2] +10)
        cp = loader.loadModel('models/Campfire/fire')
        cp.setPos(entry[0],entry[1], entry[2])
        cp.reparentTo(render)
            
    def buildKeyMap(self):
        self.keyMap = {"left": 0, "right": 0, "forward": 0, "back": 0, "down": 0, "up": 0, "lookUp": 0, "lookDown": 0, "lookLeft": 0, "lookRight": 0}

        #I changed the control scheme let me know if you would like me to try something else.
        #WASD for movement, space for jump
        self.accept("escape", sys.exit)
        self.accept("a", self.setKey, ["left", True])
        self.accept("a-up", self.setKey, ["left", False])
        self.accept("d", self.setKey, ["right", True])
        self.accept("d-up", self.setKey, ["right", False])
        self.accept("w", self.setKey, ["forward", True])
        self.accept("w-up", self.setKey, ["forward", False])
        self.accept("s", self.setKey, ["back", True])
        self.accept("s-up", self.setKey, ["back", False])
        self.accept("space", self.setKey, ["down", True])
        self.accept("space-up", self.setKey, ["down", False])
        self.accept("shift", self.setKey, ["up", True])
        self.accept("shift-up", self.setKey, ["up", False])

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

    def update(self, task):
        delta = globalClock.getDt()
        if not self.inMenu:
            SPEED = 125
            #Variable that holds what direction the player is inputting
            fblr = 0
            self.timer += delta * 25

            self.killPlane = self.water.getZ() - 25
            if self.flamieNP.getZ() < self.killPlane:
                self.reset()
                
            if self.keyMap["left"]:
                fblr = 1
                old_fblr = fblr
                self.flamieNP.setX(self.flamie, - SPEED * delta)
            if self.keyMap["right"]:
                fblr = 2
                old_fblr = fblr
                self.flamieNP.setX(self.flamie, + SPEED * delta)
            if self.keyMap["forward"]:
                fblr = 3
                old_fblr = fblr
                self.flamieNP.setY(self.flamie, + SPEED * delta)
            if self.keyMap["back"]:
                fblr = 4
                old_fblr = fblr
                self.flamieNP.setY(self.flamie, - SPEED * delta)
            if self.keyMap["up"]:
                #self.flamieNP.setZ(self.flamie, - SPEED * dt)
                self.reset()
                #self.cameraDistance = 20+self.cameraDistance
            if self.keyMap["down"] and self.timer > 1:
                #self.flamieNP.setZ(self.flamie, + SPEED * dt)
                self.timer = 0
                self.jump(delta)
                
            if fblr == 1:
                self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f8.png"))
            elif fblr == 2:
                self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f6.png"))
            elif fblr == 3:
                if old_fblr == 1:
                    self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f1.png"))
                elif old_fblr == 2:
                    self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f4.png"))
                else:
                    self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f3.png"))
            else:
                self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f7.png"))

            if self.floorHandler.isOnGround:
                self.flamieBob(delta)

            #The camera control is borrowed from Kristina's Tech Demo
            #This is also a demo found at: http://www.panda3d.org/forums/viewtopic.php?t=8452

            '''# mouse-controlled camera begins

            # Use mouse input to turn both the Character and the Camera
            if base.mouseWatcherNode.hasMouse():
                md = base.win.getPointer(0)
                x = md.getX()
                y = md.getY()
                deltaX = md.getX() - 200
                deltaY = md.getY() - 200
                # reset mouse cursor position
                base.win.movePointer(0, 200, 200)
                # alter flamie's yaw by an amount proportionate to deltaX
                self.flamie.setH(self.flamie.getH() - 0.3* deltaX)
                # find the new camera pitch and clamp it to a reasonable range
                self.cameraPitch = self.cameraPitch + 0.1 * deltaY
                if (self.cameraPitch < -60): self.cameraPitch = -60
                if (self.cameraPitch >  80): self.cameraPitch =  80
                base.camera.setHpr(0,self.cameraPitch,0)
                # set the camera at around ralph's middle
                # We should pivot around here instead of the view target which is noticebly higher
                base.camera.setPos(0,0,self.cameraTargetHeight/2)
                # back the camera out to its proper distance
                base.camera.setY(base.camera,self.cameraDistance)

            # point the camera at the view target
            viewTarget = Point3(0,0,self.cameraTargetHeight)
            base.camera.lookAt(viewTarget)
            # reposition the end of the  camera's obstruction ray trace
            #self.cameraRay.setPointB(base.camera.getPos())

            # mouse-controlled camera ends'''

            self.waterControl(delta)
            self.water.setX(self.flamieNP.getX() - 250)
            self.water.setY(self.flamieNP.getY() - 250)
            self.cameraModes(delta)
            base.camera.setPos(self.flamieNP.getX(), self.flamieNP.getY() - self.cameraDistance, self.cameraHeight)
            self.camFocus.setPos(self.flamieNP.getX(), self.flamieNP.getY(), self.camFocusCurrZ)
            base.camera.lookAt(self.camFocus)


            '''
            ######################
            #
            # SIMPLE OCCLUSION FOR START AREA
            #
            ######################

            for p in self.start.parts:
                if p.type == 'IceCube':
                    if math.fabs((math.sqrt((p.model.getX() * p.model.getX()) + (p.model.getY() * p.model.getY()))
                    - math.sqrt((self.camFocus.getX() * self.camFocus.getX()) + (self.camFocus.getY() * self.camFocus.getY())))) <= 400:
                        p.show()
                        #Ice cube movement
                        p.bob(delta)
                    else:
                        p.hide()
                    
                if p.type == 'Prism':
                    if p.type == 'Prism':
                        if math.fabs((math.sqrt((p.pos.x * p.pos.x) + (p.pos.y * p.pos.y))
                        - math.sqrt((self.camFocus.getX() * self.camFocus.getX()) + (self.camFocus.getY() * self.camFocus.getY())))) <= 1000:
                            p.show()
                        else:
                            p.hide()


            ######################
            #
            # SIMPLE OCCLUSION FOR CAVE PARTS
            #
            ######################
            for p in self.cave.parts:
                if p.type == 'Prism':
                    if math.fabs((math.sqrt((p.pos.x * p.pos.x) + (p.pos.y * p.pos.y))
                    - math.sqrt((self.flamieNP.getX() * self.flamieNP.getX()) + (self.flamieNP.getY() * self.flamieNP.getY())))) <= 2500:
                        p.show()
                    else:
                        p.hide()
                    
                if p.type == 'IceCube':
                    if math.fabs((math.sqrt((p.model.getX() * p.model.getX()) + (p.model.getY() * p.model.getY()))
                    - math.sqrt((self.flamieNP.getX() * self.flamieNP.getX()) + (self.flamieNP.getY() * self.flamieNP.getY())))) <= 2000:
                        p.show()

                        #Ice cube movement
                        self.cave.moveIceCubes(delta/25)
                        for p in self.cave.iceCubesThirdRoom:
                            p.bob(delta/25)
                        for p in self.cave.iceCubesSecondRoom:
                            p.bob(delta/25)
                        self.cave.bigCube.bob(delta/25)

                        for p in self.start.iceCubes:
                            p.bob(delta)
                    else:
                        p.hide()
            '''

            #Ice cube movement
            self.cave.moveIceCubes(delta)
            for p in self.cave.iceCubesThirdRoom:
                p.bob(delta)
            for p in self.cave.iceCubesSecondRoom:
                p.bob(delta)
            self.cave.bigCube.bob(delta)

            for p in self.start.iceCubes:
                p.bob(delta)

        elif self.inMenu:
            self.menu()


            

        if self.backgroundSound.status() is not self.backgroundSound.PLAYING:
            self.backgroundSound.play()

            
        return task.cont

    def menu(self):
        if self.keyMap["down"]:
            self.inMenu = False
            self.menuScreen.destroy()
            self.initialize()
            

    def flamieBob(self, delta):
        if self.mayFlamieBob:
            self.flamie2.setZ(self.flamie2.getZ() + .5*delta)
            if self.flamie2.getZ() - self.flamie2OriZ > 1:
                self.mayFlamieBob = False
        else:
            self.flamie2.setZ(self.flamie2.getZ() - .5*delta)
            if self.flamie2.getZ() - self.flamie2OriZ < -2:
                self.mayFlamieBob = True
        
    #Function to create a box collision using six polygon. The top face is created as terrain and thus provides gravity.
    #While the rest of the faces only act as wall pushers.
    def collisionBoxCreator(self, posx, posy, posz, length, width, height, floorname, wallname):
        ret = ()
        #Create top face
        terrain = CollisionPolygon(Point3(posx, posy+width, posz), Point3(posx, posy, posz),
                                Point3(posx+length, posy, posz), Point3(posx+length, posy+width, posz))
        terrainCol = CollisionNode(floorname)
        terrainCol.addSolid(terrain)
        terrainCol.setIntoCollideMask(BitMask32.bit(1))
        terrainColNp = self.render.attachNewNode(terrainCol)
        self.cTrav.addCollider(terrainColNp, self.floorHandler)
        ret += (terrainColNp,)
    
        #Create left face
        sideLeft = CollisionPolygon(Point3(posx, posy+width, posz-height), Point3(posx, posy, posz-height),
                                Point3(posx, posy, posz), Point3(posx, posy+width, posz))
        sideLeftCol = CollisionNode(wallname)
        sideLeftCol.addSolid(sideLeft)
        sideLeftCol.setIntoCollideMask(BitMask32.bit(2))
        sideLeftColNp = self.render.attachNewNode(sideLeftCol)
        self.cTrav.addCollider(sideLeftColNp, self.wallHandler)
        ret += (sideLeftColNp,)
        
        #Create right face
        sideRight = CollisionPolygon(Point3(posx+length, posy+width, posz), Point3(posx+length, posy, posz),
                                Point3(posx+length, posy, posz-height), Point3(posx+length, posy+width, posz-height))
        sideRightCol = CollisionNode(wallname)
        sideRightCol.addSolid(sideRight)
        sideRightCol.setIntoCollideMask(BitMask32.bit(2))
        sideRightColNp = self.render.attachNewNode(sideRightCol)
        self.cTrav.addCollider(sideRightColNp, self.wallHandler)
        ret += (sideRightColNp,)
        
        #Create front face
        sideFront = CollisionPolygon(Point3(posx, posy+width, posz-height), Point3(posx, posy+width, posz),
                                Point3(posx+length, posy+width, posz), Point3(posx+length, posy+width, posz-height))
        sideFrontCol = CollisionNode(wallname)
        sideFrontCol.addSolid(sideFront)
        sideFrontCol.setIntoCollideMask(BitMask32.bit(2))
        sideFrontColNp = self.render.attachNewNode(sideFrontCol)
        self.cTrav.addCollider(sideFrontColNp, self.wallHandler)
        ret += (sideFrontColNp,)
        
        #Create back face
        sideBack = CollisionPolygon(Point3(posx, posy, posz), Point3(posx, posy, posz-height),
                                Point3(posx+length, posy, posz-height), Point3(posx+length, posy, posz))
        sideBackCol = CollisionNode(wallname)
        sideBackCol.addSolid(sideBack)
        sideBackCol.setIntoCollideMask(BitMask32.bit(2))
        sideBackColNp = self.render.attachNewNode(sideBackCol)
        self.cTrav.addCollider(sideBackColNp, self.wallHandler)
        ret += (sideBackColNp,)

        #Create bottom face
        sideBot = CollisionPolygon(Point3(posx, posy, posz-height), Point3(posx, posy+width, posz-height),
                                Point3(posx+length, posy+width, posz-height), Point3(posx+length, posy, posz-height))
        sideBotCol = CollisionNode(wallname)
        sideBotCol.addSolid(sideBot)
        sideBotCol.setIntoCollideMask(BitMask32.bit(2))
        sideBotColNp = self.render.attachNewNode(sideBotCol)
        self.cTrav.addCollider(sideBotColNp, self.wallHandler)
        ret += (sideBotColNp,)

        #Uncomment these lines to see the collision polygons.
        '''terrainColNp.show()
        sideLeftColNp.show()
        sideRightColNp.show()
        sideFrontColNp.show()
        sideBackColNp.show()
        sideBotColNp.show()'''

        return ret
        #Old way of creating box collisions (left here for reference)
        '''box = CollisionBox((posx+(length/2), posy+(width/2),-(posz+height/2)), length/2, width/2, height/2)
        boxCol = CollisionNode('testcollision')
        boxCol.addSolid(box)
        boxCol.setIntoCollideMask(BitMask32.bit(2))
        boxColNp = self.render.attachNewNode(boxCol)
        boxHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(boxColNp, self.wallHandler)

        #Uncomment this line to see the collision solids.
        #boxColNp.show()'''

    def checkpointCreator(self, posx, posy, posz, radius):
        cp = loader.loadModel('models/Campfire/logs')
        cp.setPos(posx,posy, posz)
        cp.reparentTo(render)
        checkpoint = CollisionSphere(cp.getX(),cp.getY(),cp.getZ(),radius)
        checkpoint.setTangible(0)
        checkpointCol = CollisionNode('checkpointCol')
        checkpointCol.addSolid(checkpoint)
        checkpointCol.setIntoCollideMask(BitMask32.bit(2))
        checkpointColNp = self.render.attachNewNode(checkpointCol)
        self.cTrav.addCollider(checkpointColNp, self.wallHandler)
Ejemplo n.º 35
0
class Grabber(object):
    def __init__( self, levitNP):
        """ A widget to position, rotate, and scale Panda 3D Models and Actors
            * handleM1 decides what to do with a mouse1 click
            -- object selection by calling handleSelection when the grabModel is inactive (hidden)
            -- object manipulation by calling handleManipulationSetup (sets the stage for and launches the dragTask)

            isHidden() when nothing is selected
            isDragging means not running collision checks for selection setup and LMB is pressed

            call handleM1 from another class to push control up
            in the program hierarchy (remove inner class calls)
        """
        # TODO remove selection functionality from grabber and put it in a selector class
        self.levitorNP = levitNP  # TODO remove this and use barebonesNP
        self.selected = None
        self.initialize()

    def initialize(self):
        """Reset everything except LevitorNP and selected, also called inside __init__"""
        self.notify = DirectNotify().newCategory('grabberErr')
        self.currPlaneColNorm = Vec3(0.0)
        self.isCameraControlOn = False
        self.isDragging = False
        self.isMultiselect = False
        self.grabScaleFactor = .075
        self.currTransformDir = Point3(0.0)
        self.interFrameMousePosition = Point3(0.0)
        self.init3DemVal = Point3(0.0)
        # initCommVal holds the value before a command operation has taken place
        self.initialCommandTrgVal = None
        # To load the grabber model, this climbs up the absolute path to /barebones/ to gain access to the model folder
        self.grabModelNP = loader.loadModel(Filename.fromOsSpecific(
                                            ntpath.split( ntpath.split(inspect.stack()[0][1])[0] )[0])
                                            + '/EditorModels/widget')
        self.grabModelNP.setPos(0.0, 0.0, 0.0)
        self.grabModelNP.setBin("fixed", 40)
        self.grabModelNP.setDepthTest(False)
        self.grabModelNP.setDepthWrite(False)
        self.transformOpEnum = Enum('rot, scale, trans')
        self.currTransformOperation = None
        # TODO For readability, use this enum in the nested if/else as was the original intent.
        self.grabInd = Enum('xRot, yRot, zRot, xScaler, yScaler, zScaler, xTrans, yTrans, zTrans, xyTrans, xzTrans, zyTrans, grabCore')
        grbrNodLst = [self.grabModelNP.find("**/XRotator;+h-s-i"),       # 0
                       self.grabModelNP.find("**/YRotator;+h-s-i"),      # 1
                       self.grabModelNP.find("**/ZRotator;+h-s-i"),      # 2 end rotate
                       self.grabModelNP.find("**/XScaler;+h-s-i"),       # 3
                       self.grabModelNP.find("**/YScaler;+h-s-i"),       # 4
                       self.grabModelNP.find("**/ZScaler;+h-s-i"),       # 5 end scale
                       self.grabModelNP.find("**/XTranslator;+h-s-i"),   # 6
                       self.grabModelNP.find("**/YTranslator;+h-s-i"),   # 7
                       self.grabModelNP.find("**/ZTranslator;+h-s-i"),   # 8 end translate / end single dir operations
                       self.grabModelNP.find("**/XYTranslator;+h-s-i"),  # 9
                       self.grabModelNP.find("**/XZTranslator;+h-s-i"),  # 10
                       self.grabModelNP.find("**/ZYTranslator;+h-s-i"),  # 11 end bi-directional operations
                       self.grabModelNP.find("**/WidgetCore;+h-s-i")]    # 12
        #Mat4.yToZUpMat()  # change coordinate to z up
        grbrNodLst[12].getParent().setHprScale(0, 0, 0, 1, 1, -1)
        self.grabModelNP.setPythonTag('grabberRoot', grbrNodLst)
        self.grabModelNP.reparentTo(BBGlobalVars.bareBonesObj.levitorNP)
        self.grabModelNP.hide()
        #self.grabIntoBitMask = COLLISIONMASKS
        self.grabModelNP.setCollideMask(COLLISIONMASKS['default'])
        self.grabModelNP.setPythonTag('grabber', self)

        ##############################################################################
        # This whole section is the basics for setting up mouse selection
        # --The mouse events are added in the events section (next)

        # Create the collision node for the picker ray to add traverser as a 'from' collider
        self.grabberColNode = CollisionNode('grabberMouseRay')
        # Set the collision bitmask
        # TODO: define collision bitmask (let user define thiers? likely not)
        self.defaultBitMask = GeomNode.getDefaultCollideMask()
        self.grabberColNode.setFromCollideMask(self.defaultBitMask)
        self.grabberRayColNP = camera.attachNewNode(self.grabberColNode)
        # Create the grabberRay and add it to the picker CollisionNode
        self.grabberRay = CollisionRay(0.0, 0.0, 0.0,
                                       0.0, 1.0, 0.0)
        self.grabberRayNP = self.grabberColNode.addSolid(self.grabberRay)
        # create a collision queue for the traverser
        self.colHandlerQueue = CollisionHandlerQueue()
        # Create collision traverser
        self.colTraverser = CollisionTraverser('grabberTraverser')
        # Set the collision traverser's 'fromObj' and handler
        # e.g. trav.addCollider( fromObj, handler )
        self.colTraverser.addCollider(self.grabberRayColNP, self.colHandlerQueue)


        ############################################################
        # setup event handling with the messenger
        # URGENT remove all of this messenger code throughout Grabber, especially the camera control
        # disable the mouse when the ~ is pressed (w/o shift)
        self.disableCamera()                            # disable camera control by the mouse
        messenger.accept('`', self, self.enableCamera)  # enable camera control when the ~ key is pressed w/o shift
        messenger.accept('`-up', self, self.disableCamera)  # disable camera control when the ~ key is released

        # handle mouse selection/deselection & manipulating the scene
        messenger.accept('mouse1', self, self.handleM1, persistent=1)  # deselect in event handler

        taskMgr.add(self.scaleGrabber, 'scaleGrabber')
        # ////////////////////////////////////////////////////////////////////
        # comment out: good for debug info
        #taskMgr.add(self.watchMouseColl, name='grabberDebug')
        #this is only good for seeing types and hierarchy
        #self.grabModelNP.ls()
        #render.ls()
        # self.frames = 0  #remove
        # self.axis = loader.loadModel("zup-axis")
        # self.axis.reparentTo(self.grabModelNP)
        # self.axis.setScale(.15)
        # self.axis.setPos(0.0)
        # self.grabModelNP.append( 'newAttrib', self)
        # setattr( self.grabModelNP, 'newAttrib', self)


    def prepareForPickle(self):
        self.colTraverser = None     # Traversers are not picklable
        self.defaultBitMask = None   # BitMasks "..."
        # self.grabIntoBitMask = None  # "..."
        self.colHandlerQueue = None  # CollisonHandlerQueue "..."
        self.grabModelNP.removeNode()
        self.grabModelNP = None
        taskMgr.remove('scaleGrabber')


    def recoverFromPickle(self):
        self.initialize()
        if self.selected is not None:
            self.grabModelNP.setPos(render, self.selected.getPos(render))
            self.grabModelNP.show()
        print "grabber sel ", self.selected, " isHidden() ", self.grabModelNP.isHidden(), '\n'
        taskMgr.add(self.scaleGrabber, 'scaleGrabber')

    #### May use to gain control over pickling.
    # def __repr__(self): # for pickling purposes
    #     if self.colTraverser:
    #         self.colTraverser = None
    #
    #     dictrepr = dict.__repr__(self.__dict__)
    #     dictrepr = '%r(%r)' % (type(self).__name__, dictrepr)
    #     print dictrepr  # REMOVE
    #     return dictrepr


    def watchMouseColl(self, task):
        """ This exists for debugging purposes to perpetually watch mouse collisions.
        """
        # TODO make this highlight objects under the mouse for predictable object selection/grabber operations
        self.colTraverser.showCollisions(render)
        if base.mouseWatcherNode.hasMouse() and False == self.isCameraControlOn:
            # This gives the screen coordinates of the mouse.
            mPos = base.mouseWatcherNode.getMouse()
            # This makes the ray's origin the camera and makes the ray point
            # to the screen coordinates of the mouse.
            self.grabberRay.setFromLens(base.camNode, mPos.getX(), mPos.getY())
            # traverses the graph for collisions
            self.colTraverser.traverse(render)
        return task.cont


    def scaleGrabber(self, task):
        if self.grabModelNP.isHidden():
            return task.cont
        coreLst = self.grabModelNP.getPythonTag('grabberRoot')
        camPos = self.grabModelNP.getRelativePoint(self.grabModelNP, camera.getPos())

        if camPos.z >= 0:        # 1-4
            if camPos.x > 0.0 <= camPos.y:    # quad 1
                coreLst[12].getParent().setScale( 1, 1, -1)

            elif camPos.x < 0.0 <= camPos.y:  # quad 2
                coreLst[12].getParent().setScale( -1, 1, -1)

            elif camPos.x < 0.0 >= camPos.y:  # quad 3
                coreLst[12].getParent().setScale( -1, -1, -1)

            elif camPos.x > 0.0 >= camPos.y:  # quad 4
                coreLst[12].getParent().setScale( 1, -1, -1)

            else:
                self.notify.warning("if-else default, scaleGrabber cam.z > 0")

        else:      # 5-8
            if camPos.x > 0.0 <= camPos.y:    # quad 5
                coreLst[12].getParent().setScale( 1, 1, 1)

            elif camPos.x < 0.0 <= camPos.y:  # quad 6
                coreLst[12].getParent().setScale( -1, 1, 1)

            elif camPos.x < 0.0 >= camPos.y:  # quad 7
                coreLst[12].getParent().setScale( -1, -1, 1)

            elif camPos.x > 0.0 >= camPos.y:  # quad 8
                coreLst[12].getParent().setScale( 1, -1, 1)

            else:
                self.notify.warning("if-else default, scaleGrabber cam.z z < 0")


        distToCam = (camera.getPos() - render.getRelativePoint(BBGlobalVars.currCoordSysNP, self.grabModelNP.getPos())).length()
        self.grabModelNP.setScale(self.grabScaleFactor * distToCam,
                                  self.grabScaleFactor * distToCam,
                                  self.grabScaleFactor * distToCam)
        # keep the position identical to the selection
        # for when outside objects like undo/redo move selected
        self.grabModelNP.setPos(render, self.selected.getPos(render))
        return task.cont

    # TODO find a way to move camera control to a proper camera handler, perhaps move these to a global
    def enableCamera(self):
        self.isCameraControlOn = True
        PanditorEnableMouseFunc()

    def disableCamera(self):
        self.isCameraControlOn = False
        PanditorDisableMouseFunc()


    def handleM3(self):
        """Deselect the selected object."""
        if not self.grabModelNP.isHidden() and not self.isCameraControlOn:
            # if the grab model is in the scene and the camera is not in control
            if base.mouseWatcherNode.hasMouse() and not self.isDragging:
                # we're ignoring accidental mouse3 clicks while dragging here with not isDragging
                self.selected = None              # empty the selected, will be turned back on once something's selected
                messenger.ignore('mouse3', self)  # turn the deselect event off
                self.grabModelNP.hide()           # hide the grab model and set it back to render's pos
                self.grabModelNP.setPos(0.0)


    def handleM1Up(self):
        """Stop dragging the selected object."""
        taskMgr.remove('mouse1Dragging')
        self.isDragging = False
        self.currTransformOperation = None  # NOTE other references have been added, but no other object references them
        # record the mouse1 operation
        BBGlobalVars.undoHandler.record(self.selected, CommandUndo([self.initialCommandTrgVal],
                                                                    self.selected.setMat, self.selected.getMat(render)))
        messenger.ignore('mouse1-up', self)


    def handleM1(self):
        """Decides how to handle a mouse1 click."""
        if self.isCameraControlOn:
            return

        if base.mouseWatcherNode.hasMouse():
            # give the grabber first chance
            if self.grabModelNP.isHidden():
                # no collisions w/ grabber or nothing selected
                # handle selection with scene objects
                self.handleSelection()

            elif not self.isDragging:
                # The grabber is in place but not dragging. Get ready to drag.
                self.handleManipulationSetup()  # it'll call self.handleSelection() if no collision w/ grabber
                # TODO (if warranted) make self.handleManipulationSetup() return false if no col w/ grabber, call selection here instead


    def handleManipulationSetup(self):
        """Sets up all the attributes needed for the mouse dragging task."""
        # This makes the ray's origin the camera and makes the ray point
        # to the screen coordinates of the mouse.
        if self.isDragging:
            return
        camVec = self.grabModelNP.getRelativeVector(self.grabModelNP, camera.getPos())
        mPos = base.mouseWatcherNode.getMouse()
        self.grabberRay.setFromLens(base.camNode, mPos.getX(), mPos.getY())
        self.colTraverser.traverse(self.grabModelNP)  # look for collisions on the grabber

        if not self.isCameraControlOn and self.colHandlerQueue.getNumEntries() > 0 and not self.grabModelNP.isHidden():
            # see if collided with the grabber if not handle re or multi selection
            self.colHandlerQueue.sortEntries()
            grabberObj = self.colHandlerQueue.getEntry(0).getIntoNodePath()
            grabberLst = self.grabModelNP.getPythonTag('grabberRoot')  # see __init__

            # the index gives the operations rot < 3 scale < 6 trans < 9 trans2D < 12
            # mod index gives axis 0 == x, 1 == y, 2 == z
            ind = -1
            for i in range(0, 13):
                if grabberObj == grabberLst[i]:
                    ind = i
                    grabberObj = grabberLst[i]
            # ensure we are not picking ourselves, ahem, the grabber
            assert(not self.grabModelNP.isAncestorOf(self.selected))
            mPos3D = Point3(0.0)
            xVec = Vec3(1, 0, 0)
            yVec = Vec3(0, 1, 0)
            zVec = Vec3(0, 0, 1)
            # TODO: ??? break this up into translate rotate and scale function to make it readable
            if -1 < ind < 3:             # rotate
                if ind % 3 == 0:    # x
                    self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.rot,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))
                elif ind % 3 == 1:  # y
                    self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.rot,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))
                else:               # z
                    self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.rot,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))

            elif ind < 6:                 # scale
                if ind % 3 == 0:    # x
                    self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.scale,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))
                elif ind % 3 == 1:  # y
                    # self.currTransformDir = Point3( 0.0, 1.0, 0.0)
                    self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.scale,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))
                else:               # z
                    # self.currTransformDir = Point3( 0.0, 0.0, 1.0)
                    self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.scale,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))

            elif ind < 9:                 # translate
                if ind % 3 == 0:    # x
                    # if the camera's too flat to the collision plane bad things happen
                    if camVec.angleDeg( zVec) < 89.0 and self.getMousePlaneIntersect(mPos3D, zVec):
                        self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.trans, mPos3D, zVec)

                    elif self.getMousePlaneIntersect(mPos3D, yVec):
                        self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.trans, mPos3D, yVec)

                elif ind % 3 == 1:  # y
                    if camVec.angleDeg( zVec) < 89.0 and self.getMousePlaneIntersect(mPos3D, zVec):
                        self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.trans, mPos3D, zVec)

                    elif self.getMousePlaneIntersect(mPos3D, xVec):
                        self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.trans, mPos3D, xVec)

                else:               # z
                    if camVec.angleDeg( yVec) < 89.0 and self.getMousePlaneIntersect(mPos3D, yVec):
                        self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.trans, mPos3D, yVec)

                    elif self.getMousePlaneIntersect(mPos3D, xVec):
                        self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.trans, mPos3D, xVec)

            elif ind < 12:            # translate 2D
                if ind % 3 == 0:    # xy
                    if self.getMousePlaneIntersect(mPos3D, zVec):
                        self.initializeManipVars(Point3(1.0, 1.0, 0.0), self.transformOpEnum.trans, mPos3D, zVec)

                elif ind % 3 == 1:  # xz
                    if self.getMousePlaneIntersect(mPos3D, yVec):
                        self.initializeManipVars(Point3(1.0, 0.0, 1.0), self.transformOpEnum.trans, mPos3D, yVec)
                else:               # zy
                    if self.getMousePlaneIntersect(mPos3D, xVec):
                        self.initializeManipVars(Point3(0.0, 1.0, 1.0), self.transformOpEnum.trans, mPos3D, xVec)

            elif ind == 12:  # scale in three directions
                self.initializeManipVars(Point3(1.0, 1.0, 1.0), self.transformOpEnum.scale,
                                         Point3(mPos.getX(), mPos.getY(), 0.0))

            else:
                self.notify.warning("Grabber Err: no grabber collision when col entries > 0 AND grabber not hidden")

            # Save initial value for save/undo.
            # The end result of the operation is sent to the undo handler on mouse up event.
            if self.selected:
                self.initialCommandTrgVal = self.selected.getMat(render)
        else:
            # no collisions w/ grabber or nothing selected
            # handle reselection or multi-selection (not yet implemented) with other scene obj
            self.handleSelection()


    def handleSelection(self):
        if self.isDragging:
            return

        # First check that the mouse is not outside the screen.
        if base.mouseWatcherNode.hasMouse() and False == self.isCameraControlOn:

            self.grabberColNode.setFromCollideMask(self.defaultBitMask)
            # This gives the screen coordinates of the mouse.
            mPos = base.mouseWatcherNode.getMouse()

            # This makes the ray's origin the camera and makes the ray point
            # to the screen coordinates of the mouse.
            self.colHandlerQueue.clearEntries()
            self.grabberRay.setFromLens(base.camNode, mPos.getX(), mPos.getY())
            self.colTraverser.traverse(render)  # look for collisions

            if self.colHandlerQueue.getNumEntries() > 0:
                self.colHandlerQueue.sortEntries()
                grabbedObj = self.colHandlerQueue.getEntry(0).getIntoNodePath()
                if not grabbedObj.findNetTag('pickable').isEmpty():
                    grabbedObj = grabbedObj.findNetTag('pickable')
                    self.selected = grabbedObj
                    self.grabModelNP.setPos(render,
                                            grabbedObj.getPos(render).x,
                                            grabbedObj.getPos(render).y,
                                            grabbedObj.getPos(render).z)
                    self.grabModelNP.show()
                    messenger.accept('mouse3', self, self.handleM3)

    def handleDragging(self, task):
        """ Does the actual work of manipulating objects,
            once the needed attributes have been setup by handleManipulationSetup().
        """

        if not self.isDragging:
            return task.done
        mPos3D = Point3(0.0)
        #
        # This section handles the actual translating rotating or scale after it's been set up in mouse1SetupManip...()
        # ONLY one operation is preformed per frame
        if self.currTransformOperation == self.transformOpEnum.trans:
            # 1st translation, rotation's section is at next elif
            if self.getMousePlaneIntersect(mPos3D, self.currPlaneColNorm):

                # get the difference between the last mouse and this frames mouse
                selectedNewPos = mPos3D - self.interFrameMousePosition
                # store this frames mouse
                self.interFrameMousePosition = mPos3D
                # add the difference to the selected object's pos
                self.selected.setPos(render, self.selected.getPos(render).x + self.currTransformDir.x * selectedNewPos.x,
                                             self.selected.getPos(render).y + self.currTransformDir.y * selectedNewPos.y,
                                             self.selected.getPos(render).z + self.currTransformDir.z * selectedNewPos.z)

                self.grabModelNP.setPos(render, self.selected.getPos(render))

        elif self.currTransformOperation == self.transformOpEnum.rot:
            # 2nd rotation, followed finally by scaling
            # if operating on the z-axis, use the y (vertical screen coordinates otherwise use x (horizontal)
            mPos = base.mouseWatcherNode.getMouse()
            #rotMag = 0.0
            if self.currTransformDir == Vec3( 0.0, 0.0, 1.0):
                rotMag = (mPos.x - self.interFrameMousePosition.x) * 1000
            else:
                rotMag = (self.interFrameMousePosition.y - mPos.y) * 1000

            initPos = self.selected.getPos()
            initPar = self.selected.getParent()
            self.selected.wrtReparentTo(render)
            self.selected.setMat(self.selected.getMat() * Mat4.rotateMat(rotMag, self.currTransformDir))
            self.selected.wrtReparentTo(initPar)
            self.selected.setPos(initPos)

            self.interFrameMousePosition = Point3(mPos.x, mPos.y, 0.0)

        elif self.currTransformOperation == self.transformOpEnum.scale:
            # 3rd and final is scaling
            mPos = base.mouseWatcherNode.getMouse()
            # TODO: make dragging away from the object larger and to the object smaller (not simply left right up down)
            # td The problem with this MAY come if negative, mirrored, scaling is implemented.

            # if operating on the z-axis, use the y (vertical screen coordinates otherwise use x (horizontal)
            if self.currTransformDir == Point3( 0.0, 0.0, 1.0):
                sclMag = (mPos.y - self.interFrameMousePosition.y) * 5.5
            elif self.currTransformDir == Point3( 0.0, 1.0, 0.0):
                sclMag = (mPos.x - self.interFrameMousePosition.x) * 5.5
            else:
                sclMag = (self.interFrameMousePosition.x - mPos.x) * 5.5

            # This is the line that prevents scaling past the origin. Flipping the faces doesn't seem to work.
            if -0.0001 < sclMag < 0.0001:
                sclMag = 0.000001

            # create a dummy node to parent to and position such that applying scale to it will scale selected properly
            dummy = self.levitorNP.attachNewNode('dummy')
            initScl = dummy.getScale()
            # Don't forget the parent. Selected needs put back in place
            initPar = self.selected.getParent()
            initPos = self.selected.getPos()
            self.selected.wrtReparentTo(dummy)

            dummy.setScale(initScl.x + sclMag * self.currTransformDir.x,
                           initScl.y + sclMag * self.currTransformDir.y,
                           initScl.z + sclMag * self.currTransformDir.z)

            # reset selected's parent then destroy dummy
            self.selected.wrtReparentTo(initPar)
            self.selected.setPos(initPos)
            dummy.removeNode()
            dummy = None

            self.interFrameMousePosition = Point3( mPos.x, mPos.y, 0.0)
        else:
            self.notify.error("Err: Dragging with invalid curTransformOperation enum in handleDragging")

        return task.cont  # ended by handleM1Up(), the mouse1-up event handler


    def initializeManipVars(self, transformDir, transformOp, mPos3D, planeNormVec=None):
        self.currTransformDir = transformDir
        self.currPlaneColNorm = planeNormVec  # set the norm for the collision plane to be used in mouse1Dragging
        self.interFrameMousePosition = mPos3D
        self.currTransformOperation = transformOp
        self.isDragging = True
        taskMgr.add(self.handleDragging, 'mouse1Dragging')
        messenger.accept('mouse1-up', self, self.handleM1Up)


    def getMousePlaneIntersect(self, mPos3Dref, normVec):
        mPos = base.mouseWatcherNode.getMouse()
        plane = Plane(normVec, self.grabModelNP.getPos())
        nearPoint = Point3()
        farPoint = Point3()
        base.camLens.extrude(mPos, nearPoint, farPoint)
        if plane.intersectsLine(mPos3Dref,
            render.getRelativePoint(camera, nearPoint),
            render.getRelativePoint(camera, farPoint)):
            return True
        return False



    def destroy(self):
        raise NotImplementedError('Make sure messenger etc are cleared of refs and the model node is deleted')
        self.grabModelNP.clearPythonTag('grabberRoot')
        self.grabModelNP.clearPythonTag('grabber')
        self.grabModelNP = None
        messenger.ignoreAll(self)
Ejemplo n.º 36
0
class Moving(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        # This is used to store which keys are currently pressed.
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "back": 0, "up": 0}

        # 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("EggMod/SandPlan.egg")
        self.environ.reparentTo(render)
        self.environ.setScale(20)

        StartPos = LVector3(0,0,94)
        self.movint = loader.loadModel("EggMod/HailPar.egg")
        self.movint.reparentTo(render)
        self.movint.setScale(2)
        self.movint.setPos(StartPos + (0, 0, 0.5))


        # 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("f", self.setKey, ["up", 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("f-up", self.setKey, ["up", False])
        
        self.mopan=Pmango()
        
        self.alin = LinearEulerIntegrator()
        self.mopan.attachLinearIntegrator(self.alin)
        self.arin = AngularEulerIntegrator()
        self.mopan.attachAngularIntegrator(self.arin)
        
        taskMgr.add(self.move, "moveTask")


        self.cTrav = CollisionTraverser()
        #base.cTrav.setRespectPrevTransform(True)
        

        self.actMove = NodePath("ActMove")
        self.actMove.reparentTo(render)
        self.an = ActorNode("BMova")
        self.anp = self.actMove.attachNewNode(self.an)
        

        
        self.mopan.attachPhysicalNode(self.an)
        self.movint.reparentTo(self.anp)

        self.anp.node().getPhysicsObject().setMass(1)
        #self.an.getPhysicsObject().setTerminalVelocity(1.0)

        self.dvi=0
        self.grava=ForceNode('GravAll')
        self.grar=render.attachNewNode(self.grava)
        self.grdi=LinearVectorForce(0.0,-0.0,-8.0)
        #self.grdi.setMassDependent(1)
        self.grava.addForce(self.grdi)  #Forces have to be added to force nodes and to
        # a physics manager
         
        self.mopan.addLinearForce(self.grdi)

        
        self.BMoveBalance = CollisionSphere(0, 0, -7.0, 1)
        self.BMoveBalanceNode = CollisionNode('BMove')
        self.BMoveBalanceNode.addSolid(self.BMoveBalance)
        

        self.BMoveBalancePath = self.movint.attachNewNode(self.BMoveBalanceNode)
        self.DinGro = PhysicsCollisionHandler()
        self.DinGro.setStaticFrictionCoef(1)
        self.DinGro.setDynamicFrictionCoef(2)
        self.DinGro.setAlmostStationarySpeed(0.1)

        self.DinGro.addCollider(self.BMoveBalancePath,self.anp) #Colliders use nodepaths for collisions instead of nodes
        self.cTrav.addCollider(self.BMoveBalancePath, self.DinGro)

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

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

        # Create some lighting
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        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()
        self.dvi+=dt
        self.anr=self.an.getPhysicsObject()

        print(self.anr.getVelocity())

        if dt<=.2:
            self.mopan.doPhysics(dt)
    
        if self.keyMap["left"]:
            self.movint.setH(self.movint.getH() + 200 * dt)
        if self.keyMap["right"]:
            self.movint.setH(self.movint.getH() - 200 * dt)
        if self.keyMap["forward"]:
            self.movint.setFluidY(self.movint, -25 * dt)          
        if self.keyMap["back"]:
            self.movint.setFluidY(self.movint, 25 * dt)
        if self.keyMap["up"]:
            self.movint.setFluidZ(self.movint, 25 * 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)
        

        return task.cont
Ejemplo n.º 37
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
Ejemplo n.º 38
0
class World(DirectObject):

    def __init__(self):
        #create Queue to hold the incoming chat
        #request the heartbeat so that the caht interface is being refreshed in order to get the message from other player
        
        self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0, "charge":0}
        base.win.setClearColor(Vec4(0,0,0,1))

        self.cManager = ConnectionManager()
        self.cManager.startConnection()
        #------------------------------
        #Chat
        Chat(self.cManager)
        
        
        #send dummy login info of the particular client
        #send first chat info 
        #---------------------------------------
        self.userName = username
        dummy_login ={'user_id' : self.userName, 'factionId': faction, 'password': '******'}
        self.cManager.sendRequest(Constants.RAND_STRING, dummy_login)
        
        
        chat = { 'userName' : self.userName,     #username
                 'message'    : '-------Login------' }
        self.cManager.sendRequest(Constants.CMSG_CHAT, chat)

        #--------------------------------------
        #self.minimap = OnscreenImage(image="images/minimap.png", scale=(0.2,1,0.2), pos=(-1.1,0,0.8))

        #frame = DirectFrame(text="Resource Bar", scale=0.001)

        resource_bar = DirectWaitBar(text="",
            value=35, range=100, pos=(0,0,0.9), barColor=(255,255,0,1),
            frameSize=(-0.3,0.3,0,0.03))
        cp_bar = DirectWaitBar(text="",
            value=70, range=100, pos=(1.0,0,0.9), barColor=(0,0,255,1),
            frameSize=(-0.3,0.3,0,0.03), frameColor=(255,0,0,1))

        # 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.environ.setPos(0,0,0)
        
        # 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)

        nameplate = TextNode('textNode username_' + str(self.userName))
        nameplate.setText(self.userName)
        npNodePath = self.ralph.attachNewNode(nameplate)
        npNodePath.setScale(0.8)
        npNodePath.setBillboardPointEye()
        #npNodePath.setPos(1.0,0,6.0)
        npNodePath.setZ(6.5)

        bar = DirectWaitBar(value=100, scale=1.0)
        bar.setColor(255,0,0)
        #bar.setBarRelief()
        bar.setZ(6.0)
        bar.setBillboardPointEye()
        bar.reparentTo(self.ralph)

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("a", self.setKey, ["cam-left",1])
        self.accept("s", self.setKey, ["cam-right",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("a-up", self.setKey, ["cam-left",0])
        self.accept("s-up", self.setKey, ["cam-right",0])
        self.accept("c", self.setKey, ["charge",1])
        self.accept("c-up", self.setKey, ["charge",0])

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

        # Game state variables
        self.isMoving = False

        # Set up the camera
        
        base.disableMouse()
        base.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,1000)
        self.ralphGroundRay.setDirection(0,0,-1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.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,1000)
        self.camGroundRay.setDirection(0,0,-1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.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(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(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):

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

        base.camera.lookAt(self.ralph)
        if (self.keyMap["cam-left"]!=0):
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["cam-right"]!=0):
            base.camera.setX(base.camera, +20 * globalClock.getDt())

        # 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"]!=0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -25 * globalClock.getDt())
        if (self.keyMap["charge"]!=0):
            self.ralph.setY(self.ralph, -250 * globalClock.getDt())
            #ribbon = Ribbon(self.ralph, Vec4(1,1,1,1), 3, 10, 0.3)
            #ribbon.getRoot().setZ(2.0)

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

        if (self.keyMap["forward"]!=0) or (self.keyMap["charge"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0):
            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() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec*(5-camdist))
            camdist = 5.0

        # Now check for collisions.

        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 = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     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 = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.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.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + 2.0)
        base.camera.lookAt(self.floater)

        return task.cont
Ejemplo n.º 39
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()
class MapEditor():
    def __init__(self, terrain):
        self.terrain = terrain
        self.terrain.setTag('EditableTerrain', '1')
        self.cursor = render.attachNewNode('EditCursor')
        loader.loadModel("models/sphere").reparentTo(self.cursor)
        self.size = 10.0
        self.cursor.setScale(self.size)
        #self.cursor.setSz(self.size / self.terrain.getSz())
        self.cursor.setRenderModeWireframe()
        self.setupMouseCollision()
        self.on = False
        self.disable()

    def enable(self):
        taskMgr.add(self.update, "terrainEditor")
        self.cursor.unstash()

    def disable(self):
        taskMgr.remove("terrainEditor")
        self.cursor.stash()

    def toggle(self, value = None):
        if value == None:
            self.on = not self.on
        else:
            self.on = value
        if self.on:
            self.enable()
        else:
            self.disable()

    def update(self, task):
        self.onMouseTask()
        return Task.cont

    def onMouseTask(self):
        """ """
        #do we have a mouse
        logging.info("onMouseTask")
        if (base.mouseWatcherNode.hasMouse() == False):

            logging.error("no mouse")
            return

        #get the mouse position
        mpos = base.mouseWatcherNode.getMouse()

        #Set the position of the ray based on the mouse position

        if not self.mPickRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()):
            logging.error("point is not acceptable")


        #for this small example I will traverse everything, for bigger projects
        #this is probably a bad idea
        self.mPickerTraverser.traverse(self.terrain)
        logging.info("Mouse pick ray traversing terrain.")

        if (self.mCollisionQueue.getNumEntries() > 0):
            self.mCollisionQueue.sortEntries()
            entry     = self.mCollisionQueue.getEntry(0);
            pickedObj = entry.getIntoNodePath()
            #pickedObj = pickedObj.findNetTag('EditableTerrain')
            if not pickedObj.isEmpty():
                #here is how you get the surface collsion
                pos = entry.getSurfacePoint(render)
                #pos.z *= self.terrain.getSz()
                logging.info(str(pickedObj))
                logging.info(str(pos))
                self.cursor.setPos(pos)
                #handlePickedObject(pickedObj)
            else:
                logging.info("picked object is empty")
        else:
            logging.info("Nothing collided with mouse pick ray")


    def setupMouseCollision(self):
        """ """
        #Since we are using collision detection to do picking, we set it up
        #any other collision detection system with a traverser and a handler
        self.mPickerTraverser = CollisionTraverser()            #Make a traverser
        self.mCollisionQueue  = CollisionHandlerQueue()

        #create a collision solid ray to detect against
        self.mPickRay = CollisionRay()
        #self.mPickRay.setOrigin(base.camera.getPos(render))
        #self.mPickRay.setDirection(render.getRelativeVector(base.camera, Vec3(0,1,0)))

        #create our collison Node to hold the ray
        self.mPickNode = CollisionNode('pickRay')
        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)

        #well 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(GeomNode.getDefaultCollideMask())

        #Register the ray as something that can cause collisions
        self.mPickerTraverser.addCollider(self.mPickNP, self.mCollisionQueue)
Ejemplo n.º 41
0
class World(DirectObject):

    def __init__(self):
        self.itemID = 0
        self.switchState = True
        self.iAktion = "E"
        self.altIPos = [0,0]
        self.switchCam = False
        self.kampf = Battle.Kampf()
        self.itemDa = False
        self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0}
        base.win.setClearColor(Vec4(0,0,0,1))

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

 
        self.spieler = Players.Player(Actor("models/box.x"))
        self.spieler.actor.reparentTo(render)
        spielerStartPos = (-107.575, 26.6066, -0.490075)
        self.spieler.actor.setPos(spielerStartPos)
        self.textObjectSpieler = OnscreenText(text = self.spieler.name+":  "+str(self.spieler.energie)+"/"+str(self.spieler.maxenergie)+" HP", pos = (-0.90, -0.98), scale = 0.07, fg = (1,0,0,1))        

        # Erstellt Gegner
        
        self.gegnerStartPos = ([(-39.1143569946,25.1781406403,-0.136657714844),
                                (-102.375793457,-30.6321983337,0.0),
                                (-56.927986145, -34.6329650879, -0.16748046875),
                                (-79.6673126221,30.8231620789,2.89721679688),
                                (-4.37648868561,30.5158863068,2.18450927734),
                                (22.6527004242,4.99837779999,3.11364746094),
                                (-23.8257598877,-7.87773084641,1.36920166016),
                                (-80.6140823364,19.5769443512,4.70764160156),
                                (-75.0773696899,-15.2991075516,6.24676513672)
                                ])
        
        gegnerPos = random.choice(self.gegnerStartPos)
        self.gegnerErstellen(gegnerPos)
        self.textObjectGegner = OnscreenText(text = str(self.gegner.name)+": "+str(self.gegner.energie)+"/"+str(self.gegner.maxenergie)+" HP", pos = (0.90, -0.98), scale = 0.07, fg = (1,0,0,1))
        
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        self.item = None
        
        # Handling der Usereingaben für Bewegung

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("a", self.setKey, ["cam-left",1])
        self.accept("s", self.setKey, ["cam-right",1])
        self.accept("i", self.setKey, ["inventar",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("a-up", self.setKey, ["cam-left",0])
        self.accept("s-up", self.setKey, ["cam-right",0])

        self.accept("e", self.iAktionsHandler,["e"])
        self.accept("v", self.iAktionsHandler,["v"])
        self.accept("w", self.iAktionsHandler,["w"])
        
        taskMgr.add(self.move,"moveTask")
        taskMgr.add(self.erkenneKampf,"Kampferkennung")
        taskMgr.add(self.screentexts,"Screentexte")


        # Menü erstellen

        self.createMenu()
        
        # Kameraeinstellungen
        
        base.disableMouse()
        base.camera.setPos(self.spieler.actor.getX(),self.spieler.actor.getY()+10,2)
        
        self.collisionInit();
        
        self.setAI()
        
        # Licht
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

        # Hintergrund (Himmel)

        self.setupSkySphere()

    def iAktionsHandler(self,key):
        if key == "e":
            self.iAktion = "E"
        elif key == "w":
            self.iAktion = "W"
        elif key == "v":
            self.iAktion = "V"
            

    def collisionInit(self):
        # Kollisionserkennung, um auf dem Boden zu laufen. Der Collisionray
        # erkennt die Hoehe des Gelaendes und wenn ein Objekt da ist, wird 
        # die Bewegung als illegal gewertet.

        self.cTrav = CollisionTraverser()

        self.spielerGroundRay = CollisionRay()
        self.spielerGroundRay.setOrigin(0,0,1000)
        self.spielerGroundRay.setDirection(0,0,-1)
        self.spielerGroundCol = CollisionNode('spielerRay')
        self.spielerGroundCol.addSolid(self.spielerGroundRay)
        self.spielerGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.spielerGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.spielerGroundColNp = self.spieler.actor.attachNewNode(self.spielerGroundCol)
        self.spielerGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.spielerGroundColNp, self.spielerGroundHandler)

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

        self.gegnerGroundRay = CollisionRay()
        self.gegnerGroundRay.setOrigin(0,0,1000)
        self.gegnerGroundRay.setDirection(0,0,-1)
        self.gegnerGroundCol = CollisionNode('gegnerRay')
        self.gegnerGroundCol.addSolid(self.gegnerGroundRay)
        self.gegnerGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.gegnerGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.gegnerGroundColNp = self.gegner.actor.attachNewNode(self.gegnerGroundCol)
        self.gegnerGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.gegnerGroundColNp, self.gegnerGroundHandler)


    def setupSkySphere(self):
        self.skysphere = loader.loadModel("models/LinearPinkSkySphere.bam")
        # Textur für den Himmel laden
        self.sky_tex = loader.loadTexture("Images/Sterne.jpg")
        # Himmel Textur konfigurieren
        self.skysphere.setTexture(self.sky_tex, 1)
	self.skysphere.setBin('background', 1) 
        self.skysphere.setDepthWrite(0) 
        self.skysphere.reparentTo(render)
        self.skysphere.setScale(40)
        taskMgr.add(self.skysphereTask, "SkySphere Task") 

    def skysphereTask(self, task): 
        self.skysphere.setPos(base.camera, 0, 0, 0) 
        return task.cont

    def createMenu(self):
        self.createFrame()
        itemListe = self.spieler.inventar.anzeigen(1)
        standardpos = [0.18, 0.98, 0.83]
        self.buttonListe = []
        beutelLabel = DirectLabel(text = itemListe[0][0], pos = (0.18, 0.98, 0.95), scale = 0.07, text_fg = (1,0,0,1), text_bg = (0, 50, 50, 1), textMayChange = 1)
        del itemListe [0][0]
        for zeile in range(4):
            for i in range(0,5):
                Button = DirectButton(text = itemListe [zeile] [i], pos = standardpos, scale = 0.07, text_fg = (1,0,0,1), text_bg = (0, 50, 50, 1), textMayChange = 1, extraArgs = [zeile,i], command = self.inventarAktion)
                self.buttonListe.append (Button)
                standardpos[0] += 0.25
            standardpos[0] = 0.18    
            standardpos[2] -= 0.15
            
    def createFrame(self):
        self.myFrame = DirectFrame(frameColor=(0, 50, 50, 0.5),
                      frameSize=(-1, 1, -.7, 1),
                      pos=(1, -1, 1))

    def inventarAktion(self,zeile,spalte):
        if self.iAktion == "E":
            self.spieler.inventar.entfernen(1,[zeile,spalte])
            self.myFrame.destroy()
            i = 0
            for item in self.buttonListe:
                    self.buttonListe [i].destroy()
                    i += 1
            del self.buttonListe[:]
            self.createMenu()  
        elif self.iAktion == "W":
            self.altIPos = [zeile,spalte]
        elif self.iAktion == "V":
            self.spieler.inventar.verschieben(1,1,self.altIPos,[zeile,spalte])
            self.myFrame.destroy()
            i = 0
            for item in self.buttonListe:
                    self.buttonListe [i].destroy()
                    i += 1
            del self.buttonListe[:]
            self.createMenu()        
        
        
    # Erkennt den Status der Eingabe
    def setKey(self, key, value):
        self.keyMap[key] = value

    def screentexts(self,task):
        self.textObjectSpieler.destroy()
        self.textObjectSpieler = OnscreenText(text = self.spieler.name+":  "+str(self.spieler.energie)+"/"+str(self.spieler.maxenergie)+" HP", pos = (-0.90, -0.98), scale = 0.07, fg = (1,0,0,1))
        self.textObjectGegner.destroy()
        if self.kampf.active == True:
            self.textObjectGegner = OnscreenText(text = str(self.gegner.name)+": "+str(self.gegner.energie)+"/"+str(self.gegner.maxenergie)+" HP", pos = (0.90, -0.98), scale = 0.07, fg = (1,0,0,1))
        else:
            self.textObjectGegner = OnscreenText(text = "Kein Gegner vorhanden", pos = (0.90, -0.98), scale = 0.07, fg = (1,0,0,1))
        return Task.cont

    def camera(self):
         # cam-left Key: Kamera nach links
        # cam-right Key: Kamera nach rechts
        base.camera.lookAt(self.spieler.actor)
        if (self.keyMap["cam-left"]!=0):
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["cam-right"]!=0):
            base.camera.setX(base.camera, +20 * globalClock.getDt())

        # Wenn die Kamera zu weit weg ist, zoom heran.
        # Wenn die Kamera zu nah dran ist, zoom weg.

        camvec = self.spieler.actor.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec*(5-camdist))
            camdist = 5.0

        # Haelt die Kamera einen Schritt über dem Boden
        # oder zwei Schritte ueber dem Spieler, je nachdem, was groesser ist.
        
        entries = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0)
        if (base.camera.getZ() < self.spieler.actor.getZ() + 2.0):
            base.camera.setZ(self.spieler.actor.getZ() + 2.0)
            
        # Die Kamera soll in die Richtung des Spielers gucken, aber auch
        # immer horizontal bleiben.
        
        self.floater.setPos(self.spieler.actor.getPos())
        self.floater.setZ(self.spieler.actor.getZ() + 2.0)
        base.camera.lookAt(self.floater)

    def collisions(self,startpos):
        
        # Überprüfen auf Itemkollision
        
        if self.item <> None:
            if (self.item.actor.getX() - self.spieler.actor.getX() < 1
            and self.item.actor.getY() - self.spieler.actor.getY() < 1
            and self.item.actor.getZ() - self.spieler.actor.getZ() <1
            and self.itemDa == True):
                self.itemDa = False
                self.item.actor.detachNode()
                self.spieler.inventar.einfuegen(self.item)
                self.myFrame.destroy()
                del self.buttonListe[:]
                self.createMenu()

         # Start der Kollisionserkennung

        self.cTrav.traverse(render)


        # Aendert die Z Koordinate des Spielers. Wenn er etwas trifft, bewegt
        # ihn entsprechend, wenn er nichts trifft, setzt die Koordinate 
        # auf den Stand des letzten Frames
        self.dummyMethode(self.spielerGroundHandler, self.spieler.actor,startpos)

    
    def move(self,task):

        self.camera();
        
        # Speichert die Startposition, damit der Spieler zurueckgesetzt
        # werden kann, sollte er irgendwo runterfallen

        startpos = self.spieler.actor.getPos()

        # Wenn einer der Move Keys gedrueckt wird, wird der Spieler
        # in die ensprechende Richtung bewegt

        if (self.keyMap["left"]!=0):
            self.spieler.actor.setH(self.spieler.actor.getH() + 150 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.spieler.actor.setH(self.spieler.actor.getH() - 150 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.spieler.actor.setY(self.spieler.actor, -12 * globalClock.getDt())

        self.collisions(startpos);

        return Task.cont

    def gegnermove(self):
 
        # Zeit seit dem letzten Frame. Benötigt fuer
        # framerateunabhaengige Bewegung.
        elapsed = globalClock.getDt()

        startpos = self.gegner.actor.getPos()
 
        # Aendert die Z Koordinate des Gegners. Wenn er etwas trifft, bewegt
        # ihn entsprechend, wenn er nichts trifft, setzt die Koordinate 
        # auf den Stand des letzten Frames
 
        self.cTrav.traverse(render)
        self.dummyMethode(self.gegnerGroundHandler, self.gegner.actor,startpos)
 
        self.gegner.actor.setP(0)
        if self.gegner.energie == 0:
            return Task.done
        else:
            return Task.cont

    def dummyMethode(self, handler, actor,startpos):
        entries = []
        for i in range(handler.getNumEntries()):
            entry = handler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            actor.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            actor.setPos(startpos)
	
	
	
    def setAI(self):
        # Erstellt die AI World
        self.AIworld = AIWorld(render)
 
        self.AIchar = AICharacter("gegner",self.gegner.actor, 100, 0.02, 1)
        self.AIworld.addAiChar(self.AIchar)
        self.AIbehaviors = self.AIchar.getAiBehaviors()
 
        self.AIbehaviors.wander(360, 0, 15, 1.0)
 
        #AI World update zum Tasknamager hinzufügen       
        taskMgr.add(self.AIUpdate,"AIUpdate")
 
 
    # Update der AI World   
    def AIUpdate(self,task):
        if self.kampf.active == False:
            self.AIworld.update()
            self.gegnermove()
 
        return Task.cont

    # Startet bei einem Abstand von 4 zwischen Spieler und Gegner einen Kampf
    def erkenneKampf(self,task):
        if (self.spieler.actor.getX() - self.gegner.actor.getX() < 4
        and self.spieler.actor.getX() - self.gegner.actor.getX() > -4
        and self.kampf.active == False):
            self.kampf.active = True
            self.startzeit = globalClock.getLongTime()
        if self.kampf.active == True:
            self.Kampf(self)
        if self.gegner.energie == 0:
            return Task.done
        else:
            return Task.cont

    def gegnerErstellen(self,pos):
        self.gegner = Monster.Goblin(Actor("models/box.x"))
        self.gegner.actor.reparentTo(render)
        self.gegner.actor.setPos(pos)
        self.gegnerAltPos = pos
        self.setAI()

    def gegnerTod(self):
        self.kampf.active = False
        itemPos = self.gegner.actor.getPos()
        self.gegner.actor.detachNode()
        self.item = Items.Axt()
        self.item.ID = self.itemID
        self.itemID += 1
        self.itemDa = True
        self.item.actor.setScale(0.3)
        self.item.actor.reparentTo(render)
        self.item.actor.setPos(itemPos)
        gegnerNeuPos = random.choice(self.gegnerStartPos)
        while gegnerNeuPos == self.gegnerAltPos:
            gegnerNeuPos = random.choice(self.gegnerStartPos)
        self.gegnerErstellen(gegnerNeuPos)

    # Lässt Spieler und Gegner nach bestimmter Zeit Aktionen ausführen. Bei Tod des
    # Gegners wird ein neuer Gegner sowie ein Item generiert
    def Kampf(self,task):
        if ((int(globalClock.getLongTime()) - int(self.startzeit)) % 5 == 0
        and self.kampf.active == True):
            erg = self.kampf.Kampf(self.spieler,self.gegner)
            self.spieler = erg[0]
            self.gegner = erg[1]
            self.startzeit -= 1
            if self.spieler.energie == 0:
                sys.exit
            elif self.gegner.energie == 0:
                self.gegnerTod();
        if self.startzeit <= 0:
            self.startzeit = globalClock.getLongTime()
Ejemplo n.º 42
0
class World(DirectObject):
    def __init__(self):
        # This code puts the standard title and instruction text on screen
        self.title = OnscreenText(text="Ball in Maze",
                                  style=1,
                                  fg=(1, 1, 1, 1),
                                  pos=(0.7, -0.95),
                                  scale=.07)
        self.instructions = OnscreenText(text="Press Esc to exit.",
                                         pos=(-1.3, .95),
                                         fg=(1, 1, 1, 1),
                                         align=TextNode.ALeft,
                                         scale=.05)

        base.setBackgroundColor(0, 0, 0)

        self.central_msg = OnscreenText(text="",
                                        pos=(0, 0),
                                        fg=(1, 1, 0, 1),
                                        scale=.1)
        self.central_msg.hide()

        self.accept("escape", sys.exit)  # Escape quits
        base.disableMouse()  # Disable mouse-based camera control
        camera.setPosHpr(0, 0, 25, 0, -90, 0)  # Place the camera

        # Load the maze and place it in the scene
        self.maze = loader.loadModel("models/maze")
        self.maze.reparentTo(render)

        # Most times, you want collisions to be tested against invisible geometry
        # rather than every polygon. This is because testing against every polygon
        # in the scene is usually too slow. You can have simplified or approximate
        # geometry for the solids and still get good results.
        #
        # Sometimes you'll want to create and position your own collision solids in
        # code, but it's often easier to have them built automatically. This can be
        # done by adding special tags into an egg file. Check maze.egg and ball.egg
        # and look for lines starting with <Collide>. The part is brackets tells
        # Panda exactly what to do. Polyset means to use the polygons in that group
        # as solids, while Sphere tells panda to make a collision sphere around them
        # Keep means to keep the polygons in the group as visable geometry (good
        # for the ball, not for the triggers), and descend means to make sure that
        # the settings are applied to any subgroups.
        #
        # Once we have the collision tags in the models, we can get to them using
        # NodePath's find command

        # Find the collision node named wall_collide
        self.walls = self.maze.find("**/wall_collide")

        # Collision objects are sorted using BitMasks. BitMasks are ordinary numbers
        # with extra methods for working with them as binary bits. Every collision
        # solid has both a from mask and an into mask. Before Panda tests two
        # objects, it checks to make sure that the from and into collision masks
        # have at least one bit in common. That way things that shouldn't interact
        # won't. Normal model nodes have collision masks as well. By default they
        # are set to bit 20. If you want to collide against actual visable polygons,
        # set a from collide mask to include bit 20
        #
        # For this example, we will make everything we want the ball to collide with
        # include bit 0
        self.walls.node().setIntoCollideMask(BitMask32.bit(0))
        # CollisionNodes are usually invisible but can be shown. Uncomment the next
        # line to see the collision walls
        # self.walls.show()

        # We will now find the triggers for the holes and set their masks to 0 as
        # well. We also set their names to make them easier to identify during
        # collisions
        self.loseTriggers = []
        for i in range(6):
            trigger = self.maze.find("**/hole_collide" + str(i))
            trigger.node().setIntoCollideMask(BitMask32.bit(0))
            trigger.node().setName("loseTrigger")
            self.loseTriggers.append(trigger)
            # Uncomment this line to see the triggers
            # trigger.show()

        # Ground_collide is a single polygon on the same plane as the ground in the
        # maze. We will use a ray to collide with it so that we will know exactly
        # what height to put the ball at every frame. Since this is not something
        # that we want the ball itself to collide with, it has a different
        # bitmask.
        self.mazeGround = self.maze.find("**/ground_collide")
        self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1))

        # Load the ball and attach it to the scene
        # It is on a root dummy node so that we can rotate the ball itself without
        # rotating the ray that will be attached to it
        self.ballRoot = render.attachNewNode("ballRoot")
        self.ball = loader.loadModel("models/ball")
        self.ball.reparentTo(self.ballRoot)

        # Find the collison sphere for the ball which was created in the egg file
        # Notice that it has a from collision mask of bit 0, and an into collison
        # mask of no bits. This means that the ball can only cause collisions, not
        # be collided into
        self.ballSphere = self.ball.find("**/ball")
        self.ballSphere.node().setFromCollideMask(BitMask32.bit(0))
        self.ballSphere.node().setIntoCollideMask(BitMask32.allOff())

        # No we create a ray to start above the ball and cast down. This is to
        # Determine the height the ball should be at and the angle the floor is
        # tilting. We could have used the sphere around the ball itself, but it
        # would not be as reliable
        self.ballGroundRay = CollisionRay()  # Create the ray
        self.ballGroundRay.setOrigin(0, 0, 10)  # Set its origin
        self.ballGroundRay.setDirection(0, 0, -1)  # And its direction
        # Collision solids go in CollisionNode
        self.ballGroundCol = CollisionNode(
            'groundRay')  # Create and name the node
        self.ballGroundCol.addSolid(self.ballGroundRay)  # Add the ray
        self.ballGroundCol.setFromCollideMask(
            BitMask32.bit(1))  # Set its bitmasks
        self.ballGroundCol.setIntoCollideMask(BitMask32.allOff())
        # Attach the node to the ballRoot so that the ray is relative to the ball
        # (it will always be 10 feet over the ball and point down)
        self.ballGroundColNp = self.ballRoot.attachNewNode(self.ballGroundCol)
        # Uncomment this line to see the ray
        # self.ballGroundColNp.show()

        # Finally, we create a CollisionTraverser. CollisionTraversers are what
        # do the job of calculating collisions
        self.cTrav = CollisionTraverser()
        # Collision traverservs tell collision handlers about collisions, and then
        # the handler decides what to do with the information. We are using a
        # CollisionHandlerQueue, which simply creates a list of all of the
        # collisions in a given pass. There are more sophisticated handlers like
        # one that sends events and another that tries to keep collided objects
        # apart, but the results are often better with a simple queue
        self.cHandler = CollisionHandlerQueue()
        # Now we add the collision nodes that can create a collision to the
        # traverser. The traverser will compare these to all others nodes in the
        # scene. There is a limit of 32 CollisionNodes per traverser
        # We add the collider, and the handler to use as a pair
        self.cTrav.addCollider(self.ballSphere, self.cHandler)
        self.cTrav.addCollider(self.ballGroundColNp, self.cHandler)

        # Collision traversers have a built in tool to help visualize collisions.
        # Uncomment the next line to see it.
        # self.cTrav.showCollisions(render)

        # This section deals with lighting for the ball. Only the ball was lit
        # because the maze has static lighting pregenerated by the modeler
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.55, .55, .55, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0, 0, -1))
        directionalLight.setColor(Vec4(0.375, 0.375, 0.375, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        self.ballRoot.setLight(render.attachNewNode(ambientLight))
        self.ballRoot.setLight(render.attachNewNode(directionalLight))

        # This section deals with adding a specular highlight to the ball to make
        # it look shiny
        m = Material()
        m.setSpecular(Vec4(1, 1, 1, 1))
        m.setShininess(96)
        self.ball.setMaterial(m, 1)

        # Finally, we call start for more initialization
        self.start()

    def start(self):
        # The maze model also has a locator in it for where to start the ball
        # To access it we use the find command
        startPos = self.maze.find("**/start").getPos()
        self.ballRoot.setPos(startPos)  # Set the ball in the starting position
        self.ballV = Vec3(0, 0, 0)  # Initial velocity is 0
        self.accelV = Vec3(0, 0, 0)  # Initial acceleration is 0

        # For a traverser to actually do collisions, you need to call
        # traverser.traverse() on a part of the scene. Fortunatly, base has a
        # task that does this for the entire scene once a frame. This sets up our
        # traverser as the one to be called automatically
        base.cTrav = self.cTrav

        # Create the movement task, but first make sure it is not already running
        taskMgr.remove("rollTask")
        self.mainLoop = taskMgr.add(self.rollTask, "rollTask")
        self.mainLoop.last = 0

    # This function handles the collision between the ray and the ground
    # Information about the interaction is passed in colEntry
    def groundCollideHandler(self, colEntry):
        # Set the ball to the appropriate Z value for it to be exactly on the ground
        newZ = colEntry.getSurfacePoint(render).getZ()
        self.ballRoot.setZ(newZ + .4)

        # Find the acceleration direction. First the surface normal is crossed with
        # the up vector to get a vector perpendicular to the slope
        norm = colEntry.getSurfaceNormal(render)
        accelSide = norm.cross(UP)
        # Then that vector is crossed with the surface normal to get a vector that
        # points down the slope. By getting the acceleration in 3D like this rather
        # than in 2D, we reduce the amount of error per-frame, reducing jitter
        self.accelV = norm.cross(accelSide)

    # This function handles the collision between the ball and a wall
    def wallCollideHandler(self, colEntry):
        # First we calculate some numbers we need to do a reflection
        norm = colEntry.getSurfaceNormal(render) * -1  # The normal of the wall
        curSpeed = self.ballV.length()  # The current speed
        inVec = self.ballV / curSpeed  # The direction of travel
        velAngle = norm.dot(inVec)  # Angle of incidance
        hitDir = colEntry.getSurfacePoint(render) - self.ballRoot.getPos()
        hitDir.normalize()
        hitAngle = norm.dot(
            hitDir)  # The angle between the ball and the normal

        # Ignore the collision if the ball is either moving away from the wall
        # already (so that we don't accidentally send it back into the wall)
        # and ignore it if the collision isn't dead-on (to avoid getting caught on
        # corners)
        if velAngle > 0 and hitAngle > .995:
            # Standard reflection equation
            reflectVec = (norm * norm.dot(inVec * -1) * 2) + inVec

            # This makes the velocity half of what it was if the hit was dead-on
            # and nearly exactly what it was if this is a glancing blow
            self.ballV = reflectVec * (curSpeed * (((1 - velAngle) * .5) + .5))
            # Since we have a collision, the ball is already a little bit buried in
            # the wall. This calculates a vector needed to move it so that it is
            # exactly touching the wall
            disp = (colEntry.getSurfacePoint(render) -
                    colEntry.getInteriorPoint(render))
            newPos = self.ballRoot.getPos() + disp
            self.ballRoot.setPos(newPos)

    # This is the task that deals with making everything interactive
    def rollTask(self, task):
        # Standard technique for finding the amount of time since the last frame
        dt = task.time - task.last
        task.last = task.time

        # If dt is large, then there has been a # hiccup that could cause the ball
        # to leave the field if this functions runs, so ignore the frame
        if dt > .2: return Task.cont

        # The collision handler collects the collisions. We dispatch which function
        # to handle the collision based on the name of what was collided into
        for i in range(self.cHandler.getNumEntries()):
            entry = self.cHandler.getEntry(i)
            name = entry.getIntoNode().getName()
            if name == "wall_collide": self.wallCollideHandler(entry)
            elif name == "ground_collide": self.groundCollideHandler(entry)
            elif name == "loseTrigger": self.loseGame(entry)

        # Read the mouse position and tilt the maze accordingly
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()  # get the mouse position
            self.maze.setP(mpos.getY() * -10)
            self.maze.setR(mpos.getX() * 10)

        # Finally, we move the ball
        # Update the velocity based on acceleration
        self.ballV += self.accelV * dt * ACCEL
        # Clamp the velocity to the maximum speed
        if self.ballV.lengthSquared() > MAX_SPEED_SQ:
            self.ballV.normalize()
            self.ballV *= MAX_SPEED
        # Update the position based on the velocity
        self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV * dt))

        # This block of code rotates the ball. It uses something called a quaternion
        # to rotate the ball around an arbitrary axis. That axis perpendicular to
        # the balls rotation, and the amount has to do with the size of the ball
        # This is multiplied on the previous rotation to incrimentally turn it.
        prevRot = LRotationf(self.ball.getQuat())
        axis = UP.cross(self.ballV)
        newRot = LRotationf(axis, 45.5 * dt * self.ballV.length())
        self.ball.setQuat(prevRot * newRot)

        return Task.cont  # Continue the task indefinitely

    def show_message(self, message=''):
        if message:
            self.central_msg.setText(message)
            self.central_msg.show()
        else:
            self.central_msg.hide()

    # If the ball hits a hole trigger, then it should fall in the hole.
    # This is faked rather than dealing with the actual physics of it.
    def loseGame(self, entry):
        # The triggers are set up so that the center of the ball should move to the
        # collision point to be in the hole

        toPos = entry.getInteriorPoint(render)
        taskMgr.remove('rollTask')  # Stop the maze task

        # Move the ball into the hole over a short sequence of time. Then wait a
        # second and call start to reset the game
        Sequence(
            Parallel(
                LerpFunc(self.ballRoot.setX,
                         fromData=self.ballRoot.getX(),
                         toData=toPos.getX(),
                         duration=.1),
                LerpFunc(self.ballRoot.setY,
                         fromData=self.ballRoot.getY(),
                         toData=toPos.getY(),
                         duration=.1),
                LerpFunc(self.ballRoot.setZ,
                         fromData=self.ballRoot.getZ(),
                         toData=self.ballRoot.getZ() - .9,
                         duration=.2)), Func(self.show_message, "Try Again!"),
            Wait(1), Func(self.show_message, ""), Func(self.start)).start()
Ejemplo n.º 43
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
Ejemplo n.º 44
0
class World(DirectObject):
    def __init__(self):
        #This code puts the standard title and instruction text on screen
        self.title = OnscreenText(text="Panda3D: Tutorial - Mouse Picking",
                                  style=1,
                                  fg=(1, 1, 1, 1),
                                  pos=(0.8, -0.95),
                                  scale=.07)
        self.escapeEvent = OnscreenText(text="ESC: Quit",
                                        style=1,
                                        fg=(1, 1, 1, 1),
                                        pos=(-1.3, 0.95),
                                        align=TextNode.ALeft,
                                        scale=.05)
        self.mouse1Event = OnscreenText(
            text="Left-click and drag: Pick up and drag piece",
            style=1,
            fg=(1, 1, 1, 1),
            pos=(-1.3, 0.90),
            align=TextNode.ALeft,
            scale=.05)

        self.accept('escape', sys.exit)  #Escape quits
        base.disableMouse()  #Disble mouse camera control
        camera.setPosHpr(0, -13.75, 6, 0, -25, 0)  #Set the camera
        self.setupLights()  #Setup default lighting

        #Since we are using collision detection to do picking, we set it up like
        #any other collision detection system with a traverser and a handler
        self.picker = CollisionTraverser()  #Make a traverser
        self.pq = CollisionHandlerQueue()  #Make a handler
        #Make a collision node for our picker ray
        self.pickerNode = CollisionNode('mouseRay')
        #Attach that node to the camera since the ray will need to be positioned
        #relative to it
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        #Everything to be picked will use bit 1. This way if we were doing other
        #collision we could seperate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()  #Make our ray
        self.pickerNode.addSolid(self.pickerRay)  #Add it to the collision node
        #Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.pq)
        #self.picker.showCollisions(render)

        #Now we create the chess board and its pieces

        #We will attach all of the squares to their own root. This way we can do the
        #collision pass just on the sqaures and save the time of checking the rest
        #of the scene
        self.squareRoot = render.attachNewNode("squareRoot")

        #For each square
        self.squares = [None for i in range(64)]
        self.pieces = [None for i in range(64)]
        for i in range(64):
            #Load, parent, color, and position the model (a single square polygon)
            self.squares[i] = loader.loadModel("models/square")
            self.squares[i].reparentTo(self.squareRoot)
            self.squares[i].setPos(SquarePos(i))
            self.squares[i].setColor(SquareColor(i))
            #Set the model itself to be collideable with the ray. If this model was
            #any more complex than a single polygon, you should set up a collision
            #sphere around it instead. But for single polygons this works fine.
            self.squares[i].find("**/polygon").node().setIntoCollideMask(
                BitMask32.bit(1))
            #Set a tag on the square's node so we can look up what square this is
            #later during the collision pass
            self.squares[i].find("**/polygon").node().setTag('square', str(i))

            #We will use this variable as a pointer to whatever piece is currently
            #in this square

        #The order of pieces on a chessboard from white's perspective. This list
        #contains the constructor functions for the piece classes defined below
        pieceOrder = (Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook)

        for i in range(8, 16):
            #Load the white pawns
            self.pieces[i] = Pawn(i, WHITE)
        for i in range(48, 56):
            #load the black pawns
            self.pieces[i] = Pawn(i, PIECEBLACK)
        for i in range(8):
            #Load the special pieces for the front row and color them white
            self.pieces[i] = pieceOrder[i](i, WHITE)
            #Load the special pieces for the back row and color them black
            self.pieces[i + 56] = pieceOrder[i](i + 56, PIECEBLACK)

        #This will represent the index of the currently highlited square
        self.hiSq = False
        #This wil represent the index of the square where currently dragged piece
        #was grabbed from
        self.dragging = False

        #Start the task that handles the picking
        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')
        self.accept("mouse1", self.grabPiece)  #left-click grabs a piece
        self.accept("mouse1-up", self.releasePiece)  #releasing places it

    #This function swaps the positions of two pieces
    def swapPieces(self, fr, to):
        temp = self.pieces[fr]
        self.pieces[fr] = self.pieces[to]
        self.pieces[to] = temp
        if self.pieces[fr]:
            self.pieces[fr].square = fr
            self.pieces[fr].obj.setPos(SquarePos(fr))
        if self.pieces[to]:
            self.pieces[to].square = to
            self.pieces[to].obj.setPos(SquarePos(to))

    def mouseTask(self, task):
        #This task deals with the highlighting and dragging based on the mouse

        #First, clear the current highlight
        if self.hiSq is not False:
            self.squares[self.hiSq].setColor(SquareColor(self.hiSq))
            self.hiSq = False

        #Check to see if we can access the mouse. We need it to do anything else
        if base.mouseWatcherNode.hasMouse():
            #get the mouse position
            mpos = base.mouseWatcherNode.getMouse()

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

            #If we are dragging something, set the position of the object
            #to be at the appropriate point over the plane of the board
            if self.dragging is not False:
                #Gets the point described by pickerRay.getOrigin(), which is relative to
                #camera, relative instead to render
                nearPoint = render.getRelativePoint(camera,
                                                    self.pickerRay.getOrigin())
                #Same thing with the direction of the ray
                nearVec = render.getRelativeVector(
                    camera, self.pickerRay.getDirection())
                self.pieces[self.dragging].obj.setPos(
                    PointAtZ(.5, nearPoint, nearVec))

            #Do the actual collision pass (Do it only on the squares for
            #efficiency purposes)
            self.picker.traverse(self.squareRoot)
            if self.pq.getNumEntries() > 0:
                #if we have hit something, sort the hits so that the closest
                #is first, and highlight that node
                self.pq.sortEntries()
                i = int(self.pq.getEntry(0).getIntoNode().getTag('square'))
                #Set the highlight on the picked square
                self.squares[i].setColor(HIGHLIGHT)
                self.hiSq = i

        return Task.cont

    def grabPiece(self):
        #If a square is highlighted and it has a piece, set it to dragging mode
        if (self.hiSq is not False and self.pieces[self.hiSq]):
            self.dragging = self.hiSq
            self.hiSq = False

    def releasePiece(self):
        #Letting go of a piece. If we are not on a square, return it to its original
        #position. Otherwise, swap it with the piece in the new square
        if self.dragging is not False:  #Make sure we really are dragging something
            #We have let go of the piece, but we are not on a square
            if self.hiSq is False:
                self.pieces[self.dragging].obj.setPos(SquarePos(self.dragging))
            else:
                #Otherwise, swap the pieces
                self.swapPieces(self.dragging, self.hiSq)

        #We are no longer dragging anything
        self.dragging = False

    def setupLights(self):  #This function sets up some default lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.8, .8, .8, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0, 45, -45))
        directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(ambientLight))
Ejemplo n.º 45
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
Ejemplo n.º 46
0
class World(ShowBase):
    def skyBoxLoad(self):
        self.spaceSkyBox = load_model('skybox1.egg')
        self.spaceSkyBox.setScale(150)
        self.spaceSkyBox.setLightOff()
        self.spaceSkyBox.reparentTo(render)
        self.spaceSkyBox.setPos(0,0,-200)
        self.spaceSkyBox.setHpr(0,0,0)        

    def loadEnviron(self):
        self.environ = load_model("secondWorld.egg")
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)

    def Hooh(self):
        """ hooh """
        self.hoohActor = Actor("anim2hooh.egg",
                           {"wing":"anim-Anim0.egg"})
        self.hoohActor.reparentTo(render)
        self.hoohActor.loop("wing")
        self.hoohActor.setPos(self.ralphStartPos[0],
                              self.ralphStartPos[1]+100,
                              self.ralphStartPos[2]+100)
        self.hoohActor.setPlayRate(4.0,"wing")
        self.hoohActor.setHpr(180,90,0)

        start = Point3(self.ralphStartPos[0], self.ralphStartPos[1]+95,
                       self.ralphStartPos[2]+100)
        end = Point3(self.ralphStartPos[0], self.ralphStartPos[1]-100,
                     self.ralphStartPos[2]+100)
        turnHpr1 = Point3(180,90,0)
        turnHpr2 = Point3(0,90,0) 
        hoohPosInt1 = self.hoohActor.posInterval(5.0, start, startPos = end)
        hoohPosInt2 = self.hoohActor.posInterval(5.0, end, startPos = start)
        hoohHprInt1 = self.hoohActor.hprInterval(1.0, turnHpr2,
                                                 startHpr=turnHpr1)
        hoohHprInt2 = self.hoohActor.hprInterval(1.0, turnHpr1,
                                                 startHpr=turnHpr2)        
        self.hoohFly = Sequence(hoohPosInt1,
                                hoohHprInt1,
                                hoohPosInt2,
                                hoohHprInt2,
                                name="hoohFly")
        self.hoohFly.loop()        

    def gold(self, task):
        _GOLD_PARTICLES.setPos(self.hoohActor.getPos())
        return task.cont
        
    def loadPokemon(self):
        """ Pikachu """
        self.pikachu = load_model("pikachu.egg")
        self.pikachu.reparentTo(render)
        self.pikachu.setPos(_PIKACHU_POS)
        self.pikachu.setHpr(_PIKACHU_HPR)

        """ Groudon """
        self.Groudon = load_model("Groudon.egg")
        self.Groudon.reparentTo(render)
        self.Groudon.setPos(_GROUDON_POS)
        self.Groudon.setHpr(_GROUDON_HPR)

        """ Bulbasaur """
        self.bulbasaur = load_model("bulbasaur.egg")
        self.bulbasaur.reparentTo(render)
        self.bulbasaur.setPos(_BULBASAUR_POS)
        self.bulbasaur.setHpr(_BULBASAUR_HPR)

        """ hooh """
        self.Hooh()

        """ Pichu """
        self.pichu = load_model("pichu.egg")
        self.pichu.reparentTo(render)
        self.pichu.setPos(_PICHU_POS)
        self.pichu.setHpr(_PICHU_HPR)

        """ Charmander """
        self.charmander = load_model("char.egg")
        self.charmander.reparentTo(render)
        self.charmander.setPos(_CHARMANDER_POS)
        self.charmander.setHpr(_CHARMANDER_HPR)

        """ charizard """
        self.charizard = load_model("charizard.egg")
        self.charizard.reparentTo(render)
        self.charizard.setPos(_CHARIZARD_POS)
        self.charizard.setHpr(_CHARIZARD_HPR)

        """ blastoise """
        self.blastoise = load_model("blastoise.egg")
        self.blastoise.reparentTo(render)
        self.blastoise.setPos(_BLASTOISE_POS)
        self.blastoise.setHpr(_BLASTOISE_HPR)

        """ Squirtle """
        self.squirtle = load_model("squirtle.egg")
        self.squirtle.reparentTo(render)
        self.squirtle.setPos(_SQUIRTLE_POS)
        self.squirtle.setHpr(_SQUIRTLE_HPR)

        """ Dragonite """
        self.dragonite = load_model("dragonite.egg")
        self.dragonite.reparentTo(render)
        self.dragonite.setPos(_DRAGONITE_POS)
        self.dragonite.setHpr(_DRAGONITE_HPR)
        
        _FLAME.setPos(_FLAME_POS)
        _FLAME.setScale(0.1)
        _FLAME.start(parent=render, renderParent=render)
        
        """ venusaur """
        self.venusaur = load_model("venusaur.egg")
        self.venusaur.reparentTo(render)
        self.venusaur.setPos(_VENUSAUR_POS)
        self.venusaur.setHpr(_VENUSAUR_HPR)
        
    def loadRalph(self):
        # Create the main character, Ralph
        basePath = r"../google_drive/ball/data/models/"
        self.ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor(basePath+"ralph",{"run":basePath+"ralph-run",
                                  "walk":basePath+"ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(self.ralphStartPos)
        self.ralph.hide()                    

    def loadNextMusic(self, task):
        # random load background music
        if (self.music.status()!=self.music.PLAYING):
            # not playing
            self.musicCounter += 1
            index = self.musicCounter % len(_BGMUSIC)
            self.music = load_bgmusic(_BGMUSIC[index])
            self.music.play()
        return task.cont
        
    def keyControl(self):
        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("w",self.setKey,["upward",1])
        self.accept("w-up",self.setKey,["upward",0])
        self.accept("s",self.setKey,["downward",1])
        self.accept("s-up",self.setKey,["downward",0])
        self.accept("t", self.toggleMusic)
        self.accept("u", self.changeVolume, ['u'])
        self.accept("d", self.changeVolume, ['d'])
        self.accept("h", self.hideInstructions)

    def changeVolume(self, direction):
        if direction == 'u' and self.volume < 1:
            self.volume += 0.05
        else: # direction == 'd'
            if self.volume > 0:
                self.volume -= 0.05
        self.music.setVolume(self.volume)
            
    def toggleMusic(self):
        self.music.stop()
        self.musicCounter += 1 # increment the counter by 
        index = self.musicCounter % len(_BGMUSIC)
        self.music = load_bgmusic(_BGMUSIC[index])
        self.music.play()
        
    def displayInformation(self):
        self.title = addTitle("My Pokemon - Roam Mode")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[Arrow Keys]: Move")
        self.inst3 = addInstructions(0.85, "[w]: look up")
        self.inst4 = addInstructions(0.80, "[s]: look down")
        self.inst5 = addInstructions(0.75, "[t]: toggle next song")
        self.inst6 = addInstructions(0.70, "[u]: volume up")
        self.inst7 = addInstructions(0.65, "[d]: volume down")
        self.inst8 = addInstructions(0.60, "[h]: hide/show instructions")
        self.insts = [self.title, self.inst1, self.inst2, self.inst3,
                      self.inst4, self.inst5, self.inst6, self.inst7,
                      self.inst8]

    def hideInstructions(self):
        if self.instStatus == "show":
            self.instStatus = "hide"
            groupHide(self.insts)
        else: # instructions are hidden
            self.instStatus = "show"
            groupShow(self.insts)
        
    def __init__(self):
        base.enableParticles()
        self.keyMap = {"left":0, "right":0, "forward":0,"backward":0,
                       "upward":0, "downward":0, "leftward":0,"rightward":0,
                       "cam-left":0, "cam-right":0}
        _GOLD_PARTICLES.start(parent=render, renderParent=render)
        _GOLD_PARTICLES.setScale(200)
        self.instStatus = "show"
        self.musicCounter = 0
        self.music = load_bgmusic(_BGMUSIC[0])
        # self.music.play()
        self.volume = 0
        self.music.setVolume(self.volume)
        base.win.setClearColor(Vec4(0,0,0,1))
        self.above = 3.0
        # load environment
        self.loadEnviron()
        # load ralph
        self.loadRalph()
        # load sky box
        self.skyBoxLoad()
        # load pokemon
        self.loadPokemon()

        self.displayInformation()
        self.keyControl()
        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)
        taskMgr.add(self.move,"moveTask")
        taskMgr.add(self.setAbove,"setAbove")
        taskMgr.add(self.loadNextMusic, "loadRandomMusic")
        taskMgr.add(self.gold, "gold")
        # Game state variables
        self.isMoving = False
        # Set up the camera
        base.disableMouse()
        base.camera.setPos(self.ralph.getX(),self.ralph.getY(),2)
        self.cTrav = CollisionTraverser()
        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,1000)
        self.ralphGroundRay.setDirection(0,0,-1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.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,1000)
        self.camGroundRay.setDirection(0,0,-1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.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(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def setAbove(self,task):
        if self.keyMap["upward"] == 1:
            self.above += 0.1
        if self.keyMap["downward"] == 1:
            self.above -= 0.1
        return task.cont
    #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):

        # 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"]!=0):
            self.ralph.setH(self.ralph.getH() + 113 * globalClock.getDt())
            base.camera.setX(base.camera, +20 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 113 * globalClock.getDt())
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -75 * globalClock.getDt())
        if (self.keyMap["backward"] != 0):
            pass
            #self.ralph.setY(self.ralph, 75 * globalClock.getDt())
        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0):# or (self.keyMap["backward"]!=0):
            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() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec*(5-camdist))
            camdist = 5.0

        # Now check for collisions.

        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 = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     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 = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.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.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + self.above)#self.above)
        
        base.camera.lookAt(self.floater)
        return task.cont
Ejemplo n.º 47
0
class Collision():
    def __init__(self, ui):

        self.ui = ui

        # Most times, you want collisions to be tested against invisible geometry
        # rather than every polygon. This is because testing against every polygon
        # in the scene is usually too slow. You can have simplified or approximate
        # geometry for the solids and still get good results.
        #
        # Sometimes you'll want to create and position your own collision solids in
        # code, but it's often easier to have them built automatically. This can be
        # done by adding special tags into an egg file. Check maze.egg and ball.egg
        # and look for lines starting with <Collide>. The part is brackets tells
        # Panda exactly what to do. Polyset means to use the polygons in that group
        # as solids, while Sphere tells panda to make a collision sphere around them
        # Keep means to keep the polygons in the group as visable geometry (good
        # for the ball, not for the triggers), and descend means to make sure that
        # the settings are applied to any subgroups.
        #
        # Once we have the collision tags in the models, we can get to them using
        # NodePath's find command

        # Find the collision node named wall_collide
        self.walls = self.ui.maze.find("**/wall_collide")

        # Collision objects are sorted using BitMasks. BitMasks are ordinary numbers
        # with extra methods for working with them as binary bits. Every collision
        # solid has both a from mask and an into mask. Before Panda tests two
        # objects, it checks to make sure that the from and into collision masks
        # have at least one bit in common. That way things that shouldn't interact
        # won't. Normal model nodes have collision masks as well. By default they
        # are set to bit 20. If you want to collide against actual visable polygons,
        # set a from collide mask to include bit 20
        #
        # For this example, we will make everything we want the ball to collide with
        # include bit 0
        self.walls.node().setIntoCollideMask(BitMask32.bit(0))
        # CollisionNodes are usually invisible but can be shown. Uncomment the next
        # line to see the collision walls
        # self.walls.show()

        # We will now find the triggers for the holes and set their masks to 0 as
        # well. We also set their names to make them easier to identify during
        # collisions
        self.loseTriggers = []
        for i in range(6):
            trigger = self.ui.maze.find("**/hole_collide" + str(i))
            trigger.node().setIntoCollideMask(BitMask32.bit(0))
            trigger.node().setName("loseTrigger")
            self.loseTriggers.append(trigger)
            # Uncomment this line to see the triggers
            # trigger.show()

        # Ground_collide is a single polygon on the same plane as the ground in the
        # maze. We will use a ray to collide with it so that we will know exactly
        # what height to put the ball at every frame. Since this is not something
        # that we want the ball itself to collide with, it has a different
        # bitmask.
        self.mazeGround = self.ui.maze.find("**/ground_collide")
        self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1))

        # Find the collison sphere for the ball which was created in the egg file
        # Notice that it has a from collision mask of bit 0, and an into collison
        # mask of no bits. This means that the ball can only cause collisions, not
        # be collided into
        self.ballSphere = self.ui.ball.find("**/ball")
        self.ballSphere.node().setFromCollideMask(BitMask32.bit(0))
        self.ballSphere.node().setIntoCollideMask(BitMask32.allOff())

        # No we create a ray to start above the ball and cast down. This is to
        # Determine the height the ball should be at and the angle the floor is
        # tilting. We could have used the sphere around the ball itself, but it
        # would not be as reliable
        self.ballGroundRay = CollisionRay()  # Create the ray
        self.ballGroundRay.setOrigin(0, 0, 10)  # Set its origin
        self.ballGroundRay.setDirection(0, 0, -1)  # And its direction
        # Collision solids go in CollisionNode
        self.ballGroundCol = CollisionNode(
            'groundRay')  # Create and name the node
        self.ballGroundCol.addSolid(self.ballGroundRay)  # Add the ray
        self.ballGroundCol.setFromCollideMask(
            BitMask32.bit(1))  # Set its bitmasks
        self.ballGroundCol.setIntoCollideMask(BitMask32.allOff())
        # Attach the node to the ballRoot so that the ray is relative to the ball
        # (it will always be 10 feet over the ball and point down)
        self.ballGroundColNp = self.ui.ballRoot.attachNewNode(
            self.ballGroundCol)
        # Uncomment this line to see the ray
        # self.ballGroundColNp.show()

        # Finally, we create a CollisionTraverser. CollisionTraversers are what
        # do the job of calculating collisions
        self.cTrav = CollisionTraverser()
        # Collision traverservs tell collision handlers about collisions, and then
        # the handler decides what to do with the information. We are using a
        # CollisionHandlerQueue, which simply creates a list of all of the
        # collisions in a given pass. There are more sophisticated handlers like
        # one that sends events and another that tries to keep collided objects
        # apart, but the results are often better with a simple queue
        self.cHandler = CollisionHandlerQueue()
        # Now we add the collision nodes that can create a collision to the
        # traverser. The traverser will compare these to all others nodes in the
        # scene. There is a limit of 32 CollisionNodes per traverser
        # We add the collider, and the handler to use as a pair
        self.cTrav.addCollider(self.ballSphere, self.cHandler)
        self.cTrav.addCollider(self.ballGroundColNp, self.cHandler)
Ejemplo n.º 48
0
class World(DirectObject):
    mySound = base.loader.loadSfx("trial.mp3")

    #Used for adding a virus at a randomly generated position
    def random_vgen(self):
        print 'I am in random'
        for i in range(0, 5):

            self.a[random.randint(0, 7)][random.randint(0, 7)] = 1

    def initializer(self, level):

        self.turns = 0

        ##   Level Definition

        def levelone():
            self.a[4][4] = 1
            self.a[4][5] = 1
            self.a[4][6] = 1
            self.a[5][2] = 1
            self.a[3][5] = 1
            self.a[4][6] = 1
            self.a[5][5] = 1

        def leveltwo():
            self.a[4][3] = 1
            self.a[4][5] = 1
            self.a[4][7] = 1
            self.a[5][2] = 1
            self.a[3][5] = 1
            self.a[2][2] = 1
            self.a[5][3] = 1
            self.a[1][2] = 1

        def levelthree():
            self.a[4][4] = 1
            self.a[4][5] = 1
            self.a[4][6] = 1
            self.a[5][2] = 1
            self.a[3][5] = 1
            self.a[4][6] = 1
            self.a[5][5] = 1
            self.a[4][3] = 1
            self.a[4][5] = 1
            self.a[4][7] = 1
            self.a[5][2] = 1
            self.a[3][5] = 1
            self.a[2][2] = 1
            self.a[5][3] = 1

        options = {1: levelone, 2: leveltwo, 3: levelthree}

        options[level]()

        print self.a
        temp = []
        count = 0
        for element in reversed(self.a):
            for ele in element:
                #print 'cheking element is 1 : ' + str(ele)
                if ele == 1:
                    temp.append(count)
                    self.pieces[count] = Monster(count, WHITE)
                    #self.squares[count].setColor(HIGHLIGHT)
                count = count + 1
        self.list = temp

    def showscore(self):
        try:
            self.score.destroy()
        except:
            pass
        self.score = OnscreenText(text='Number of Turns : %s' % (self.turns),
                                  pos=(0.5, 0.95),
                                  scale=0.07,
                                  mayChange=True)

    def menuscreen(self):

        # Callback function to set  text
        def setText():
            b.destroy()
            helptext.destroy()

        # Add button
        b = DirectButton(text=("START", "START", "START", "disabled"),
                         scale=0.15,
                         command=setText,
                         pos=(0, 0, 0.85))

        helptext = OnscreenText(text='''
    STORY:
    Hello Mad Scientist!
    You are so close to finding the cure to aids!
    You understood the behaviour and can finally manipulate the virus to kill itself!
    But time is running out!
    You have a red and white blood cell sample infected with AIDS Virus.

    INSTRUCTIONS:
    The AIDS Virus obeys the Conway's Game of Life. Who would have guessed?
    1.  If virus is surrounded by more than 3 viruses, it dies of suffocation
    2.  If virus is surrounded by less than 2 viruses, it dies of underpopulation
    3.  If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned due to breeding.

    AIM:
    To kill all the viruses, by moving one of them every turn.

    ''',
                                pos=(-0.90, 0.72),
                                frame=(123, 123, 123, 1),
                                wordwrap=25,
                                align=TextNode.ALeft,
                                bg=(0.23, 0.243, 0.13, 0.9))

    def endscreen(self):
        def restart():
            taskMgr.remove(self.mouseTask)
            for i in range(64):
                self.squares[i].setColor(SquareColor(i))
            scorecard.destroy()
            restartb.destroy()
            end.destroy()
            nextlevelb.destroy()
            self.reference.destroy()
            self.mySound.stop()
            try:
                self.score.destroy()
            except:
                pass
            print 'restarting'
            print self.a
            print self.list

            World()

        def quitgame():
            sys.exit()

        def nextLevel():
            self.currlevel = self.currlevel + 1
            nextlevelb.destroy()
            scorecard.destroy()
            restartb.destroy()
            end.destroy()
            self.score.destroy()
            self.initializer(self.currlevel)

        # Add button

        scorecard = OnscreenText(text='You finished it in %s turns! ' %
                                 (self.turns),
                                 frame=(123, 123, 123, 0),
                                 wordwrap=25,
                                 bg=(0.2, 0, 0.8, 1))

        nextlevelb = DirectButton(text=("NEXT LEVEL", "NEXT LEVEL",
                                        "NEXT LEVEL", "disabled"),
                                  scale=0.15,
                                  command=nextLevel,
                                  pos=(0, 0, -0.15))
        restartb = DirectButton(text=("RESTART", "RESTART", "RESTART",
                                      "disabled"),
                                scale=0.15,
                                command=restart,
                                pos=(0, 0, -0.35))
        end = DirectButton(text=("QUIT", "QUIT", "QUIT", "disabled"),
                           scale=0.15,
                           command=quitgame,
                           pos=(0, 0, -0.55))
        if self.currlevel == self.maxlevel:
            nextlevelb.destroy()

    def __init__(self):
        #music

        self.mySound.play()

        print 'I am being initialized'

        self.menuscreen()
        self.list = []
        self.turns = 0
        self.maxlevel = 3
        self.currlevel = 1
        self.a = [[0 for x in range(8)] for y in range(8)]

        #This code puts the standard title and instruction text on screen
        self.title = OnscreenText(text="Game of Life : Help in ending AIDS!",
                                  style=1,
                                  fg=(1, 1, 1, 1),
                                  pos=(0, -0.95),
                                  scale=.07)
        self.escapeEvent = OnscreenText(text="ESC: Quit",
                                        style=1,
                                        fg=(1, 1, 1, 1),
                                        pos=(-1.3, 0.95),
                                        align=TextNode.ALeft,
                                        scale=.05)
        ##    self.mouse1Event = OnscreenText(
        ##      text="Left-click and drag: Pick up virus and drag it to a new bloodcell",
        ##      style=1, fg=(1,1,1,1), pos=(-1.3, 0.90),
        ##      align=TextNode.ALeft, scale = .05)
        ##

        self.accept('escape', sys.exit)  #Escape quits

        base.disableMouse()  #Disble mouse camera control
        camera.setPosHpr(0, -13.75, 6, 0, -25, 0)  #Set the camera
        self.setupLights()  #Setup default lighting

        #Since we are using collision detection to do picking, we set it up like
        #any other collision detection system with a traverser and a handler
        self.picker = CollisionTraverser()  #Make a traverser
        self.pq = CollisionHandlerQueue()  #Make a handler
        #Make a collision node for our picker ray
        self.pickerNode = CollisionNode('mouseRay')
        #Attach that node to the camera since the ray will need to be positioned
        #relative to it
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        #Everything to be picked will use bit 1. This way if we were doing other
        #collision we could seperate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()  #Make our ray
        self.pickerNode.addSolid(self.pickerRay)  #Add it to the collision node
        #Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.pq)
        #self.picker.showCollisions(render)

        #We will attach all of the squares to their own root. This way we can do the
        #collision pass just on the sqaures and save the time of checking the rest
        #of the scene
        self.squareRoot = render.attachNewNode("squareRoot")

        #For each square
        self.squares = [None for i in range(64)]
        self.pieces = [None for i in range(64)]

        for i in range(64):
            #Load, parent, color, and position the model (a single square polygon)
            self.squares[i] = loader.loadModel("models/square")
            self.squares[i].reparentTo(self.squareRoot)
            self.squares[i].setPos(SquarePos1(i))
            self.squares[i].setColor(SquareColor(i))
            #Set the model itself to be collideable with the ray. If this model was
            #any more complex than a single polygon, you should set up a collision
            #sphere around it instead. But for single polygons this works fine.
            self.squares[i].find("**/polygon").node().setIntoCollideMask(
                BitMask32.bit(1))
            #Set a tag on the square's node so we can look up what square this is
            #later during the collision pass
            self.squares[i].find("**/polygon").node().setTag('square', str(i))

            #We will use this variable as a pointer to whatever piece is currently
            #in this square

        self.initializer(self.currlevel)

        #This will represent the index of the currently highlited square
        self.hiSq = False
        #This wil represent the index of the square where currently dragged piece
        #was grabbed from
        self.dragging = False

        #Start the task that handles the picking
        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')
        #self.trial = taskMgr.add(self.trial,'trial')
        self.accept("mouse1", self.grabPiece)  #left-click grabs a piece
        self.accept("mouse1-up", self.releasePiece)  #releasing places it

    #This function swaps the positions of two pieces
    def swapPieces(self, fr, to):
        temp = self.pieces[fr]
        self.pieces[fr] = self.pieces[to]
        self.pieces[to] = temp
        if self.pieces[fr]:
            print 'imma swapping'
            self.pieces[fr].square = fr
            print fr
            print SquarePos(fr)
            try:
                self.pieces[fr].obj.setPos(SquarePos(fr))
            except:
                pass
            print 'done'
        if self.pieces[to]:
            self.pieces[to].square = to
            try:
                self.pieces[to].obj.setPos(SquarePos(to))
            except:
                pass

    def trial(self):
        self.turns = self.turns + 1
        try:
            self.reference.destroy()
        except:
            pass
        self.reference = OnscreenText(text='''
Reference:
virus is surrounded by more than 3 viruses, it dies
virus is surrounded by less than 2 viruses, it dies
If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned.
''',
                                      style=1,
                                      fg=(1, 1, 1, 1),
                                      pos=(-1, 0.95),
                                      align=TextNode.ALeft,
                                      scale=.05)

        self.showscore()
        a = self.a
        while True:
            for i in self.list:
                #insert deletion code
                print 'imma deleting the sq : ' + str(i)
                self.pieces[i].obj.delete()

                self.squares[i].setColor(SquareColor(i))
            count = 0
            a = [[([[
                sum(b[y1][x1]
                    for b in [[[(
                        (-1 < x2 + dx < len(a[0])) and
                        (-1 < y2 + dy < len(a))) and a[y2 + dy][x2 + dx] or 0
                                for x2 in range(len(a[0]))]
                               for y2 in range(len(a))]
                              for (dx, dy) in [(dx, dy) for dx in [-1, 0, 1]
                                               for dy in [-1, 0, 1] if
                                               (dy != 0 or dx != 0)]])
                for x1 in range(len(a[0]))
            ] for y1 in range(len(a))][y][x] == 3 or ([[
                sum(c[y3][x3]
                    for c in [[[(
                        (-1 < x4 + dx < len(a[0])) and
                        (-1 < y4 + dy < len(a))) and a[y4 + dy][x4 + dx] or 0
                                for x4 in range(len(a[0]))]
                               for y4 in range(len(a))]
                              for (dx, dy) in [(dx, dy) for dx in [-1, 0, 1]
                                               for dy in [-1, 0, 1] if
                                               (dy != 0 or dx != 0)]])
                for x3 in range(len(a[0]))
            ] for y3 in range(len(a))][y][x] == 2 and a[y][x] == 1)) and 1 or 0
                  for x in range(len(a[0]))] for y in range(len(a))]
            lis = []
            #insert a random virus at a probability of 1/5
            diceroll = random.randint(0, 5)
            if diceroll == 2:

                self.random_vgen()
            for element in reversed(a):

                for ele in element:
                    #print 'cheking element is 1 : ' + str(ele)
                    if ele == 1:
                        lis.append(count)
                    count = count + 1
            print lis
            self.list = lis

            self.a = a
            print self.list

            for i in self.list:
                self.pieces[i] = Monster(i, WHITE)
                #self.squares[i].setColor(HIGHLIGHT)
            print 'leaving trial'
            if len(self.list) == 0:
                self.endscreen()
            break

        return

    def mouseTask(self, task):
        #This task deals with the highlighting and dragging based on the mouse

        #First, clear the current highlight
        if self.hiSq is not False:
            self.squares[self.hiSq].setColor(SquareColor(self.hiSq))
            self.hiSq = False

        #Check to see if we can access the mouse. We need it to do anything else
        if base.mouseWatcherNode.hasMouse():
            #get the mouse position
            mpos = base.mouseWatcherNode.getMouse()

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

            #If we are dragging something, set the position of the object
            #to be at the appropriate point over the plane of the board
            if self.dragging is not False:
                #Gets the point described by pickerRay.getOrigin(), which is relative to
                #camera, relative instead to render
                nearPoint = render.getRelativePoint(camera,
                                                    self.pickerRay.getOrigin())
                #Same thing with the direction of the ray
                nearVec = render.getRelativeVector(
                    camera, self.pickerRay.getDirection())
                try:
                    self.pieces[self.dragging].obj.setPos(
                        PointAtZ(.5, nearPoint, nearVec))
                except:
                    pass
            #Do the actual collision pass (Do it only on the squares for
            #efficiency purposes)
            self.picker.traverse(self.squareRoot)
            if self.pq.getNumEntries() > 0:
                #if we have hit something, sort the hits so that the closest
                #is first, and highlight that node
                self.pq.sortEntries()
                i = int(self.pq.getEntry(0).getIntoNode().getTag('square'))
                #Set the highlight on the picked square
                self.squares[i].setColor(HIGHLIGHT)
                self.hiSq = i
                #print 'selected is ' + str(i)

        return Task.cont

    def grabPiece(self):
        #If a square is highlighted and it has a piece, set it to dragging mode
        if (self.hiSq is not False and self.pieces[self.hiSq]):
            self.dragging = self.hiSq
            self.hiSq = False

    def releasePiece(self):
        #Letting go of a piece. If we are not on a square, return it to its original
        #position. Otherwise, swap it with the piece in the new square
        if self.dragging is not False:  #Make sure we really are dragging something
            #We have let go of the piece, but we are not on a square
            if self.hiSq is False:
                try:
                    self.pieces[self.dragging].obj.setPos(
                        SquarePos(self.dragging))
                except:
                    pass
            else:
                #Otherwise, swap the pieces
                self.swapPieces(self.dragging, self.hiSq)
                #self.draggin is the from
                print self.list
                print 'you picked this, so Imma deleting this ' + str(
                    self.dragging)
                #deletion of i after picking it up.
                try:
                    self.list.remove(self.dragging)
                except:
                    pass
                temp2 = []
                temp2 = SquarePosTuple(self.dragging)
                self.a[temp2[0]][temp2[1]] = 0

                i = self.hiSq
                print self.list
                print 'highlighted sq is ' + str(i)
                templis = []
                templis = SquarePosTuple(i)
                print templis
                self.list.append(i)
                print self.list
                print templis
                self.a[templis[0]][templis[1]] = 1

                for line in self.a:
                    print line
                self.trial()

        #We are no longer dragging anything
        self.dragging = False

    def setupLights(self):  #This function sets up some default lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.8, .8, .8, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0, 45, -45))
        directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(ambientLight))
class GameEngine( DirectObject ):
    def __init__(self):
        print 'Game Engine Started'
        self.lastBlock = 0
        self.map = []
        self.startBlock = 0
        self.endBlock = 0
        self.mapName = 'test2'
        
        self.loadEnvironment(self.mapName)
        self.loadCursorPicker()
        self.camera = RTS_Camera()
        self.loadSimpleLighting()
        
        self.waveController = WaveController(self.mapName, self.startBlock, self.map)
        self.towerController = TowerController(self.waveController)
        
        self.setupKeyListeners()
        self.EFT = taskMgr.add(self.everyFrameTask, "everyFrameTask")
        
    # The task that is run every frame
    def everyFrameTask(self, task):
        self.camera.handleMouseInput()
        self.checkCursorCollision()
        self.towerController.updateTowers()
        
        return task.cont
    
    # Loads the level from the text file. Puts each
    # row into an array then creates the rows in the
    # 1st quadrant
    def loadEnvironment(self, file):
        fileName = 'maps/' + file + '.map'
        rows = []
        self.environmentRoot = render.attachNewNode('environmentRoot')
        
        FILE = open(fileName, 'r')
        while( 1 ):
            line = FILE.readline()
            if( not line ):
                break
            print line,
            if( line[-1] == '\n' ):
                line = line[:-1]
            rows.append(line)
            
        rows.reverse()
        for i, row in enumerate(rows):
            self.createRow( i, row )
            
    # Loads the models corresponding to the
    # characters in the map file for an entire row
    def createRow(self, rowIndex, row):
        mapRow = []
        
        for colIndex, block in enumerate(row):
            block = BLOCK_CHAR_TO_MODEL[block]( self.environmentRoot, colIndex + 0.5, rowIndex + 0.5 )
            mapRow.append( block )
            block.setIndex( str(rowIndex) + ' ' + str(colIndex) )
            
            if( block.isType(StartBlock) ):
                self.startBlock = block
            elif( block.isType(EndBlock) ):
                self.endBlock = block
                
        self.map.append(mapRow)
            
    # Creates necessary collision parts to determine what object
    # the cursor is hovering
    def loadCursorPicker(self):
        self.picker = CollisionTraverser()
        self.pq     = CollisionHandlerQueue()
        self.pickerNode = CollisionNode('mouseRay')
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        self.picker.addCollider(self.pickerNP, self.pq)
        
    def checkCursorCollision(self):
        if base.mouseWatcherNode.hasMouse():
              mpos = base.mouseWatcherNode.getMouse()
              self.pickerRay.setFromLens( base.camNode, mpos.getX(), mpos.getY() )
              
        self.picker.traverse( self.environmentRoot )
        if( self.pq.getNumEntries() > 0 ):
            self.pq.sortEntries()
            (row, ignore, col) = self.pq.getEntry(0).getIntoNode().getTag('index').partition(' ')
            row = int(row)
            col = int(col)
            block = self.map[row][col]
            if( block != self.lastBlock ):
                block.highlight()
                if( self.lastBlock ):
                    self.lastBlock.unHighlight()
            self.lastBlock = block
        else:
            if( self.lastBlock ):
                self.lastBlock.unHighlight()
                self.lastBlock = 0
            
    def mouseClick(self):
        if( self.lastBlock ):
            self.towerController.addTower(self.lastBlock)
            
    def spawnEnemy(self):
        e = Enemy(self.startBlock, self.map)
        e.moveToEnd()
        
    def setTowerType(self, type):
        self.towerController.currentTowerType = type
    
    def setupKeyListeners(self):
        self.accept('mouse1', self.mouseClick)
        self.accept('q', self.waveController.start)
        
        self.accept('1', self.setTowerType, [NormalTower])
        self.accept('2', self.setTowerType, [SlowTower])
        self.accept('3', self.setTowerType, [StunTower])
            
    def loadSimpleLighting(self):
        ambientLight = AmbientLight( "ambientLight" )
        ambientLight.setColor( Vec4(.8, .8, .8, 1) )
        directionalLight = DirectionalLight( "directionalLight" )
        directionalLight.setDirection( Vec3( 0, 45, -45 ) )
        directionalLight.setColor( Vec4( 0.2, 0.2, 0.2, 0.6 ) )
        render.setLight(render.attachNewNode( directionalLight ) )
        render.setLight(render.attachNewNode( ambientLight ) )
Ejemplo n.º 50
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
Ejemplo n.º 51
0
class GameContainer(ShowBase):

    def __init__(self):

        ShowBase.__init__(self)

        ########## Window configuration #########

        wp = WindowProperties()
        wp.setSize(1024, 860)

        self.win.requestProperties(wp)

        ########## Gameplay settings #########

        self.GAME_MODE = PLAY
        self.play_mode = SPACE

        self.level = 1.5

        self.mode_initialized = False

        ######### Camera #########

        self.disableMouse()

        self.mainCamera = Camera(self.camera)

        self.mainCamera.camObject.setHpr(0, 0, 0)

        #Trigger game chain

        self.loadLevel(LEVEL)

        ######### Events #########

        self.taskMgr.add(self.gameLoop, "gameLoop", priority = 35)

        self.keys = {"w" : 0, "s" : 0, "a" : 0, "d" : 0, "space" : 0}

        self.accept("w", self.setKey, ["w", 1])
        self.accept("w-up", self.setKey, ["w", 0])
        self.accept("s", self.setKey, ["s", 1])
        self.accept("s-up", self.setKey, ["s", 0])
        self.accept("a", self.setKey, ["a", 1])
        self.accept("a-up", self.setKey, ["a", 0])
        self.accept("d", self.setKey, ["d", 1])
        self.accept("d-up", self.setKey, ["d", 0])
        self.accept("space", self.setKey, ["space", 1])
        self.accept("space-up", self.setKey, ["space", 0])
        self.accept("wheel_up", self.zoomCamera, [-1])
        self.accept("wheel_down", self.zoomCamera, [1])
        self.accept("escape", self.switchGameMode, [IN_GAME_MENU])

        self.accept("window-event", self.handleWindowEvent)

        self.accept("playerGroundRayJumping-in", self.avatar.handleCollisionEvent, ["in"])
        self.accept("playerGroundRayJumping-out", self.avatar.handleCollisionEvent, ["out"])

        ######### GUI #########

        self.gui_elements = []

    def loadSpaceTexture(self, level):

        if level < 10: return 'textures/space#.jpg'
        elif level < 15: pass  

    def loadLevel(self, level):

        #Resets

        self.avatarActor = Actor("models/panda",
                                {"walk": "models/panda-walk"})
        self.avatarActor.setScale(.5, .5, .5)
        self.avatarActor.setHpr(180, 0, 0)
        self.avatarActor.setCollideMask(BitMask32.allOff())

        self.asteroidManager = AsteroidManager()

        #Alternate modes

        if int(self.level) == self.level: self.play_mode = TERRAIN

        else: self.play_mode = SPACE

        #Specifics

        if self.play_mode == SPACE:

            self.avatar = Avatar(self.avatarActor)
            self.avatar.objectNP.reparentTo(render)

            ########## Sky #########

            cubeMap = loader.loadCubeMap(self.loadSpaceTexture(self.level))
            self.spaceSkyBox = loader.loadModel('models/box')

            self.spaceSkyBox.setScale(100)
            self.spaceSkyBox.setBin('background', 0)
            self.spaceSkyBox.setDepthWrite(0)
            self.spaceSkyBox.setTwoSided(True)
            self.spaceSkyBox.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldCubeMap)
            self.spaceSkyBox.setTexture(cubeMap, 1)
            #self.spaceSkyBox.setEffect(CompassEffect.make(render))

            parentNP = render.attachNewNode('parent')

            self.spaceSkyBox.reparentTo(parentNP)
            self.spaceSkyBox.setPos(-self.spaceSkyBox.getSx()/2, -self.spaceSkyBox.getSy()/2, 
                                    -self.spaceSkyBox.getSz()/2)

            self.asteroidManager.initialize(self.level)

        elif self.play_mode == TERRAIN:

            ########## Terrain #########

            #self.environ = loader.loadModel("../mystuff/test.egg")
            self.environ = loader.loadModel("models/environment")
            self.environ.setName("terrain")
            self.environ.reparentTo(render)
            self.environ.setPos(0, 0, 0)
            self.environ.setCollideMask(BitMask32.bit(0))

            ######### Models #########

            ######### Physics #########

            base.enableParticles()

            gravityForce = LinearVectorForce(0, 0, -9.81)
            gravityForce.setMassDependent(False)
            gravityFN = ForceNode("world-forces")
            gravityFN.addForce(gravityForce)
            render.attachNewNode(gravityFN)
            base.physicsMgr.addLinearForce(gravityForce)

            self.avatarPhysicsActorNP = render.attachNewNode(ActorNode("player"))
            self.avatarPhysicsActorNP.node().getPhysicsObject().setMass(50.)
            self.avatarActor.reparentTo(self.avatarPhysicsActorNP)
            base.physicsMgr.attachPhysicalNode(self.avatarPhysicsActorNP.node())

            self.avatarPhysicsActorNP.setPos(15, 10, 5)

            ######### Game objects #########

            self.avatar = Avatar(self.avatarPhysicsActorNP)

            ######### Collisions #########

            self.cTrav = CollisionTraverser()

            #Make player rigid body

            self.pandaBodySphere = CollisionSphere(0, 0, 4, 3)

            self.pandaBodySphereNode = CollisionNode("playerBodyRay")
            self.pandaBodySphereNode.addSolid(self.pandaBodySphere)
            self.pandaBodySphereNode.setFromCollideMask(BitMask32.bit(0))
            self.pandaBodySphereNode.setIntoCollideMask(BitMask32.allOff())

            self.pandaBodySphereNodepath = self.avatar.objectNP.attachNewNode(self.pandaBodySphereNode)
            self.pandaBodySphereNodepath.show()

            self.pandaBodyCollisionHandler = PhysicsCollisionHandler()
            self.pandaBodyCollisionHandler.addCollider(self.pandaBodySphereNodepath, self.avatar.objectNP)

            #Keep player on ground

            self.pandaGroundSphere = CollisionSphere(0, 0, 1, 1)

            self.pandaGroundSphereNode = CollisionNode("playerGroundRay")
            self.pandaGroundSphereNode.addSolid(self.pandaGroundSphere)
            self.pandaGroundSphereNode.setFromCollideMask(BitMask32.bit(0))
            self.pandaGroundSphereNode.setIntoCollideMask(BitMask32.allOff())

            self.pandaGroundSphereNodepath = self.avatar.objectNP.attachNewNode(self.pandaGroundSphereNode)
            self.pandaGroundSphereNodepath.show()

            self.pandaGroundCollisionHandler = PhysicsCollisionHandler()
            self.pandaGroundCollisionHandler.addCollider(self.pandaGroundSphereNodepath, self.avatar.objectNP)

            #Notify when player lands

            self.pandaGroundRayJumping = CollisionSphere(0, 0, 1, 1)

            self.pandaGroundRayNodeJumping = CollisionNode("playerGroundRayJumping")
            self.pandaGroundRayNodeJumping.addSolid(self.pandaGroundRayJumping)
            self.pandaGroundRayNodeJumping.setFromCollideMask(BitMask32.bit(0))
            self.pandaGroundRayNodeJumping.setIntoCollideMask(BitMask32.allOff())

            self.pandaGroundRayNodepathJumping = self.avatar.objectNP.attachNewNode(self.pandaGroundRayNodeJumping)
            self.pandaGroundRayNodepathJumping.show()

            self.collisionNotifier = CollisionHandlerEvent()
            self.collisionNotifier.addInPattern("%fn-in")
            self.collisionNotifier.addOutPattern("%fn-out")

            self.cTrav.addCollider(self.pandaGroundSphereNodepath, self.pandaGroundCollisionHandler)
            self.cTrav.addCollider(self.pandaGroundRayNodepathJumping, self.collisionNotifier)
            self.cTrav.addCollider(self.pandaBodySphereNodepath, self.pandaBodyCollisionHandler)

    def maintainTurrets(self):

        pass

    def setKey(self, key, value):

        self.keys[key] = value

    def zoomCamera(self, direction):

        Camera.AVATAR_DIST += direction

    def b(self, hey):

        self.avatarLanded = True

    def handleWindowEvent(self, window=None):

        wp = window.getProperties()

        self.win_center_x = wp.getXSize() / 2
        self.win_center_y = wp.getYSize() / 2

    def switchGameMode(self, newGameMode=None):

        self.cleanupGUI()

        if self.GAME_MODE == IN_GAME_MENU: 

            if newGameMode == PLAY:

                render.clearFog()

            elif newGameMode == MAIN_MENU:

                pass

        elif True:

            pass

        self.GAME_MODE = newGameMode

        self.mode_initialized = False

    def cleanupGUI(self):

        for gui_element in self.gui_elements:

            gui_element.destroy()

    def evenButtonPositions(self, button_spacing, button_height, num_buttons):

        center_offset = (button_spacing/(2.0) if (num_buttons % 2 == 0) else 0)

        button_positions = []

        current_pos = center_offset + ((num_buttons - 1)/2) * button_spacing

        for i in range(0, num_buttons):

            button_positions.append(current_pos + (button_height/2.0))

            current_pos -= button_spacing

        return button_positions

    def buildInGameMenu(self):

        props = WindowProperties()
        props.setCursorHidden(False) 
        base.win.requestProperties(props)

        resume_button = DirectButton(text = "Resume", scale = .1, command = (lambda: self.switchGameMode(PLAY)),
                                    rolloverSound=None)

        main_menu_button = DirectButton(text = "Main Menu", scale = .1, command = self.b,
                                    rolloverSound=None)

        options_button = DirectButton(text = "Options", scale = .1, command = self.b,
                                    rolloverSound=None)

        exit_button = DirectButton(text = "Exit", scale = .1, command = exit,
                                    rolloverSound=None)

        BUTTON_SPACING = .2
        BUTTON_HEIGHT = resume_button.getSy()

        button_positions = self.evenButtonPositions(BUTTON_SPACING, BUTTON_HEIGHT, 4)

        resume_button.setPos(Vec3(0, 0, button_positions[0]))
        main_menu_button.setPos(Vec3(0, 0, button_positions[1]))
        options_button.setPos(Vec3(0, 0, button_positions[2]))
        exit_button.setPos(Vec3(0, 0, button_positions[3]))

        self.gui_elements.append(resume_button)
        self.gui_elements.append(main_menu_button)
        self.gui_elements.append(options_button)
        self.gui_elements.append(exit_button)

    def buildMainMenu(self):

        props = WindowProperties()
        props.setCursorHidden(False) 
        base.win.requestProperties(props)

        start_game_button = DirectButton(text = "Start", scale = .1,
                            command = self.b)

        select_level_button = DirectButton(text = "Select Level", scale = .1,
                            command = self.b)

        game_options_button = DirectButton(text = "Options", scale = .1,
                            command = self.b)

        exit_button = DirectButton(text = "Exit", scale = .1,
                            command = exit)

        BUTTON_SPACING = .2
        BUTTON_HEIGHT = start_game_button.getSy()

        button_positions = self.evenButtonPositions(BUTTON_SPACING, BUTTON_HEIGHT)

        start_game_button.setPos(Vec3(0, 0, button_positions[0]))
        select_level_button.setPos(Vec3(0, 0, button_positions[1]))
        game_options_button.setPos(Vec3(0, 0, button_positions[2]))
        exit_button.setPos(Vec3(0, 0, button_positions[3]))

        self.gui_elements.append(start_game_button)
        self.gui_elements.append(select_level_button)
        self.gui_elements.append(game_options_button)
        self.gui_elements.append(exit_button)

    def gameLoop(self, task):

        #Compensate for inconsistent update intervals

        dt = globalClock.getDt()

        if self.GAME_MODE == MAIN_MENU:

            if not self.mode_initialized:

                self.buildMainMenu()

                self.mode_initialized = True

        if self.GAME_MODE == IN_GAME_MENU:

            if not self.mode_initialized:

                #Fog out background

                inGameMenuFogColor = (50, 150, 50)

                inGameMenuFog = Fog("inGameMenuFog")

                inGameMenuFog.setMode(Fog.MExponential)
                inGameMenuFog.setColor(*inGameMenuFogColor)
                inGameMenuFog.setExpDensity(.01)

                render.setFog(inGameMenuFog)

                self.buildInGameMenu()

                self.mode_initialized = True

        if self.GAME_MODE == PLAY:

            if not self.mode_initialized:

                props = WindowProperties()
                props.setCursorHidden(True) 
                base.win.requestProperties(props)

                self.last_mouse_x = self.win.getPointer(0).getX()
                self.last_mouse_y = self.win.getPointer(0).getY()

                self.mode_initialized = True

            if self.play_mode == TERRAIN:

                self.maintainTurrets()
                self.avatar.move(dt)

            elif self.play_mode == SPACE:

                self.asteroidManager.maintainAsteroidField(self.avatar.objectNP.getPos(), 
                                                           self.avatar.speed, dt)

            #Handle keyboard input

            self.avatar.handleKeys(self.keys, self.play_mode)

            ########## Mouse-based viewpoint rotation ##########

            mouse_pos = self.win.getPointer(0)

            current_mouse_x = mouse_pos.getX()
            current_mouse_y = mouse_pos.getY()

            #Side to side

            if self.play_mode == TERRAIN:

                mouse_shift_x = current_mouse_x - self.last_mouse_x
                self.last_mouse_x = current_mouse_x

                if current_mouse_x < 5 or current_mouse_x >= (self.win_center_x * 1.5):

                    base.win.movePointer(0, self.win_center_x, current_mouse_y)
                    self.last_mouse_x = self.win_center_x

                yaw_shift = -((mouse_shift_x) * Camera.ROT_RATE[0])

                self.avatar.yawRot += yaw_shift

                self.avatar.objectNP.setH(self.avatar.yawRot)

            #Up and down

            mouse_shift_y = current_mouse_y - self.last_mouse_y
            self.last_mouse_y = current_mouse_y

            if current_mouse_y < 5 or current_mouse_y >= (self.win_center_y * 1.5):

                base.win.movePointer(0, current_mouse_x, self.win_center_y)
                self.last_mouse_y = self.win_center_y

            pitch_shift = -((mouse_shift_y) * Camera.ROT_RATE[1])

            self.mainCamera.pitchRot += pitch_shift

            if self.mainCamera.pitchRot > Camera.FLEX_ROT_MAG[0]:

                self.mainCamera.pitchRot = Camera.FLEX_ROT_MAG[0]

            elif self.mainCamera.pitchRot < -Camera.FLEX_ROT_MAG[0]:

                self.mainCamera.pitchRot = -Camera.FLEX_ROT_MAG[0]

            xy_plane_cam_dist = Camera.AVATAR_DIST

            cam_x_adjust = xy_plane_cam_dist*sin(radians(self.avatar.yawRot))  
            cam_y_adjust = xy_plane_cam_dist*cos(radians(self.avatar.yawRot))
            cam_z_adjust = Camera.ELEVATION

            self.mainCamera.camObject.setH(self.avatar.yawRot)
            self.mainCamera.camObject.setP(self.mainCamera.pitchRot)

            self.mainCamera.camObject.setPos(self.avatar.objectNP.getX() + cam_x_adjust, self.avatar.objectNP.getY() - cam_y_adjust, 
                            self.avatar.objectNP.getZ() + cam_z_adjust)

            #Find collisions

            #self.cTrav.traverse(render)

            #print self.environ.getBounds()

        return Task.cont
Ejemplo n.º 52
0
class Controller():
    # Конструктор
    def __init__(self):
        # значение шага перемещения клавиатурой
        self.key_step = 0.2
        # значение шага поворота мышкой
        self.mouse_step = 0.2

        # координаты центра экрана
        self.x_center = base.win.getXSize() // 2
        self.y_center = base.win.getYSize() // 2
        # перемещаем указатель мышки в центр экрана
        base.win.movePointer(0, self.x_center, self.y_center)
        # отключаем стандартное управление мышкой
        base.disableMouse()
        # устанавливаем поле зрения объектива
        base.camLens.setFov(80)
        # устанавливаем ближайшую границу отрисовки
        base.camLens.setNear(0.2)

        # устанавливаем текущие значения ориентации камеры
        self.heading = 0
        self.pitch = 0

        # запускаем задачу контроля камеры
        taskMgr.doMethodLater(0.02, self.controlCamera, "camera-task")
        # регистрируем на нажатие клавиши "Esc"
        # событие закрытия приложения
        base.accept("escape", base.userExit)

        # устанавливаем клавиши управления перемещением камеры
        # словарь, хранящий флаги нажатия клавиш
        self.keys = dict()
        # заполняем словарь
        for key in ['a', 'd', 'w', 's', 'q', 'e', 'space']:
            # создаём запись в словаре
            self.keys[key] = 0
            # регистрируем событие на нажатие клавиши
            base.accept(key, self.setKey, [key, 1])
            # регистрируем событие на отжатие клавиши
            base.accept(key + '-up', self.setKey, [key, 0])

        # создание обходчика столкновений
        self.traverser = CollisionTraverser()
        # очередь обработки столкновений
        self.collisQueue = CollisionHandlerQueue()
        # узел для сферы столкновений
        self.collisNode = CollisionNode('CameraSphere')
        # устанавливаем маску проверки столкновений ОТ
        self.collisNode.setFromCollideMask(BitMask32.bit(1))
        # сбрасываем маску проверки столкновений ДО
        self.collisNode.setIntoCollideMask(BitMask32.allOff())
        # создаём сферу столкновения радиусом 0.95
        collisSphere = CollisionSphere(0, 0, 0, 0.8)
        # и прикрепляем к созданному ранее узлу
        self.collisNode.addSolid(collisSphere)
        # закрепляем узел на камере
        self.collisCamNode = base.camera.attachNewNode(self.collisNode)
        # уведомляем обходчик о новом «объекте ОТ»
        self.traverser.addCollider(self.collisCamNode, self.collisQueue)

        # ускорение падения
        self.fall_acceleration = 0.015
        # величина силы прыжка
        self.jump_power = 0.21

        # скорость падения
        self.fall_speed = 0
        # флаг касания земли
        self.ground = False

        # режим редактирования
        self.edit_mode = True

        # устанавливаем режим редактирования
        self.setEditMode(self.edit_mode)

    # Метод установки режима редактирования
    def setEditMode(self, mode):
        self.edit_mode = mode

        if self.edit_mode:
            # значение шага перемещения клавиатурой
            self.key_step = 0.2
        else:
            # значение шага перемещения клавиатурой
            self.key_step = 0.2
            # скорость падения
            self.fall_speed = 0
            # флаг касания земли
            self.ground = False
            # поднимаем высоко камеру, чтобы избежать наложений
            #base.camera.setZ(20)

    # Метод установки состояния клавиши
    def setKey(self, key, value):
        self.keys[key] = value

    # Метод управления положением и ориентацией камеры
    def controlCamera(self, task):
        # если установлен режим редактирования
        if self.edit_mode:
            # рассчитываем смещения положения камеры по осям X Y Z
            move_x = self.key_step * (self.keys['d'] - self.keys['a'])
            move_y = self.key_step * (self.keys['w'] - self.keys['s'])
            move_z = self.key_step * (self.keys['e'] - self.keys['q'])

            # смещаем позицию камеры относительно предыдущего положения камеры
            base.camera.setPos(base.camera, move_x, move_y, move_z)
        # если установлен режим хождения
        else:
            # предыдущая позиция камеры
            old_pos = base.camera.getPos()

            # рассчитываем смещения положения камеры по осям X Y
            move_x = self.key_step * (self.keys['d'] - self.keys['a'])
            move_y = self.key_step * (self.keys['w'] - self.keys['s'])

            # сохраняем наклон камеры по вертикали
            pitch = base.camera.getP()
            # сбрасываем наклон в 0 - ходим прямо без наклона
            base.camera.setP(0)
            # смещаем позицию камеры относительно предыдущего положения камеры
            base.camera.setPos(base.camera, move_x, move_y, 0)
            # восстанавливаем наклон
            base.camera.setP(pitch)

            # если есть столкновения с блоками
            if self.collisionTest():
                # восстанавливаем старую позицию
                base.camera.setPos(old_pos)

            # предыдущая высота камеры
            old_z = base.camera.getZ()

            # если нажат пробел и есть касание земли
            if self.keys['space'] and self.ground:
                # прыгаем вверх - сильно уменьшаем скорость падения
                self.fall_speed = -self.jump_power
                # сбрасываем флаг касания земли
                self.ground = False

            # опускаем камеру под действием гравитации
            base.camera.setZ(old_z - self.fall_speed)

            # если есть касание блоков
            if self.collisionTest():
                # восстанавливаем высоту камеры
                base.camera.setZ(old_z)
                # сбрасываем скорость падения
                self.fall_speed = 0
                # устанавливаем флаг касания земли
                self.ground = True
            else:
                # ускоряем падение
                self.fall_speed += self.fall_acceleration

        # получаем новое положение курсора мышки
        new_mouse_pos = base.win.getPointer(0)
        new_x = new_mouse_pos.getX()
        new_y = new_mouse_pos.getY()
        # пробуем установить курсор в центр экрана
        if base.win.movePointer(0, self.x_center, self.y_center):
            # рассчитываем поворот камеры по горизонтали
            self.heading = self.heading - (new_x -
                                           self.x_center) * self.mouse_step
            # рассчитываем наклон камеры по вертикали
            self.pitch = self.pitch - (new_y - self.y_center) * self.mouse_step
            # устанавливаем новую ориентацию камеры
            base.camera.setHpr(self.heading, self.pitch, 0)

        # сообщаем о необходимости повторного запуска задачи
        return task.again

    # Метод проверки столкновений с объектами
    def collisionTest(self):
        # запускаем обходчик на проверку
        self.traverser.traverse(base.render)

        # если обходчик обнаружил какие-то столкновения
        if self.collisQueue.getNumEntries() > 0:
            return True
        else:
            return False
Ejemplo n.º 53
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")
        self.dirText = addInstructions(0.42, "pos")
        self.anglesText = addInstructions(0.48, "angle")

        # 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.createArm()

        # 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", self.exitButton)
        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(15, 0, 3)#self.ralph.getX(), self.ralph.getY() + 10, 2)
        self.camera.setHpr(90, -5, 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 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))

    def exitButton(self):
      servos.exit()
      __import__('sys').exit()

    def createArm(self):
        self.robotarm = Actor("models/robotarm")
        self.robotarm.reparentTo(render)
        self.robotarm.setPos(0,0,0)
        self.robotarm.setScale(.2)
        self.jointForearm = self.robotarm.controlJoint(None, "modelRoot", "forearm")
        self.jointBase = self.robotarm.controlJoint(None, "modelRoot", "base")
        taskMgr.add(self.monitorArm, "robot arm")

        inc = 15
        self.accept("i", self.setForearm, [inc])
        self.accept("u", self.setForearm, [-inc])
        self.accept("j", self.setBase, [inc])
        self.accept("k", self.setBase, [-inc])

    def monitorArm(self, task):
        def clamp1(x): return min(1, max(-1, x))

        direction = self.ralph.get_pos() - self.robotarm.get_pos()
        direction.z += 1
        direction.normalize()

        # camera starts facing along x
        dec = math.asin(direction.x)
        cosdec = math.cos(dec) 
        if cosdec > 1e-05:
          ra = math.asin(clamp1(direction.z / cosdec))
          ra2 = math.acos(clamp1(direction.y / cosdec))
        else: ra = ra2 = math.pi/2#float('nan')
        #print(cosdec, direction)
        #print(dec, ra, ra2, cosdec)

        if direction.z < 0: 
          if ra2 < math.pi/2: ra2 = 0
          else: ra2 = math.pi

        self.jointForearm.setH(-dec * 180/math.pi)
        self.jointBase.setP(ra2 * 180/math.pi) 

        self.dirText.setText(str(direction)) 
        self.anglesText.setText(str((dec, ra, ra2, cosdec)))

        a = self.jointForearm.getH() / 90.0 * 300 + 512
        b = self.jointBase.getP()    / 90.0 * 300 + 212
        #print(a, b)
        baseID = 9
        servos.setAngle({baseID:int(round(b)), (baseID+1):int(round(a))})
        return task.again

    def monitorArmServos(self, task):
        baseID = 9
        a = self.jointForearm.getH() / 90.0 * 300 + 512
        b = self.jointBase.getP()    / 90.0 * 300 + 212
        #print(a, b)
        servos.setAngle({baseID:int(round(a)), (baseID+1):int(round(b))})

#	frac = task.time - int(task.time) 
#        if frac > .9 and frac < .99:
        #print(self.jointForearm.getH(), self.jointBase.getP())
        return task.again

    def setForearm(self, inc):
        #self.jointForearm.setH(random.random()*180-90)
        self.jointForearm.setH(self.jointForearm.getH() + inc)
    def setBase(self, inc):
        #self.jointBase.setP(random.random()*180)
        self.jointBase.setP(self.jointBase.getP() + inc)


    # 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
Ejemplo n.º 54
0
class Weapon(DirectObject):
    def __init__(self, _main, _name, _fireRate, _dmg=20,_mountSlot=0, weaponType="Pistol"):
        self.main = _main
        self.name = _name
        self.fireRate = _fireRate
        self.dmg = _dmg
        self.weaponType = weaponType
        self.mountSlot = _mountSlot

        self.muzzleFlash = loader.loadModel("muzzleflash")
        if weaponType == "Pistol":
            self.style = "OneHand"
            self.model = loader.loadModel("Pistol")
            self.muzzleFlash.setZ(0.65)
            self.muzzleFlash.setX(-0.04)
            self.muzzleFlash.setScale(0.25)
            self.muzzleFlash.find('**/+SequenceNode').node().setFrameRate(20)
        else:
            self.style = "TwoHand"
            self.model = loader.loadModel("MG")
            self.muzzleFlash.setZ(0.65)
            self.muzzleFlash.setX(0.08)
            self.muzzleFlash.setScale(0.3)
            self.muzzleFlash.find('**/+SequenceNode').node().setFrameRate(20)
        self.model.setY(2)
        self.muzzleFlash.reparentTo(self.model)
        self.muzzleFlash.find('**/+SequenceNode').node().stop()
        self.muzzleFlash.hide()

        # Load bullet model
        self.bullet = loader.loadModel("Bullet")
        self.bullet.setP(-90)
        self.bullet.setH(180)
        #self.bullet.setPos(0, 0.5, 0)

        # Control
        self.isFiring = False

        # Collision Stuff
        self.wepRay = None
        # Make weapon ray
        self.setupRay()
        self.model.show()

    def setAmmo(self):
        pass

    def setupRay(self):
        self.shootTraverser = CollisionTraverser()
        self.shootingQH = CollisionHandlerQueue()
        #self.shootingEH = CollisionHandlerEvent()
        #self.shootingEH.addInPattern('into-%in')
        # Create a collision Node
        shootNode = CollisionNode('WeaponRay')
        # set the nodes collision bitmask
        shootNode.setFromCollideMask(BitMask32.bit(1))
        # create a collision segment (ray like)
        self.shootRay = CollisionSegment()
        shootNode.addSolid(self.shootRay)
        #self.pickerNP = self.main.player.model.attachNewNode(pickerNode)
        self.shootNP = render.attachNewNode(shootNode)
        #self.shootTraverser.addCollider(self.shootNP, self.shootingEH)
        self.shootTraverser.addCollider(self.shootNP, self.shootingQH)
        #self.shootNP.show()

    def doFire(self, _toPos=(0, 0, 0)):
        self.isFiring = True

        if self.weaponType == "Pistol":
            self.muzzleFlash.find('**/+SequenceNode').node().play(0, 1)
        else:
            self.muzzleFlash.find('**/+SequenceNode').node().loop(True)
        self.muzzleFlash.show()

        # For some reason the mouse ray end up at posZ -1 (which causes a problem when we make the enemy spheres smaller in radius)
        # so here for now.. ill make a quick fix.
        adjustedZ = (_toPos[0], _toPos[1], 0)

        self.shootRay.setPointA(self.main.player.model.getPos())
        self.shootRay.setPointB(adjustedZ)

        fromPos = self.main.player.model.getPos() #self.model.getPos()
        #self.setProjectile(fromPos, adjustedZ)#_toPos)

        self.shootTraverser.traverse(self.main.enemyParent)
        if self.shootingQH.getNumEntries() > 0:
            self.shootingQH.sortEntries()
            enemyCol = self.shootingQH.getEntry(0).getIntoNodePath().node().getName()
            base.messenger.send("into-" + enemyCol, [self.dmg])

    def stopFire(self):
        if self.weaponType == "Pistol" and \
               self.muzzleFlash.find('**/+SequenceNode').node().isPlaying():
            taskMgr.add(self.waitForFrame, "waitForFrame")
            return
        self.muzzleFlash.find('**/+SequenceNode').node().stop()
        self.muzzleFlash.hide()

    def waitForFrame(self, task):
        if self.muzzleFlash.find('**/+SequenceNode').node().isPlaying():
            return task.cont
        self.muzzleFlash.find('**/+SequenceNode').node().stop()
        self.muzzleFlash.hide()

    def reload(self):
        pass

    def setProjectile(self, _from, _to):
        self.bullet.reparentTo(render)#self.model)
        # setup the projectile interval
        #self.bulletProjectile = ProjectileInterval(self.bullet,
        #                                startPos = Point3(_from),
        #                                duration = 1,
        #                                endPos = Point3(_to))
        #self.bulletProjectile = self.bullet.posInterval(1.0, Point3(_to), startPos=Point3(_from))
        #self.bulletProjectile = LerpPosInterval(self.bullet, 2.0, _to, _from)
        print "POSITIONS:"
        print _to
        print _from
        frm = render.getPos(self.main.player.model)
        print frm

        self.bulletProjectile = LerpPosInterval(self.bullet, 1.0, _to, _from)
        self.bulletProjectile.start()
Ejemplo n.º 55
0
class Labryn(DirectObject):

    def setCamera(self, spin):
        self.spin = spin
    
    def spinCamera(self, task):
        if self.spin == 1: # spin counter-clockwise
            self.cameraSpinCount += 1
            angleDegrees = self.cameraSpinCount
            angleRadians =  angleDegrees * (pi/ 180)
            self.CAM_RAD = angleRadians
            camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R) 
            camera.setHpr(angleDegrees,-65,0)
        elif self.spin == 2: # spin clockwise
            self.cameraSpinCount  -= 1
            angleDegrees = self.cameraSpinCount
            angleRadians =  angleDegrees * (pi/ 180)
            self.CAM_RAD = angleRadians
            camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
            camera.setHpr(angleDegrees,-65,0)
        elif self.spin == 3: # ZOOM IN not spin
            self.cameraZoomCount += 1
            deltaR = self.cameraZoomCount * 0.1
            new_R = 12-deltaR
            self.CAM_R = new_R
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*new_R)
        elif self.spin == 4: # ZOOM OUT
            self.cameraZoomCount -= 1
            deltaR = self.cameraZoomCount * 0.1
            new_R = 12-deltaR
            self.CAM_R = new_R
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
                          
        return Task.cont

    def checkMouse(self, task):
        if base.mouseWatcherNode.hasMouse():
            self.mouseX=base.mouseWatcherNode.getMouseX()
            self.mouseY=base.mouseWatcherNode.getMouseY()
        return Task.cont

    def dropRock(self):
        if self.pokeMoveChoice == 1: # selected Geodude
            result = MAZE.canDropRock(self.rockX, self.rockY)
            if result != False: # can place rock here
                MAZE.dropRock(result[0],result[1])
                self.rock.setPos(self.rockX, self.rockY, 1)
                self.rockOnMaze = True
                self.pokeMoveChoice = None
                self.myPokeName.hide()
                self.myPokeName = None
                self.updateTwoD()
                self.playerCandyCount -= 1

    def useFlame(self):
        self.onFire = True # on fire
        self.playerCandyCount -= 1
        self.pokeStatus = 1
        self.flame = ParticleEffect()
        self.flame.loadConfig("fireish.ptf")
        self.flame.setPos(self.pikachu.getPos())
        self.flame.start(parent=render, renderParent=render)
        self.updateTwoD()

    def useStringShot(self):
        self.pokeStatus = 2
        self.updateTwoD()

    def placeRock(self, task):
        if self.pokeMoveChoice == 1: # selected Geodude
            dX,dY = ((self.mouseX-self.rockRefX),
                     (self.mouseY-self.rockRefY))
            self.rockX, self.rockY = MAZE.translateRockPosition(self.rockRefX,
                                                      self.rockRefY,
                                                      dX, dY)
            self.rock.show()
            self.rock.setPos(self.rockX, self.rockY, 1)
        self.updateTwoD()
        return Task.cont
    
    def placeRareCandy(self, task):
        if int(task.time) % 4 == 9 and self.candyOnBoard:
            self.candy.hide()
            self.candyOnBoard = False
        if int(task.time) % 10 ==  0 and (self.candyOnBoard == False):
            # every 10 seconds
            self.candy.setPos(MAZE.generateCandyPos())
            self.candy.show()
            self.candyOnBoard = True
        return Task.cont

    def updateTwoD(self):
        # update player candy count
        self.playerCandyStatus.destroy()
        self.playerCandyStatus = candyStatus(0, self.playerCandyCount)
        # update pikachu candy count
        # TODO
        # update my pokes color     
        if self.playerCandyCount == 0 :
            groupHide(self.myPokesBright)
            groupShow(self.myPokesDark)
            # update name
            if self.myPokeName != None:
                self.myPokeName.destroy()

    def clearRock(self):
        self.rock.hide()
        self.rockOnMaze = False
        MAZE.clearRock() # clear it in 2D

    def clearFlame(self):
        self.onFire = False
        self.flame.cleanup()
        self.pokeStatus = 0
        self.pokeMoveChoice = None
        try:
            self.myPokeName.destroy()
        except:
            pass
        self.myPokeName = None

    def clearString(self):
        self.pokeStatus = 0
        self.pokeMoveChoice = None
        try:
            self.myPokeName.destroy()
        except:
            pass
        self.myPokeName = None

        
    def timer(self, task): # deals with moves' lasting effects
        ##############################################################
        if self.rockOnMaze: # rock on maze
            self.rockCounter += 1
        elif self.rockCounter != 1: # rock not on maze, counter not cleared
            self.rockCounter = 0

        if self.onFire:
            self.fireCounter += 1
        elif self.fireCounter != 1:
            self.fireCounter = 0

        if self.pokeStatus == 2: # string shot
            self.stringCounter += 1
        elif self.stringCounter != 1:
            self.stringCounter = 0

        ##################################################################
        if self.rockCounter == 500:
            self.clearRock()

        if self.fireCounter == 80:
            self.clearFlame()

        if self.stringCounter == 120:
            self.clearString()
            
        return Task.cont
    
    def usePokeMove(self, number):
        if self.playerCandyCount > 0: # have more than one candy
            if number == 1 and self.rockOnMaze == False:
                if self.pokeMoveChoice != 1: # NONE or other
                    # set to center position
                    centerx =  base.win.getProperties().getXSize()/2
                    centery =  base.win.getProperties().getYSize()/2
                    base.win.movePointer(0,centerx,centery)
                    self.pokeMoveChoice = 1 # placeRock called here
                    self.rockRefX, self.rockRefY = 0,0
                    self.rock.show()
                    self.rock.setPos(0,0,1)
                else: # already 1
                    self.pokeMoveChoice = None
                    self.clearRock() # clear rock
            elif number == 2:
                if self.pokeMoveChoice != 2:
                    self.pokeMoveChoice = 2
                    self.useFlame()
                else:
                    self.pokeMoveChoice = None
            elif number == 3:
                if self.pokeMoveChoice != 3:
                    self.pokeMoveChoice = 3
                    self.useStringShot()
                else:
                    self.pokeMoveChoice = None
            if self.pokeMoveChoice == None: # no choice
                if self.myPokeName != None: # there is a name on board
                    self.myPokeName.destroy() # kill it
                else: # no name
                    pass
            else: # there is a choice
                if self.myPokeName != None:
                    self.myPokeName.destroy()
                self.myPokeName = Two_D.writePokeName(self.pokeMoveChoice)
  
    def loadRareCandy(self):
        self.candy = Model_Load.loadRareCandy()
        self.candy.reparentTo(render)
        self.candy.setScale(0.1)
        self.candy.hide()
        
    def eatRareCandy(self, task):
        if self.candyOnBoard: # candy on board
            if checkEat(self.ballRoot.getX(), self.ballRoot.getY(),
                        self.candy.getX(), self.candy.getY()): # ball eats
                self.candy.hide() # eaten
                self.candyOnBoard = False
                self.playerCandyCount += 1
                # self.playerCandyStatus.destroy()
                # self.playerCandyStatus = candyStatus(0,
                                       # self.playerCandyCount) # update
                print "BALL EATS CANDY"
                groupShow(self.myPokesBright)

            elif checkEat(self.pikachu.getX(), self.pikachu.getY(),
                          self.candy.getX(), self.candy.getY()):
                self.candy.hide()
                self.candyOnBoard = False
                self.pokemonCandyCount += 1
        return Task.cont

    def setFocus(self, changing):
        self.changingFocus = changing
        if changing == True: # Just Pressed
            self.referenceX, self.referenceY = self.mouseX, self.mouseY
        else: # cursor moves up
            self.referenceX, self.referenceY = None, None

    def resetView(self):
        self.CAM_R, self.CAM_RAD = 12, 0
        self.cameraSpinCount, self.cameraZoomCount = 0, 0
        # _FOCUS = [0,0,0] does not work WHY???
        _FOCUS[0], _FOCUS[1], _FOCUS[2] = 0,0,0
        self.changingFocus = False
        self.referenceX, self.referenceY = None, None
        camera.setPos(_FOCUS[0], _FOCUS[1]-self.CAM_R, 25)
        camera.setHpr(0, -65, 0)
        
    def changeFocus(self, task):
        if (self.changingFocus == True and self.mouseX != None and
            self.mouseY != None ):
            dX, dY = ((self.mouseX - self.referenceX)*0.1,
                      (self.mouseY - self.referenceY)*0.1)
            _FOCUS[0] += dX
            _FOCUS[1] += dY
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
        return Task.cont

    def initialize(self):
        #bgmusic = load_bgmusic("palette.mp3")
        #bgmusic.play()

        self.background = Two_D.loadBackground()
        base.cam2dp.node().getDisplayRegion(0).setSort(-20)
        self.candyOnBoard = False
        self.playerCandyCount, self.pokemonCandyCount = 2, 0
        ######################Rare Candy###############################
        pokes=['caterpie', 'charmander', 'geodude']
        self.myPokesDark = Two_D.loadMyPokemon_Dark(pokes) # my pokemons
        self.myPokesBright = Two_D.loadMyPokemon_Bright()
        groupHide(self.myPokesBright)
        self.loadRareCandy() # load rare candy
        ######################Camera Initialization####################
        self.CAM_R, self.CAM_RAD = 12, 0
        camera.setPos(_FOCUS[0],_FOCUS[1]-12,_FOCUS[2]+25)
        camera.setHpr(0, -65, 0)
        self.cameraSpinCount, self.cameraZoomCount = 0, 0
        self.changingFocus = False
        self.spin = 0
        #######################ICONS###################################
        self.myIcon = Two_D.loadMyIcon()
        self.pokeIcon = Two_D.loadPokeIcon()
        self.playerCandyStatus = candyStatus(0, self.playerCandyCount)
        #######################FLAMES##################################
        base.enableParticles()
        self.fireCounter = 0
        self.onFire = False
        #######################STRINGSHOT#############################
        self.stringCounter = 0
        #######################GLOBALS#################################
        self.i = 0
        self.myDirection = ['zx', 'zy']
        self.rockCounter  = 0
        self.rockX, self.rockY = None, None
        self.rockOnMaze = False
        self.pokeMoveChoice = None
        self.myPokeName = None
        self.arrowKeyPressed = False
        self.pokemonDirection = 'd'
        self.mouseX, self.mouseY = None, None
        # direction the ball is going
        self.jerkDirection = None
        base.disableMouse()
        self.jerk = (0,0,0)
        self.MAZE = Model_Load.loadLabyrinth()
        Control.keyControl(self)
        self.loadPokemonLevel1()
        self.light()
        self.loadBall()
        self.pokeStatus = 0 # 0 is normal, 1 is burned, 2 is slow-speed
        ########################################ROCK###################
        self.rock = Model_Load.loadRock()
        self.rock.reparentTo(render)
        self.rock.hide() # Do not show, but load beforehand for performance
        
    def loadPokemonLevel1(self):
        self.pikachu = load_model("pikachu.egg")
        self.pikachu.reparentTo(render)
        self.pikachu.setScale(0.3)
        endPos = self.MAZE.find("**/end").getPos()
        self.pikachu.setPos(endPos) 
        
    def light(self):
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def loadBall(self):
        self.ballRoot = render.attachNewNode("ballRoot")
        self.ball = load_model("ball")
        self.ball.reparentTo(self.ballRoot)
        self.ball_tex = load_tex("pokeball.png")
        self.ball.setTexture(self.ball_tex,1)
        self.ball.setScale(0.8)
        # Find the collision sphere for the ball in egg.
        self.ballSphere = self.ball.find("**/ball")
        self.ballSphere.node().setFromCollideMask(BitMask32.bit(0))
        self.ballSphere.node().setIntoCollideMask(BitMask32.allOff())
        #self.ballSphere.show()
        # Now we create a ray to cast down at the ball.
        self.ballGroundRay = CollisionRay()
        self.ballGroundRay.setOrigin(0,0,10)
        self.ballGroundRay.setDirection(0,0,-1)

        # Collision solids go in CollisionNode
        self.ballGroundCol =  CollisionNode('groundRay')
        self.ballGroundCol.addSolid(self.ballGroundRay)
        self.ballGroundCol.setFromCollideMask(BitMask32.bit(1))
        self.ballGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ballGroundColNp = self.ballRoot.attachNewNode(self.ballGroundCol)
        
        # light
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.55, .55, .55, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0,0,-1))
        directionalLight.setColor(Vec4(0.375,0.375,0.375,1))
        directionalLight.setSpecularColor(Vec4(1,1,1,1))
        self.ballRoot.setLight(render.attachNewNode(ambientLight))
        self.ballRoot.setLight(render.attachNewNode(directionalLight))
        # material to the ball
        m = Material()
        m.setSpecular(Vec4(1,1,1,1))
        m.setShininess(96)
        self.ball.setMaterial(m,1)

    def __init__(self):
        self.initialize()
        self.WALLS = self.MAZE.find("**/Wall.004")
        self.WALLS.node().setIntoCollideMask(BitMask32.bit(0))
        # collision with the ground. different bit mask
        #self.mazeGround = self.maze.find("**/ground_collide")
        #self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1))
        self.MAZEGROUND = self.MAZE.find("**/Cube.004")
        self.MAZEGROUND.node().setIntoCollideMask(BitMask32.bit(1))
        # add collision to the rock
        cs = CollisionSphere(0, 0, 0, 0.5)
        self.cnodePath = self.rock.attachNewNode(CollisionNode('cnode'))
        self.cnodePath.node().addSolid(cs)
        self.cnodePath.show()
        self.cnodePath.node().setIntoCollideMask(BitMask32.bit(0))
        # load the ball and attach it to the scene.
        # it is on a dummy node so that we can rotate the ball
        # without rotating the ray that will be attached to it

        # CollisionTraversers calculate collisions
        self.cTrav = CollisionTraverser()
        #self.cTrav.showCollisions(render)
        #self.cTrav.showCollisions(render)
        # A list collision handler queue
        self.cHandler = CollisionHandlerQueue()
        # add collision nodes to the traverse.
        # maximum nodes per traverser: 32
        self.cTrav.addCollider(self.ballSphere,self.cHandler)
        self.cTrav.addCollider(self.ballGroundColNp,self.cHandler)
        self.cTrav.addCollider(self.cnodePath, self.cHandler)
        # collision traversers have a built-in tool to visualize collisons
        #self.cTrav.showCollisions(render)
        self.start()

    def pokemonTurn(self, pokemon, direction):
        if direction  == 'l' and self.pokemonDirection != 'l':
            self.pokemonDirection = 'l'
            pokemon.setH(-90)
        if direction  == 'r' and self.pokemonDirection != 'r':
            self.pokemonDirection = 'r'
            pokemon.setH(90)
        if direction  == 'd' and self.pokemonDirection != 'd':
            self.pokemonDirection = 'd'
            pokemon.setH(0)
        if direction  == 'u' and self.pokemonDirection != 'u':
            self.pokemonDirection = 'u'
            pokemon.setH(180)
                        
    def pokemonMove(self, pokemon, direction):
        self.pokemonTurn(pokemon, direction)
        if self.pokeStatus == 0: speed = _SPEED
        elif self.pokeStatus == 1: speed = 0
        else: # self.pokeStatus == 2
            speed = _SPEED/2.0
        if direction == 'l':
            newX = pokemon.getX() - speed
            pokemon.setX(newX)
        elif direction == 'r':
            newX = pokemon.getX() + speed
            pokemon.setX(newX)
        elif direction == 'u':
            newY = pokemon.getY() + speed
            pokemon.setY(newY)
        elif direction == 'd':
            newY = pokemon.getY() - speed
            pokemon.setY(newY)
        elif direction == "s": # stop
            pass
        
    def whereToGo(self, task):
        # this returns the direction pokemon should go
        # tell MAZE pokemon and ball's board position
        print self.myDirection
        MAZE.setPokeCoord(self.pikachu.getX(), self.pikachu.getY(),
                          self.pokemonDirection)
        MAZE.setBallCoord(self.ballRoot.getX(), self.ballRoot.getY())
        # find out which direction to go
        direction = MAZE.getDecision()
        self.pokemonMove(self.pikachu,direction)
        return Task.cont

    def getInformation(self, task):
        # get information on the board
        # TODO
        self.i += 1 # sample every other call to avoid 
        if self.i % 2 == 0:
            dX = self.ballRoot.getX() - self.oldPos[0]
            dY = self.ballRoot.getY() - self.oldPos[1]
            if dX < 0 :
                # print "going left"
                self.myDirection[0] = 'l'
            elif abs(dX) < _EPSILON:
                # print "not moving horiz"
                self.myDirection[0] = 'zx'
            else:
                # print "going right"
                self.myDirection[0] = 'r'

            if dY < 0 :
                # print "going down"
                self.myDirection[1] = 'd'
            elif abs(dY) < _EPSILON:
                # print "not moving verti"
                self.myDirection[1] = 'zy'
            else:
                # print "going up"
                self.myDirection[1] = 'u'
            self.oldPos = self.ballRoot.getPos()
        return Task.cont
    
    def start(self):
        # maze model has a locator in it
        # self.ballRoot.show()
        self.startPos = self.MAZE.find("**/start").getPos()
        self.oldPos = self.MAZE.find("**/start").getPos()
        self.ballRoot.setPos(self.startPos) # set the ball in the pos
        self.ballV = Vec3(0,0,0) # initial velocity
        self.accelV = Vec3(0,0,0) # initial acceleration

        # for a traverser to work, need to call traverser.traverse()
        # base has a task that does this once a frame
        base.cTrav = self.cTrav

        # create the movement task, make sure its not already running
        taskMgr.remove("rollTask")
        taskMgr.add(self.placeRock, "placeRock")
        taskMgr.add(self.timer, "timer")
        taskMgr.add(self.getInformation, "getInformation")
        taskMgr.add(self.eatRareCandy, "eatRareCandy")
        taskMgr.add(self.placeRareCandy, "placeRareCandy")
        taskMgr.add(self.checkMouse, "checkMouse")
        taskMgr.add(self.spinCamera, "spinCamera")
        taskMgr.add(self.changeFocus, "changeFocus")
        taskMgr.add(self.whereToGo, "whereToGo")
        # taskMgr.add(lambda task: self.moveBall(task, self.jerkDirection),
                    # "moveBall")
        taskMgr.add(self.moveBall, "moveBall")
        self.mainLoop = taskMgr.add(self.rollTask, "rollTask")
        self.mainLoop.last = 0

    def moveBallWrapper(self, direction):
        if direction == False:
            self.arrowKeyPressed = False
        else:
            self.arrowKeyPressed = True
            self.jerkDirection = direction
    
    def moveBall(self, task):
        direction = self.jerkDirection
        if self.arrowKeyPressed == True:
            if direction == "u":
                self.jerk = Vec3(0,_JERK,0)
            elif direction == "d":
                self.jerk = Vec3(0,-_JERK,0)
            elif direction == "l":
                self.jerk = Vec3(-_JERK,0,0)
            elif direction == "r":
                self.jerk = Vec3(_JERK,0,0)
        return Task.cont        
    """      
    def moveBall(self, task, direction):
        if self.arrowKeyPressed == True:
            if direction == "u":
                self.jerk = Vec3(0,_JERK,0)
            elif direction == "d":
                self.jerk = Vec3(0,-_JERK,0)
            elif direction == "l":
                self.jerk = Vec3(-_JERK,0,0)
            elif direction == "r":
                self.jerk = Vec3(_JERK,0,0)
        return Task.cont
    """       
    # collision between ray and ground
    # info about the interaction is passed in colEntry
    
    def groundCollideHandler(self,colEntry):
        # set the ball to the appropriate Z for it to be on the ground
        newZ = colEntry.getSurfacePoint(render).getZ()
        self.ballRoot.setZ(newZ+.4)

        # up vector X normal vector
        norm = colEntry.getSurfaceNormal(render)
        accelSide = norm.cross(UP)
        self.accelV = norm.cross(accelSide)

    # collision between the ball and a wall
    def wallCollideHandler(self,colEntry):
        # some vectors needed to do the calculation
        norm = colEntry.getSurfaceNormal(render) * -1
        norm.normalize()
        curSpeed = self.ballV.length()
        inVec = self.ballV/curSpeed
        velAngle = norm.dot(inVec) # angle of incidance
        hitDir = colEntry.getSurfacePoint(render) - self.ballRoot.getPos()
        hitDir.normalize()
        hitAngle = norm.dot(hitDir)
    # deal with collision cases

        if velAngle > 0 and hitAngle >.995:
            # standard reflection equation
            reflectVec = (norm * norm.dot(inVec*-1)*2) + inVec

            # makes velocity half of hitting dead-on
            self.ballV = reflectVec * (curSpeed * (((1-velAngle)*.5)+.5))

            # a collision means the ball is already a little bit buried in
            # move it so exactly touching the wall
            disp = (colEntry.getSurfacePoint(render) -
                    colEntry.getInteriorPoint(render))
            newPos = self.ballRoot.getPos() + disp
            self.ballRoot.setPos(newPos)
            
    def rollTask(self,task):
        # standard technique for finding the amount of time
        # since the last frame
        dt = task.time - task.last
        task.last = task.time

        # If dt is large, then there is a HICCUP
        # ignore the frame
        if dt > .2: return Task.cont

        # dispatch which function to handle the collision based on name
        for i in range(self.cHandler.getNumEntries()):
            entry = self.cHandler.getEntry(i)
            name = entry.getIntoNode().getName()
       
            if name == "Wall.004":
                self.wallCollideHandler(entry)
            elif name=="Cube.004":
                self.groundCollideHandler(entry)
            else: 
                if self.rockOnMaze == True:
                    self.wallCollideHandler(entry)
        self.accelV += self.jerk
        # move the ball, update the velocity based on accel
        self.ballV += self.accelV * dt * ACCELERATION
        # clamp the velocity to the max speed
        if self.ballV.lengthSquared() > MAX_SPEED_SQ:
            self.ballV.normalize()
            self.ballV *= MAX_SPEED
        # update the position
        self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV*dt))

        # uses quaternion to rotate the ball
        prevRot = LRotationf(self.ball.getQuat())
        axis = UP.cross(self.ballV)
        newRot = LRotationf(axis, 45.5 * dt * self.ballV.length())
        self.ball.setQuat(prevRot * newRot)
        return Task.cont # continue the task
class World(DirectObject):

    def __init__(self):
        
        self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0}
        base.win.setClearColor(Vec4(0,0,0,1))

        # Post the instructions

        self.title = addTitle("Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward")
        self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left")
        self.inst7 = addInstructions(0.65, "[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.environ.setPos(0,0,0)
        
        # Create the main character, Ralph
        ralphStartPos = self.environ.find("**/start_point").getPos()
        
        #self.addRalph(ralphStartPos)
       

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

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

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

        # Game state variables
        self.isMoving = False

        # Set up the camera
        
        base.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.

       

        # 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(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))
        
        # Add some text
        '''
        bk_text = "This is a test"
        textObject = OnscreenText(text = bk_text, pos = (0.95,-0.35), 
        scale = 0.07,fg=(1,0.5,0.5,1),align=TextNode.ACenter,mayChange=1)
        '''
    
    #MS: Adds a Roaming Ralph
    def addRalph(self, pos):
        ralphStartPos = pos
        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)
        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,1000)
        self.ralphGroundRay.setDirection(0,0,-1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.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,1000)
        self.camGroundRay.setDirection(0,0,-1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.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
    

    # 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 the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        base.camera.lookAt(self.ralph)
        if (self.keyMap["cam-left"]!=0):
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["cam-right"]!=0):
            base.camera.setX(base.camera, +20 * globalClock.getDt())

        # 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"]!=0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -25 * globalClock.getDt())

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

        if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0):
            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() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec*(5-camdist))
            camdist = 5.0

        # Now check for collisions.

        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 = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     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 = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.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.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + 2.0)
        base.camera.lookAt(self.floater)

        return task.cont
Ejemplo n.º 57
0
class World(DirectObject):
    def __init__(self):
        #This code puts the standard title and instruction text on screen
        self.title = OnscreenText(text="Panda3D: Tutorial - Mouse Picking",
                                  style=1, fg=(1, 1, 1, 1),
                                  pos=(0.8, -0.95), scale=.07)
        self.escapeEvent = OnscreenText(
            text="ESC: Quit",
            style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.95),
            align=TextNode.ALeft, scale=.05)
        self.mouse1Event = OnscreenText(
            text="Left-click and drag: Pick up and drag piece",
            style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.90),
            align=TextNode.ALeft, scale=.05)

        self.accept('escape', sys.exit)  #Escape quits
        base.disableMouse()  #Disble mouse camera control
        camera.setPosHpr(0, -13.75, 6, 0, -25, 0)  #Set the camera
        self.setupLights()  #Setup default lighting

        #Since we are using collision detection to do picking, we set it up like
        #any other collision detection system with a traverser and a handler
        self.picker = CollisionTraverser()  #Make a traverser
        self.pq = CollisionHandlerQueue()  #Make a handler
        #Make a collision node for our picker ray
        self.pickerNode = CollisionNode('mouseRay')
        #Attach that node to the camera since the ray will need to be positioned
        #relative to it
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        #Everything to be picked will use bit 1. This way if we were doing other
        #collision we could seperate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()  #Make our ray
        self.pickerNode.addSolid(self.pickerRay)  #Add it to the collision node
        #Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.pq)
        #self.picker.showCollisions(render)

        #Now we create the chess board and its pieces

        #We will attach all of the squares to their own root. This way we can do the
        #collision pass just on the sqaures and save the time of checking the rest
        #of the scene
        self.squareRoot = render.attachNewNode("squareRoot")

        #For each square
        self.squares = [None for i in range(64)]
        self.pieces = dict((i, None) for i in range(64))  #MOD
        for i in range(64):
            #Load, parent, color, and position the model (a single square polygon)
            self.squares[i] = loader.loadModel("models/square")
            self.squares[i].reparentTo(self.squareRoot)
            self.squares[i].setPos(SquarePos(i))
            self.squares[i].setColor(SquareColor(i))
            #Set the model itself to be collideable with the ray. If this model was
            #any more complex than a single polygon, you should set up a collision
            #sphere around it instead. But for single polygons this works fine.
            self.squares[i].find("**/polygon").node().setIntoCollideMask(
                BitMask32.bit(1))
            #Set a tag on the square's node so we can look up what square this is
            #later during the collision pass
            self.squares[i].find("**/polygon").node().setTag('square', str(i))

            #We will use this variable as a pointer to whatever piece is currently
            #in this square

        #The order of pieces on a chessboard from white's perspective. This list
        #contains the constructor functions for the piece classes defined below
        pieceOrder = (Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook)

        for i in range(8, 16):
            #Load the white pawns
            self.pieces[i] = Pawn(i, WHITE)
        for i in range(48, 56):
            #load the black pawns
            self.pieces[i] = Pawn(i, PIECEBLACK)
        for i in range(8):
            #Load the special pieces for the front row and color them white
            self.pieces[i] = pieceOrder[i](i, WHITE)
            #Load the special pieces for the back row and color them black
            self.pieces[i + 56] = pieceOrder[i](i + 56, PIECEBLACK)

        #This will represent the index of the currently highlited square
        self.hiSq = False
        #This wil represent the index of the square where currently dragged piece
        #was grabbed from
        self.dragging = False

        #Start the task that handles the picking
        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')
        self.accept("mouse1", self.grabPiece)  #left-click grabs a piece
        self.accept("mouse1-up", self.releasePiece)  #releasing places it

    #This function swaps the positions of two pieces
    def swapPieces(self, fr, to):
        temp = self.pieces[fr]
        self.pieces[fr] = self.pieces[to]
        self.pieces[to] = temp
        if self.pieces[fr]:
            self.pieces[fr].square = fr
            self.pieces[fr].obj.setPos(SquarePos(fr))
        if self.pieces[to]:
            self.pieces[to].square = to
            self.pieces[to].obj.setPos(SquarePos(to))

    def mouseTask(self, task):
        #This task deals with the highlighting and dragging based on the mouse

        #First, clear the current highlight
        if self.hiSq is not False:
            self.squares[self.hiSq].setColor(SquareColor(self.hiSq))
            self.hiSq = False

        #Check to see if we can access the mouse. We need it to do anything else
        if base.mouseWatcherNode.hasMouse():
            #get the mouse position
            mpos = base.mouseWatcherNode.getMouse()

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

            #If we are dragging something, set the position of the object
            #to be at the appropriate point over the plane of the board
            if self.dragging is not False:
                #Gets the point described by pickerRay.getOrigin(), which is relative to
                #camera, relative instead to render
                nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin())
                #Same thing with the direction of the ray
                nearVec = render.getRelativeVector(camera, self.pickerRay.getDirection())
                self.pieces[self.dragging].obj.setPos(
                    PointAtZ(.5, nearPoint, nearVec))

            #Do the actual collision pass (Do it only on the squares for
            #efficiency purposes)
            self.picker.traverse(self.squareRoot)
            if self.pq.getNumEntries() > 0:
                #if we have hit something, sort the hits so that the closest
                #is first, and highlight that node
                self.pq.sortEntries()
                i = int(self.pq.getEntry(0).getIntoNode().getTag('square'))
                #Set the highlight on the picked square
                self.squares[i].setColor(HIGHLIGHT)
                self.hiSq = i

        return Task.cont

    def grabPiece(self):
        #If a square is highlighted and it has a piece, set it to dragging mode
        if (self.hiSq is not False and
                self.pieces[self.hiSq]):
            self.dragging = self.hiSq
            self.hiSq = False

    def releasePiece(self):
        #Letting go of a piece. If we are not on a square, return it to its original
        #position. Otherwise, swap it with the piece in the new square
        if self.dragging is not False:  #Make sure we really are dragging something
            #We have let go of the piece, but we are not on a square
            if self.hiSq is False:
                self.pieces[self.dragging].obj.setPos(
                    SquarePos(self.dragging))
            else:
                #Otherwise, swap the pieces
                self.swapPieces(self.dragging, self.hiSq)

        #We are no longer dragging anything
        self.dragging = False

    def setupLights(self):  #This function sets up some default lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.8, .8, .8, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0, 45, -45))
        directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(ambientLight))
Ejemplo n.º 58
0
class World(DirectObject):
    def __init__(self):
        #create Queue to hold the incoming chat
        #request the heartbeat so that the caht interface is being refreshed in order to get the message from other player

        self.keyMap = {
            "left": 0,
            "right": 0,
            "forward": 0,
            "cam-left": 0,
            "cam-right": 0,
            "charge": 0
        }
        base.win.setClearColor(Vec4(0, 0, 0, 1))

        self.cManager = ConnectionManager()
        self.cManager.startConnection()
        #------------------------------
        #Chat
        Chat(self.cManager)

        #send dummy login info of the particular client
        #send first chat info
        #---------------------------------------
        self.userName = username
        dummy_login = {
            'user_id': self.userName,
            'factionId': faction,
            'password': '******'
        }
        self.cManager.sendRequest(Constants.RAND_STRING, dummy_login)

        chat = {
            'userName': self.userName,  #username
            'message': '-------Login------'
        }
        self.cManager.sendRequest(Constants.CMSG_CHAT, chat)

        #--------------------------------------
        #self.minimap = OnscreenImage(image="images/minimap.png", scale=(0.2,1,0.2), pos=(-1.1,0,0.8))

        #frame = DirectFrame(text="Resource Bar", scale=0.001)

        resource_bar = DirectWaitBar(text="",
                                     value=35,
                                     range=100,
                                     pos=(0, 0, 0.9),
                                     barColor=(255, 255, 0, 1),
                                     frameSize=(-0.3, 0.3, 0, 0.03))
        cp_bar = DirectWaitBar(text="",
                               value=70,
                               range=100,
                               pos=(1.0, 0, 0.9),
                               barColor=(0, 0, 255, 1),
                               frameSize=(-0.3, 0.3, 0, 0.03),
                               frameColor=(255, 0, 0, 1))

        # 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.environ.setPos(0, 0, 0)

        # 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)

        nameplate = TextNode('textNode username_' + str(self.userName))
        nameplate.setText(self.userName)
        npNodePath = self.ralph.attachNewNode(nameplate)
        npNodePath.setScale(0.8)
        npNodePath.setBillboardPointEye()
        #npNodePath.setPos(1.0,0,6.0)
        npNodePath.setZ(6.5)

        bar = DirectWaitBar(value=100, scale=1.0)
        bar.setColor(255, 0, 0)
        #bar.setBarRelief()
        bar.setZ(6.0)
        bar.setBillboardPointEye()
        bar.reparentTo(self.ralph)

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("arrow_right", self.setKey, ["right", 1])
        self.accept("arrow_up", self.setKey, ["forward", 1])
        self.accept("a", self.setKey, ["cam-left", 1])
        self.accept("s", self.setKey, ["cam-right", 1])
        self.accept("arrow_left-up", self.setKey, ["left", 0])
        self.accept("arrow_right-up", self.setKey, ["right", 0])
        self.accept("arrow_up-up", self.setKey, ["forward", 0])
        self.accept("a-up", self.setKey, ["cam-left", 0])
        self.accept("s-up", self.setKey, ["cam-right", 0])
        self.accept("c", self.setKey, ["charge", 1])
        self.accept("c-up", self.setKey, ["charge", 0])

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

        # Game state variables
        self.isMoving = False

        # Set up the camera

        base.disableMouse()
        base.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, 1000)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.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, 1000)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.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(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(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):

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

        base.camera.lookAt(self.ralph)
        if (self.keyMap["cam-left"] != 0):
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["cam-right"] != 0):
            base.camera.setX(base.camera, +20 * globalClock.getDt())

        # 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"] != 0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        if (self.keyMap["right"] != 0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"] != 0):
            self.ralph.setY(self.ralph, -25 * globalClock.getDt())
        if (self.keyMap["charge"] != 0):
            self.ralph.setY(self.ralph, -250 * globalClock.getDt())
            #ribbon = Ribbon(self.ralph, Vec4(1,1,1,1), 3, 10, 0.3)
            #ribbon.getRoot().setZ(2.0)

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

        if (self.keyMap["forward"] != 0) or (self.keyMap["charge"] != 0) or (
                self.keyMap["left"] != 0) or (self.keyMap["right"] != 0):
            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() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec * (5 - camdist))
            camdist = 5.0

        # Now check for collisions.

        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 = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(
            y.getSurfacePoint(render).getZ(),
            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 = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(
            y.getSurfacePoint(render).getZ(),
            x.getSurfacePoint(render).getZ()))
        if (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                   == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.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.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + 2.0)
        base.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)

        #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