Exemple #1
0
 def appendWord(self,word,tm = None, fadein = 0, fadeinType = 0):
     if word == '\n':
         self.startLine()
         return
     
     textMaker = tm or self.textMaker
     if not self.lines:
         self.startLine()
     
     active_line = self.lines[-1] 
     
     unicodeText = isinstance(word, types.UnicodeType)
     if unicodeText:
         textMaker.setWtext(word)
     else:
         textMaker.setText(word)
         
     width = textMaker.getWidth()
     height = textMaker.getHeight()
     node = textMaker.generate()
     textpath = NodePath('text_path')
     textpath.attachNewNode(node)
     if self.wordwrap:
         if active_line.getTotalWidth() + width > self.wordwrap:
             self.startLine()
             active_line = self.lines[-1]
     
     active_line.append(textpath, width, height,self.spacing, fadein = fadein, fadeinType = fadeinType)
     active_line.setPos(0,0,-(self.currentHeight + active_line.getLineHeight()) )
Exemple #2
0
    def __build_Model(self, planet, model_type, rec):
        model_np = NodePath("model_{}".format(rec))
        
        # Basic terrain model.
        ter_model, pts = self.__get_Sphere_Model(model_type, rec, planet.radius, "terrain")
        ter_model.NP.reparentTo(model_np)

        # Map planet topography.
        if "height_map" in planet.__dict__ and model_type in ("mid", "high"):
            self.__map_Topography(planet, ter_model, pts)
        
        # Map planet colours for low type models only.
        if model_type == "low" and "colour_map" in planet.__dict__:
            self.__map_Colours(planet, ter_model, rec, pts)
        
        # Atmosphere.
        if "atmos_ceiling" in planet.__dict__:
            a_radius = planet.radius + planet.atmos_ceiling
            am_type = model_type if model_type != "high" else "mid"
            atmos_model, a_pts = self.__get_Sphere_Model(am_type, min(rec,7), a_radius, "atmos")
            atmos_model.NP.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullCounterClockwise))
            atmos_model.NP.setAttrib(TransparencyAttrib.make(TransparencyAttrib.MAlpha))
            atmos_model.NP.reparentTo(model_np)
            
        model_np.attachNewNode("planet_label")
        return model_np
class TestApplication:

  def __init__(self):

    self.setupPhysics()
    self.clock_ = ClockObject()


  def sim(self):
    
    while True:
        try:
          
          time.sleep(LOOP_DELAY)
          
          self.clock_.tick()
          self.physics_world_.doPhysics(self.clock_.getDt(), 5, 1.0/180.0)

          # printing location of first box
          print "Box 0: %s"%(str(self.boxes_[0].getPos()))

        except KeyboardInterrupt:
            print "Simulation finished"
            sys.exit()

  def setupPhysics(self):

    # setting up physics world and parent node path 
    self.physics_world_ = BulletWorld()
    self.world_node_ = NodePath()
    self.physics_world_.setGravity(Vec3(0, 0, -9.81))

    # setting up ground
    self.ground_ = self.world_node_.attachNewNode(BulletRigidBodyNode('Ground'))
    self.ground_.node().addShape(BulletPlaneShape(Vec3(0, 0, 1), 0))
    self.ground_.setPos(0,0,0)
    self.ground_.setCollideMask(BitMask32.allOn())
    self.physics_world_.attachRigidBody(self.ground_.node())

    self.boxes_ = []
    num_boxes = 20
    side_length = 0.2
    size = Vec3(side_length,side_length,side_length)
    start_pos = Vec3(-num_boxes*side_length,0,10)
    for i in range(0,20):
      self.addBox("name %i"%(i),size,start_pos + Vec3(i*2*side_length,0,0))

  def addBox(self,name,size,pos):

    # Box (dynamic)
    box = self.world_node_.attachNewNode(BulletRigidBodyNode(name))
    box.node().setMass(1.0)
    box.node().addShape(BulletBoxShape(size))
    box.setPos(pos)
    box.setCollideMask(BitMask32.allOn())

    self.physics_world_.attachRigidBody(box.node())
    self.boxes_.append(box)
class Army(GameObject):
    def __init__(self,player,scale,x,y):
        self.my_id = base.army_count
        base.army_count += 1
        self.name = "Army"+str(self.my_id)
        self.player = player
        self.scale = scale
        self.type = "army"

        self.node_path = NodePath("army"+str(self.my_id)+"_node_path")
        self.node_path.setPos(x,y,0)
        self.node_path.setTag("player","p"+str(player))
        self.node_path.setScale(self.scale,self.scale,self.scale)

        self.model_list = ["../models/infantry_counter_grey.egg","../models/infantry_counter_red.egg","../models/infantry_counter_green.egg"]
        self.model = loader.loadModel(self.model_list[player])
        self.model.reparentTo(self.node_path)

        self.node_col = self.node_path.attachNewNode(CollisionNode("tower"+str(self.my_id)+"_c_node"))
        self.node_col.setScale((2,2,1))
        self.node_col.setPos(0,0,0)
        self.node_col.node().addSolid(CollisionSphere(0,0,0,1))
        self.node_col.setTag("type","army")

        base.cTrav.addCollider(self.node_col,base.col_manager.col_handler)

        self.node_path.reparentTo(render)

        self.selected = False

    def change_player(self,player):
        self.model.remove()
        self.player = player
        self.model = loader.loadModel(self.model_list[player])
Exemple #5
0
    def drawBlocks(self):
        max_x = self.world.getMaxSize()

        print "max_x:", max_x, "nodes: ",
        for tmp_x in range(0, max_x - 1):
            tmp = self.world.blocks[tmp_x]
            x = tmp[0]
            y = tmp[1]
            z = tmp[2]

            tmpModel = self.loader.loadModel("models/box")

            newModel = NodePath("model")
            tmpModel.getChildren().reparentTo(newModel)

            newModel.reparentTo(self.render)
            newModel.setScale(1, 1, 1)
            newModel.setPos(x, y, z)

        self.render.flattenStrong()

        Node = NodePath(PandaNode("PhysicsNode"))
        Node.reparentTo(render)
        jetpackGuy = loader.loadModel("models/box")
        jetpackGuy.reparentTo(render)
        an = ActorNode("jetpack-guy-physics")
        anp = Node.attachNewNode(an)
        base.attachPhysicalNode(an)
        jetpackGuy.reparentTo(anp)

        self.render.analyze()
    def renderQuadInto(self, xsize, ysize, colortex=None, cmode = GraphicsOutput.RTMBindOrCopy, auxtex = None):

        buffer = self.createBuffer("filter-stage", xsize, ysize, colortex, cmode, auxtex)

        if (buffer == None):
            return None

        cm = CardMaker("filter-stage-quad")
        cm.setFrameFullscreenQuad()
        quad = NodePath(cm.generate())
        quad.setDepthTest(0)
        quad.setDepthWrite(0)
        quad.setColor(Vec4(1,0.5,0.5,1))

        quadcamnode = Camera("filter-quad-cam")
        lens = OrthographicLens()
        lens.setFilmSize(2, 2)
        lens.setFilmOffset(0, 0)
        lens.setNearFar(-1000, 1000)
        quadcamnode.setLens(lens)
        quadcam = quad.attachNewNode(quadcamnode)
        
        buffer.getDisplayRegion(0).setCamera(quadcam)
        buffer.getDisplayRegion(0).setActive(1)

        return quad, buffer
Exemple #7
0
    def _updateDebugNode(self):
        """ Internal method to generate new debug geometry. """
        mainNode = NodePath("DebugNodeInner")
        mainNode.setPos(self.position)
        lineNode = mainNode.attachNewNode("lines")

        inner = Globals.loader.loadModel("box")
        inner.setPos(-0.5, -0.5, 0.6)
        inner.flattenStrong()
        inner.reparentTo(mainNode)

        # Generate outer circles
        points1 = []
        points2 = []
        points3 = []
        for i in range(self.visualizationNumSteps + 1):
            angle = float(
                i) / float(self.visualizationNumSteps) * math.pi * 2.0
            points1.append(Vec3(0, math.sin(angle), math.cos(angle)))
            points2.append(Vec3(math.sin(angle), math.cos(angle), 0))
            points3.append(Vec3(math.sin(angle), 0, math.cos(angle)))

        self._createDebugLine(points1, False).reparentTo(lineNode)
        self._createDebugLine(points2, False).reparentTo(lineNode)
        self._createDebugLine(points3, False).reparentTo(lineNode)

        lineNode.setScale(self.radius)
        mainNode.flattenStrong()
        self.debugNode.node().removeAllChildren()
        mainNode.reparentTo(self.debugNode)
def empty(prefix, points=False):
    path = NodePath(prefix + '_path')
    node = GeomNode(prefix + '_node')
    path.attachNewNode(node)

    gvd = GeomVertexData('gvd', GeomVertexFormat.getV3n3t2(), Geom.UHStatic)
    geom = Geom(gvd)
    gvw = GeomVertexWriter(gvd, b'vertex')
    gnw = GeomVertexWriter(gvd, b'normal')
    gtw = GeomVertexWriter(gvd, b'texcoord')
    node.addGeom(geom)
    if points:
        prim = GeomPoints(Geom.UHStatic)
    else:
        prim = GeomTriangles(Geom.UHStatic)
    return (gvw, gnw, gtw, prim, geom, path)
class TerrainPhysicsDemo2():
    """Modified from ODE demo and Bullet demo."""
    def __init__(self, world, spawnNP):
        self.running = False
        self.world = world
        rbc = RigidBodyCombiner("rbc")
        self.rbcnp = NodePath(rbc)
        self.rbcnp.reparentTo(render)
        self.NrObjectToDrop = 10
        self.spawnNP = spawnNP
        self.objects = []
        self.model = loader.loadModel('models/box.egg')
        self.model.flattenLight()
        self.shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))

    def start(self):
        """Drop Rectangles"""
        # add objects one by one
        if self.running:
            return
        self.running = True
        self.newObjects = 0
        taskMgr.doMethodLater(0.5, self.runTask, "myDemo")

    def runTask(self, task):
        if self.demoContinue():
            return task.done
        return task.again

    def demoContinue(self):
        if self.newObjects < self.NrObjectToDrop:

            node = BulletRigidBodyNode('Box')
            node.setMass(1.0)
            node.addShape(self.shape)
            np = self.rbcnp.attachNewNode(node)
            np.setPos(self.spawnNP.getPos(render))
            np.setHpr(randint(-45, 45), randint(-45, 45), randint(-45, 45))
            self.world.attachRigidBody(node)

            bNP = self.model.copyTo(np)
            #bNP.setPos(self.spawnNP.getPos())
            #bNP.setColor(random(), random(), random(), 1)
            #bNP.setHpr(randint(-45, 45), randint(-45, 45), randint(-45, 45))
            #self.setUntextured(bNP)
            #bNP.setTexureOff()
            #np.setScale(10)
            np.flattenStrong()

            self.objects.append(np)
            self.newObjects += 1
            self.rbcnp.node().collect()

        if self.newObjects < self.NrObjectToDrop:
            return False
        else:
            self.running = False
            return True
Exemple #10
0
    def make_lights():
        """Create one point light and an ambient light.

        Return:
           (NodePath): Lights nodepath.

        """
        lights = NodePath("lights")
        # Create point lights.
        plight = PointLight("plight1")
        light = lights.attachNewNode(plight)
        light.setPos((3, -10, 2))
        light.lookAt(0, 0, 0)
        # Create ambient light.
        alight = AmbientLight("alight")
        alight.setColor((0.75, 0.75, 0.75, 1.0))
        lights.attachNewNode(alight)
        return lights
Exemple #11
0
def createPlane(width,height):

    format=GeomVertexFormat.getV3()
    vdata=GeomVertexData("vertices", format, Geom.UHStatic)

    vertexWriter=GeomVertexWriter(vdata, "vertex")
    vertexWriter.addData3f(0,0,0)
    vertexWriter.addData3f(width,0,0)
    vertexWriter.addData3f(width,height,0)
    vertexWriter.addData3f(0,height,0)

    #step 2) make primitives and assign vertices to them
    tris=GeomTriangles(Geom.UHStatic)

    #have to add vertices one by one since they are not in order
    tris.addVertex(0)
    tris.addVertex(1)
    tris.addVertex(3)

    #indicates that we have finished adding vertices for the first triangle.
    tris.closePrimitive()

    #since the coordinates are in order we can use this convenience function.
    tris.addConsecutiveVertices(1,3) #add vertex 1, 2 and 3
    tris.closePrimitive()

    #step 3) make a Geom object to hold the primitives
    squareGeom=Geom(vdata)
    squareGeom.addPrimitive(tris)

    #now put squareGeom in a GeomNode. You can now position your geometry in the scene graph.
    squareGN=GeomNode("square")
    squareGN.addGeom(squareGeom)

    terrainNode = NodePath("terrNode")
    terrainNode.reparentTo(render)
    terrainNode.attachNewNode(squareGN)
    terrainNode.setX(-width/2)
    texGrass = loader.loadTexture("textures/envir-ground.jpg")
    terrainNode.setTexture(texGrass)
Exemple #12
0
def loadTSX(filename):
    builtTiles = []
    animatedTiles = []
    folder, file = path.split(filename)
    ts = untangle.parse(filename).tileset
    size = int(ts["tilewidth"]), int(ts["tileheight"])
    cards = spriteSheetToCards(folder + "/" + ts.image['source'], size)
    for i in range(int(ts["tilecount"])):
        try:
            tile = ts.tile[i]
            animationData = tile.animation
            animatedTiles.append(tile)
        except (AttributeError, IndexError):
            tile = None

        if tile == None:
            tile = {"id":str(i), type:"none"}
        builtTiles.append([cards[i], tile])

    for tile in animatedTiles:
        animation = SequenceNode("animation")
        animationNode = NodePath("animationNode")

        for frame in tile.animation.frame:
            frameNode = builtTiles[int(frame["tileid"])][0].node()
            animation.addChild(frameNode)

        frameDuration = int(tile.animation.frame[0]["duration"])
        if frameDuration == 9999:
            fps = 0
        else:
            fps = 1000/frameDuration

        animation.setFrameRate(fps)
        animation.loop(True)
        animationNode.attachNewNode(animation)

        builtTiles[int(tile["id"])][0] = animationNode
    return builtTiles
    def renderQuadInto(self, mul=1, div=1, align=1, depthtex=None, colortex=None, auxtex0=None, auxtex1=None):

        """ Creates an offscreen buffer for an intermediate
        computation. Installs a quad into the buffer.  Returns
        the fullscreen quad.  The size of the buffer is initially
        equal to the size of the main window.  The parameters 'mul',
        'div', and 'align' can be used to adjust that size. """

        texgroup = (depthtex, colortex, auxtex0, auxtex1)

        winx, winy = self.getScaledSize(mul, div, align)
        
        depthbits = bool(depthtex != None)

        buffer = self.createBuffer("filter-stage", winx, winy, texgroup, depthbits)

        if (buffer == None):
            return None

        cm = CardMaker("filter-stage-quad")
        cm.setFrameFullscreenQuad()
        quad = NodePath(cm.generate())
        quad.setDepthTest(0)
        quad.setDepthWrite(0)
        quad.setColor(1, 0.5, 0.5, 1)

        quadcamnode = Camera("filter-quad-cam")
        lens = OrthographicLens()
        lens.setFilmSize(2, 2)
        lens.setFilmOffset(0, 0)
        lens.setNearFar(-1000, 1000)
        quadcamnode.setLens(lens)
        quadcam = quad.attachNewNode(quadcamnode)

        dr = buffer.makeDisplayRegion((0, 1, 0, 1))
        dr.disableClears()
        dr.setCamera(quadcam)
        dr.setActive(True)
        dr.setScissorEnabled(False)

        # This clear stage is important if the buffer is padded, so that
        # any pixels accidentally sampled in the padded region won't
        # be reading from unititialised memory.
        buffer.setClearColor((0, 0, 0, 1))
        buffer.setClearColorActive(True)

        self.buffers.append(buffer)
        self.sizes.append((mul, div, align))
        
        return quad
Exemple #14
0
def spriteSheetToCards(filename, tileSize):
    texture = loader.loadTexture(
        filename,
        minfilter=SamplerState.FT_nearest,
        magfilter=SamplerState.FT_nearest)

    cards = []
    columns = int(texture.getXSize()/tileSize[0])
    rows = int(texture.getYSize()/tileSize[1])
    uvWidth = 1/columns
    uvHeight = 1/rows

    for y in range(rows):
        for x in range(columns):
            part = NodePath(filename + "_tile_" + str(x)+"_"+str(y))
            part.attachNewNode(cardmaker.generate())
            part.setTexture(textureStage, texture)
            part.setTexScale(textureStage, uvWidth, uvHeight)
            ox, oy = uvWidth*x, (1-uvHeight)-(uvHeight*y)
            part.setTexOffset(textureStage, ox, oy)
            part.setTransparency(5, 1)
            part.setHpr(0,-90,0)
            cards.append(part)
    return cards
Exemple #15
0
class DistributedGardenBox(DistributedLawnDecor.DistributedLawnDecor):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGardenPlot')

    def __init__(self, cr):
        DistributedLawnDecor.DistributedLawnDecor.__init__(self, cr)
        self.plantPath = NodePath('plantPath')
        self.plantPath.reparentTo(self)
        self.plotScale = 1.0
        self.plantingGuiDoneEvent = 'plantingGuiDone'
        self.defaultModel = 'phase_5.5/models/estate/planterC'

    def announceGenerate(self):
        self.notify.debug('announceGenerate')
        DistributedLawnDecor.DistributedLawnDecor.announceGenerate(self)

    def doModelSetup(self):
        if self.typeIndex == GardenGlobals.BOX_THREE:
            self.defaultModel = 'phase_5.5/models/estate/planterA'
        elif self.typeIndex == GardenGlobals.BOX_TWO:
            self.defaultModel = 'phase_5.5/models/estate/planterC'
        else:
            self.defaultModel = 'phase_5.5/models/estate/planterD'
            self.collSphereOffset = 0.0
            self.collSphereRadius = self.collSphereRadius * 1.41
            self.plotScale = Vec3(1.0, 1.0, 1.0)

    def setupShadow(self):
        pass

    def loadModel(self):
        self.rotateNode = self.plantPath.attachNewNode('rotate')
        self.model = None
        self.model = loader.loadModel(self.defaultModel)
        self.model.setScale(self.plotScale)
        self.model.reparentTo(self.rotateNode)
        self.stick2Ground()
        return

    def handleEnterPlot(self, entry = None):
        pass

    def handleExitPlot(self, entry = None):
        DistributedLawnDecor.DistributedLawnDecor.handleExitPlot(self, entry)

    def setTypeIndex(self, typeIndex):
        self.typeIndex = typeIndex
Exemple #16
0
def buildMap(tmx):
    rootNode = NodePath("root")
    for l, layer in enumerate(tmx.map.layer):
        layerNode = rootNode.attachNewNode(layer["name"])
        unique = False
        if hasattr(layer, 'properties'):
            for property in layer.properties:
                unique_keys = ("unique", "seperate", "dynamic")
                if property.property["name"] in unique_keys:
                    unique = True

        for y, row in enumerate(layer.data):
            for x, tile in enumerate(row):
                if not tile == 0:
                    tileNode = tmx.tiles[tile-1][0]
                    tileObject = tmx.tiles[tile-1][1]
                    instance(layerNode, tileNode,
                        pos=(x,-y,l), hpr=(0,0,0), unique=unique)
        if not unique:
            layerNode.flattenStrong()
    rootNode.setLightOff()
    return rootNode
def rebuildGeomNodesToColPolys (incomingNode,relativeTo=None): 
    ''' 
    Converts GeomNodes into CollisionPolys in a straight 1-to-1 conversion 

    Returns a new NodePath containing the CollisionNodes 
    ''' 
    
    parent = NodePath('cGeomConversionParent') 
    for c in incomingNode.findAllMatches('**/+GeomNode'): 
        if relativeTo:
            xform=c.getMat(relativeTo).xformPoint
        else:
            xform=(c.getMat(incomingNode)*(incomingNode.getMat())).xformPoint
        gni = 0 
        geomNode = c.node() 
        for g in range(geomNode.getNumGeoms()): 
            geom = geomNode.getGeom(g).decompose() 
            vdata = geom.getVertexData() 
            vreader = GeomVertexReader(vdata, 'vertex') 
            cChild = CollisionNode('cGeom-%s-gni%i' % (c.getName(), gni)) 
            
            gni += 1 
            for p in range(geom.getNumPrimitives()): 
                prim = geom.getPrimitive(p) 
                for p2 in range(prim.getNumPrimitives()): 
                    s = prim.getPrimitiveStart(p2) 
                    e = prim.getPrimitiveEnd(p2) 
                    v = [] 
                    for vi in range (s, e): 
                        vreader.setRow(prim.getVertex(vi)) 
                        v.append (xform(vreader.getData3f())) 
                    colPoly = CollisionPolygon(*v) 
                    cChild.addSolid(colPoly) 

            n=parent.attachNewNode (cChild) 
            #n.show()
            
    return parent 
def getBam(mesh, filename):
    scene_members = pandacore.getSceneMembers(mesh)
    
    rotateNode = GeomNode("rotater")
    rotatePath = NodePath(rotateNode)
    matrix = numpy.identity(4)
    if mesh.assetInfo.upaxis == collada.asset.UP_AXIS.X_UP:
        r = collada.scene.RotateTransform(0,1,0,90)
        matrix = r.matrix
    elif mesh.assetInfo.upaxis == collada.asset.UP_AXIS.Y_UP:
        r = collada.scene.RotateTransform(1,0,0,90)
        matrix = r.matrix
    rotatePath.setMat(Mat4(*matrix.T.flatten().tolist()))
    
    for geom, renderstate, mat4 in scene_members:
        node = GeomNode("primitive")
        node.addGeom(geom)
        if renderstate is not None:
            node.setGeomState(0, renderstate)
        geomPath = rotatePath.attachNewNode(node)
        geomPath.setMat(mat4)

    rotatePath.flattenStrong()
    wrappedNode = pandacore.centerAndScale(rotatePath)
    
    model_name = filename.replace('/', '_')
    wrappedNode.setName(model_name)
    
    bam_temp = tempfile.mktemp(suffix = model_name + '.bam')
    wrappedNode.writeBamFile(bam_temp)
    
    bam_f = open(bam_temp, 'rb')
    bam_data = bam_f.read()
    bam_f.close()
    
    os.remove(bam_temp)
    
    return bam_data
def rebuildGeomNodesToColPolys (incomingNode,relativeTo=None,filter=lambda n:True): 
    ''' 
    Converts GeomNodes into CollisionPolys in a straight 1-to-1 conversion 

    Returns a new NodePath containing the CollisionNodes 
    
    If the geometry is at all complex, running the result of this through colTree
    should improve performance.
    
    '''
    parent = NodePath('cGeomConversionParent') 
    for c in incomingNode.findAllMatches('**/+GeomNode'): 
        if not filter(c): continue
        if relativeTo:
            xform=c.getMat(relativeTo).xformPoint
        else:
            xform=(c.getMat(incomingNode)*(incomingNode.getMat())).xformPoint
        geomNode = c.node() 
        for g in range(geomNode.getNumGeoms()): 
            geom = geomNode.getGeom(g).decompose() 
            vdata = geom.getVertexData() 
            vreader = GeomVertexReader(vdata, 'vertex') 
            cChild = CollisionNode("") 
            for p in range(geom.getNumPrimitives()): 
                prim = geom.getPrimitive(p) 
                for p2 in range(prim.getNumPrimitives()): 
                    s = prim.getPrimitiveStart(p2) 
                    e = prim.getPrimitiveEnd(p2) 
                    if e-s>2:
                        v = []
                        for vi in range (s, e): 
                            vreader.setRow(prim.getVertex(vi)) 
                            v.append(Point3(xform(vreader.getData3f())) )
                        colPoly = CollisionPolygon(*v) 
                        cChild.addSolid(colPoly) 
            n=parent.attachNewNode(cChild)   
    return parent 
    def _updateDebugNode(self):
        """ Internal method to generate new debug geometry. """
        debugNode = NodePath("PointLightDebugNode")
        debugNode.setPos(self.position)

        # Create the inner image 
        cm = CardMaker("PointLightDebug")
        cm.setFrameFullscreenQuad()
        innerNode = NodePath(cm.generate())
        innerNode.setTexture(Globals.loader.loadTexture("Data/GUI/Visualization/PointLight.png"))
        innerNode.setBillboardPointEye()
        innerNode.reparentTo(debugNode)

        # Create the outer lines
        lineNode = debugNode.attachNewNode("lines")

        # Generate outer circles
        points1 = []
        points2 = []
        points3 = []
        for i in range(self.visualizationNumSteps + 1):
            angle = float(
                i) / float(self.visualizationNumSteps) * math.pi * 2.0
            points1.append(Vec3(0, math.sin(angle), math.cos(angle)))
            points2.append(Vec3(math.sin(angle), math.cos(angle), 0))
            points3.append(Vec3(math.sin(angle), 0, math.cos(angle)))

        self._createDebugLine(points1, False).reparentTo(lineNode)
        self._createDebugLine(points2, False).reparentTo(lineNode)
        self._createDebugLine(points3, False).reparentTo(lineNode)
        lineNode.setScale(self.radius)

        # Remove the old debug node
        self.debugNode.node().removeAllChildren()

        # Attach the new debug node
        debugNode.reparentTo(self.debugNode)
Exemple #21
0
class FireflyDemo(ShowBase):
    def __init__(self):
        # Initialize the ShowBase class from which we inherit, which will
        # create a window and set up everything we need for rendering into it.
        ShowBase.__init__(self)
        self.setBackgroundColor((0, 0, 0, 0))

        # Preliminary capabilities check.

        if not self.win.getGsg().getSupportsBasicShaders():
            self.t = addTitle("Firefly Demo: Video driver reports that Cg "
                              "shaders are not supported.")
            return
        if not self.win.getGsg().getSupportsDepthTexture():
            self.t = addTitle("Firefly Demo: Video driver reports that depth "
                              "textures are not supported.")
            return

        # This algorithm uses two offscreen buffers, one of which has
        # an auxiliary bitplane, and the offscreen buffers share a single
        # depth buffer.  This is a heck of a complicated buffer setup.

        self.modelbuffer = self.makeFBO("model buffer", 1)
        self.lightbuffer = self.makeFBO("light buffer", 0)

        # Creation of a high-powered buffer can fail, if the graphics card
        # doesn't support the necessary OpenGL extensions.

        if self.modelbuffer is None or self.lightbuffer is None:
            self.t = addTitle("Toon Shader: Video driver does not support "
                              "multiple render targets")
            return

        # Create four render textures: depth, normal, albedo, and final.
        # attach them to the various bitplanes of the offscreen buffers.

        self.texDepth = Texture()
        self.texDepth.setFormat(Texture.FDepthStencil)
        self.texAlbedo = Texture()
        self.texNormal = Texture()
        self.texFinal = Texture()

        self.modelbuffer.addRenderTexture(self.texDepth,
            GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPDepthStencil)
        self.modelbuffer.addRenderTexture(self.texAlbedo,
            GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPColor)
        self.modelbuffer.addRenderTexture(self.texNormal,
            GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPAuxRgba0)

        self.lightbuffer.addRenderTexture(self.texFinal,
            GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPColor)

        # Set the near and far clipping planes.

        self.cam.node().getLens().setNear(50.0)
        self.cam.node().getLens().setFar(500.0)
        lens = self.cam.node().getLens()

        # This algorithm uses three cameras: one to render the models into the
        # model buffer, one to render the lights into the light buffer, and
        # one to render "plain" stuff (non-deferred shaded) stuff into the
        # light buffer.  Each camera has a bitmask to identify it.

        self.modelMask = 1
        self.lightMask = 2
        self.plainMask = 4

        self.modelcam = self.makeCamera(self.modelbuffer,
            lens=lens, scene=render, mask=self.modelMask)
        self.lightcam = self.makeCamera(self.lightbuffer,
            lens=lens, scene=render, mask=self.lightMask)
        self.plaincam = self.makeCamera(self.lightbuffer,
            lens=lens, scene=render, mask=self.plainMask)

        # Panda's main camera is not used.

        self.cam.node().setActive(0)

        # Take explicit control over the order in which the three
        # buffers are rendered.

        self.modelbuffer.setSort(1)
        self.lightbuffer.setSort(2)
        self.win.setSort(3)

        # Within the light buffer, control the order of the two cams.

        self.lightcam.node().getDisplayRegion(0).setSort(1)
        self.plaincam.node().getDisplayRegion(0).setSort(2)

        # By default, panda usually clears the screen before every
        # camera and before every window.  Tell it not to do that.
        # Then, tell it specifically when to clear and what to clear.

        self.modelcam.node().getDisplayRegion(0).disableClears()
        self.lightcam.node().getDisplayRegion(0).disableClears()
        self.plaincam.node().getDisplayRegion(0).disableClears()
        self.cam.node().getDisplayRegion(0).disableClears()
        self.cam2d.node().getDisplayRegion(0).disableClears()
        self.modelbuffer.disableClears()
        self.win.disableClears()

        self.modelbuffer.setClearColorActive(1)
        self.modelbuffer.setClearDepthActive(1)
        self.lightbuffer.setClearColorActive(1)
        self.lightbuffer.setClearColor((0, 0, 0, 1))

        # Miscellaneous stuff.

        self.disableMouse()
        self.camera.setPos(-9.112, -211.077, 46.951)
        self.camera.setHpr(0, -7.5, 2.4)
        random.seed()

        # Calculate the projection parameters for the final shader.
        # The math here is too complex to explain in an inline comment,
        # I've put in a full explanation into the HTML intro.

        proj = self.cam.node().getLens().getProjectionMat()
        proj_x = 0.5 * proj.getCell(3, 2) / proj.getCell(0, 0)
        proj_y = 0.5 * proj.getCell(3, 2)
        proj_z = 0.5 * proj.getCell(3, 2) / proj.getCell(2, 1)
        proj_w = -0.5 - 0.5 * proj.getCell(1, 2)

        # Configure the render state of the model camera.

        tempnode = NodePath(PandaNode("temp node"))
        tempnode.setAttrib(
            AlphaTestAttrib.make(RenderAttrib.MGreaterEqual, 0.5))
        tempnode.setShader(loader.loadShader("model.sha"))
        tempnode.setAttrib(DepthTestAttrib.make(RenderAttrib.MLessEqual))
        self.modelcam.node().setInitialState(tempnode.getState())

        # Configure the render state of the light camera.

        tempnode = NodePath(PandaNode("temp node"))
        tempnode.setShader(loader.loadShader("light.sha"))
        tempnode.setShaderInput("texnormal", self.texNormal)
        tempnode.setShaderInput("texalbedo", self.texAlbedo)
        tempnode.setShaderInput("texdepth", self.texDepth)
        tempnode.setShaderInput("proj", (proj_x, proj_y, proj_z, proj_w))
        tempnode.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd,
            ColorBlendAttrib.OOne, ColorBlendAttrib.OOne))
        tempnode.setAttrib(
            CullFaceAttrib.make(CullFaceAttrib.MCullCounterClockwise))
        # The next line causes problems on Linux.
        # tempnode.setAttrib(DepthTestAttrib.make(RenderAttrib.MGreaterEqual))
        tempnode.setAttrib(DepthWriteAttrib.make(DepthWriteAttrib.MOff))
        self.lightcam.node().setInitialState(tempnode.getState())

        # Configure the render state of the plain camera.

        rs = RenderState.makeEmpty()
        self.plaincam.node().setInitialState(rs)

        # Clear any render attribs on the root node. This is necessary
        # because by default, panda assigns some attribs to the root
        # node.  These default attribs will override the
        # carefully-configured render attribs that we just attached
        # to the cameras.  The simplest solution is to just clear
        # them all out.

        render.setState(RenderState.makeEmpty())

        # My artist created a model in which some of the polygons
        # don't have textures.  This confuses the shader I wrote.
        # This little hack guarantees that everything has a texture.

        white = loader.loadTexture("models/white.jpg")
        render.setTexture(white, 0)

        # Create two subroots, to help speed cull traversal.

        self.lightroot = NodePath(PandaNode("lightroot"))
        self.lightroot.reparentTo(render)
        self.modelroot = NodePath(PandaNode("modelroot"))
        self.modelroot.reparentTo(render)
        self.lightroot.hide(BitMask32(self.modelMask))
        self.modelroot.hide(BitMask32(self.lightMask))
        self.modelroot.hide(BitMask32(self.plainMask))

        # Load the model of a forest.  Make it visible to the model camera.
        # This is a big model, so we load it asynchronously while showing a
        # load text.  We do this by passing in a callback function.
        self.loading = addTitle("Loading models...")

        self.forest = NodePath(PandaNode("Forest Root"))
        self.forest.reparentTo(render)
        self.forest.hide(BitMask32(self.lightMask | self.plainMask))
        loader.loadModel([
            "models/background",
            "models/foliage01",
            "models/foliage02",
            "models/foliage03",
            "models/foliage04",
            "models/foliage05",
            "models/foliage06",
            "models/foliage07",
            "models/foliage08",
            "models/foliage09"],
            callback=self.finishLoading)

        # Cause the final results to be rendered into the main window on a
        # card.

        self.card = self.lightbuffer.getTextureCard()
        self.card.setTexture(self.texFinal)
        self.card.reparentTo(render2d)

        # Panda contains a built-in viewer that lets you view the results of
        # your render-to-texture operations.  This code configures the viewer.

        self.bufferViewer.setPosition("llcorner")
        self.bufferViewer.setCardSize(0, 0.40)
        self.bufferViewer.setLayout("vline")
        self.toggleCards()
        self.toggleCards()

        # Firefly parameters

        self.fireflies = []
        self.sequences = []
        self.scaleseqs = []
        self.glowspheres = []
        self.fireflysize = 1.0
        self.spheremodel = loader.loadModel("misc/sphere")

        # Create the firefly model, a fuzzy dot
        dotSize = 1.0
        cm = CardMaker("firefly")
        cm.setFrame(-dotSize, dotSize, -dotSize, dotSize)
        self.firefly = NodePath(cm.generate())
        self.firefly.setTexture(loader.loadTexture("models/firefly.png"))
        self.firefly.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.M_add,
            ColorBlendAttrib.O_incoming_alpha, ColorBlendAttrib.O_one))

        # these allow you to change parameters in realtime

        self.accept("escape", sys.exit, [0])
        self.accept("arrow_up",   self.incFireflyCount, [1.1111111])
        self.accept("arrow_down", self.decFireflyCount, [0.9000000])
        self.accept("arrow_right", self.setFireflySize, [1.1111111])
        self.accept("arrow_left",  self.setFireflySize, [0.9000000])
        self.accept("v", self.toggleCards)
        self.accept("V", self.toggleCards)

    def finishLoading(self, models):
        # This function is used as callback to loader.loadModel, and called
        # when all of the models have finished loading.

        # Attach the models to the scene graph.
        for model in models:
            model.reparentTo(self.forest)

        # Show the instructions.
        self.loading.destroy()
        self.title = addTitle("Panda3D: Tutorial - Fireflies using Deferred Shading")
        self.inst1 = addInstructions(0.06, "ESC: Quit")
        self.inst2 = addInstructions(0.12, "Up/Down: More / Fewer Fireflies (Count: unknown)")
        self.inst3 = addInstructions(0.18, "Right/Left: Bigger / Smaller Fireflies (Radius: unknown)")
        self.inst4 = addInstructions(0.24, "V: View the render-to-texture results")

        self.setFireflySize(25.0)
        while len(self.fireflies) < 5:
            self.addFirefly()
        self.updateReadout()

        self.nextadd = 0
        taskMgr.add(self.spawnTask, "spawner")

    def makeFBO(self, name, auxrgba):
        # This routine creates an offscreen buffer.  All the complicated
        # parameters are basically demanding capabilities from the offscreen
        # buffer - we demand that it be able to render to texture on every
        # bitplane, that it can support aux bitplanes, that it track
        # the size of the host window, that it can render to texture
        # cumulatively, and so forth.
        winprops = WindowProperties()
        props = FrameBufferProperties()
        props.setRgbColor(True)
        props.setRgbaBits(8, 8, 8, 8)
        props.setDepthBits(1)
        props.setAuxRgba(auxrgba)
        return self.graphicsEngine.makeOutput(
            self.pipe, "model buffer", -2,
            props, winprops,
            GraphicsPipe.BFSizeTrackHost | GraphicsPipe.BFCanBindEvery |
            GraphicsPipe.BFRttCumulative | GraphicsPipe.BFRefuseWindow,
            self.win.getGsg(), self.win)

    def addFirefly(self):
        pos1 = LPoint3(random.uniform(-50, 50), random.uniform(-100, 150), random.uniform(-10, 80))
        dir = LVector3(random.uniform(-1, 1), random.uniform(-1, 1), random.uniform(-1, 1))
        dir.normalize()
        pos2 = pos1 + (dir * 20)
        fly = self.lightroot.attachNewNode(PandaNode("fly"))
        glow = fly.attachNewNode(PandaNode("glow"))
        dot = fly.attachNewNode(PandaNode("dot"))
        color_r = 1.0
        color_g = random.uniform(0.8, 1.0)
        color_b = min(color_g, random.uniform(0.5, 1.0))
        fly.setColor(color_r, color_g, color_b, 1.0)
        fly.setShaderInput("lightcolor", color_r, color_g, color_b, 1.0)
        int1 = fly.posInterval(random.uniform(7, 12), pos1, pos2)
        int2 = fly.posInterval(random.uniform(7, 12), pos2, pos1)
        si1 = fly.scaleInterval(random.uniform(0.8, 1.5),
            LPoint3(0.2, 0.2, 0.2), LPoint3(0.2, 0.2, 0.2))
        si2 = fly.scaleInterval(random.uniform(1.5, 0.8),
            LPoint3(1.0, 1.0, 1.0), LPoint3(0.2, 0.2, 0.2))
        si3 = fly.scaleInterval(random.uniform(1.0, 2.0),
            LPoint3(0.2, 0.2, 0.2), LPoint3(1.0, 1.0, 1.0))
        siseq = Sequence(si1, si2, si3)
        siseq.loop()
        siseq.setT(random.uniform(0, 1000))
        seq = Sequence(int1, int2)
        seq.loop()
        self.spheremodel.instanceTo(glow)
        self.firefly.instanceTo(dot)
        glow.setScale(self.fireflysize * 1.1)
        glow.hide(BitMask32(self.modelMask | self.plainMask))
        dot.hide(BitMask32(self.modelMask | self.lightMask))
        dot.setColor(color_r, color_g, color_b, 1.0)
        self.fireflies.append(fly)
        self.sequences.append(seq)
        self.glowspheres.append(glow)
        self.scaleseqs.append(siseq)

    def updateReadout(self):
        self.inst2.destroy()
        self.inst2 = addInstructions(0.12,
            "Up/Down: More / Fewer Fireflies (Currently: %d)" % len(self.fireflies))
        self.inst3.destroy()
        self.inst3 = addInstructions(0.18,
            "Right/Left: Bigger / Smaller Fireflies (Radius: %d ft)" % self.fireflysize)

    def toggleCards(self):
        self.bufferViewer.toggleEnable()
        # When the cards are not visible, I also disable the color clear.
        # This color-clear is actually not necessary, the depth-clear is
        # sufficient for the purposes of the algorithm.
        if (self.bufferViewer.isEnabled()):
            self.modelbuffer.setClearColorActive(True)
        else:
            self.modelbuffer.setClearColorActive(False)

    def incFireflyCount(self, scale):
        n = int((len(self.fireflies) * scale) + 1)
        while (n > len(self.fireflies)):
            self.addFirefly()
        self.updateReadout()

    def decFireflyCount(self, scale):
        n = int(len(self.fireflies) * scale)
        if (n < 1):
            n = 1
        while (len(self.fireflies) > n):
            self.glowspheres.pop()
            self.sequences.pop().finish()
            self.scaleseqs.pop().finish()
            self.fireflies.pop().removeNode()
        self.updateReadout()

    def setFireflySize(self, n):
        n = n * self.fireflysize
        self.fireflysize = n
        for x in self.glowspheres:
            x.setScale(self.fireflysize * 1.1)
        self.updateReadout()

    def spawnTask(self, task):
        if task.time > self.nextadd:
            self.nextadd = task.time + 1.0
            if (len(self.fireflies) < 300):
                self.incFireflyCount(1.03)
        return Task.cont
    def _updateDebugNode(self):
        """ Internal method to generate new debug geometry. """
        debugNode = NodePath("SpotLightDebugNode")

        # Create the inner image 
        cm = CardMaker("SpotLightDebug")
        cm.setFrameFullscreenQuad()
        innerNode = NodePath(cm.generate())
        innerNode.setTexture(Globals.loader.loadTexture("Data/GUI/Visualization/SpotLight.png"))
        innerNode.setBillboardPointEye()
        innerNode.reparentTo(debugNode)
        innerNode.setPos(self.position)
        innerNode.setColorScale(1,1,0,1)

        # Create the outer lines
        lineNode = debugNode.attachNewNode("lines")

        currentNodeTransform = render.getTransform(self.ghostCameraNode).getMat()
        currentCamTransform = self.ghostLens.getProjectionMat()
        currentRelativeCamPos = self.ghostCameraNode.getPos(render)
        currentCamBounds = self.ghostLens.makeBounds()
        currentCamBounds.xform(self.ghostCameraNode.getMat(render))

        p = lambda index: currentCamBounds.getPoint(index)

        # Make a circle at the bottom
        frustumBottomCenter = (p(0) + p(1) + p(2) + p(3)) * 0.25
        upVector = (p(0) + p(1)) / 2 - frustumBottomCenter
        rightVector = (p(1) + p(2)) / 2 - frustumBottomCenter
        points = []
        for idx in xrange(64):
            rad = idx / 64.0 * math.pi * 2.0
            pos = upVector * math.sin(rad) + rightVector * math.cos(rad)
            pos += frustumBottomCenter
            points.append(pos)
        frustumLine = self._createDebugLine(points, True)
        frustumLine.setColorScale(1,1,0,1)
        frustumLine.reparentTo(lineNode)


        # Create frustum lines which connect the origin to the bottom circle
        pointArrays = [
            [self.position, frustumBottomCenter + upVector],
            [self.position, frustumBottomCenter - upVector],
            [self.position, frustumBottomCenter + rightVector],
            [self.position, frustumBottomCenter - rightVector],
        ]

        for pointArray in pointArrays:
            frustumLine = self._createDebugLine(pointArray, False)
            frustumLine.setColorScale(1,1,0,1)
            frustumLine.reparentTo(lineNode)

        # Create line which is in the direction of the spot light
        startPoint = (p(0) + p(1) + p(2) + p(3)) * 0.25
        endPoint = (p(4) + p(5) + p(6) + p(7)) * 0.25
        line = self._createDebugLine([startPoint, endPoint], False)
        line.setColorScale(1,1,1,1)
        line.reparentTo(lineNode)

        # Remove the old debug node
        self.debugNode.node().removeAllChildren()

        # Attach the new debug node
        debugNode.reparentTo(self.debugNode)
Exemple #23
0
def treeMe(parent, positions, uuids, geomCollide, center = None, side = None, radius = None, request_hash = b'Fake', pipe = None):
    """ Divide the space covered by all the objects into an oct tree and then
        replace cubes with 512 objects with spheres radius = (side**2 / 2)**.5
        for some reason this massively improves performance even w/o the code
        for mouse over adding and removing subsets of nodes.
    """
    num_points = len(positions)

    if not num_points:
        return None

    if type(center) == type(None):  # must use equality due to id changing across interpreters
        center = np.mean(positions, axis=0)
        norms = np.linalg.norm(positions - center, axis = 1)
        radius = np.max(norms) * .75  # align points to center of oct node
        side = ((4/3) * radius**2) ** .5
        if parent == None:
            l2Node = NodePath(CollisionNode('ObjectRoot for %s 0'%request_hash))  # TODO naming for search
        else:
            l2Node = parent.attachNewNode(CollisionNode('ObjectRoot for %s 0'%request_hash))
    else:
        #l2Node = parent.attachNewNode(CollisionNode('%s.%s. %s'%(request_hash, center, int(parent.getName()[-2:]) + 1)))
        l2Node = parent.attachNewNode(CollisionNode(' %s'%(int(parent.getName()[-2:]) + 1)))

    #base_mask = np.zeros_like(uuids, dtype=np.bool_)  # FIXME INSANE INTERACTION WITH SOMETHING panda related
    bitmasks = []
    for _ in range(8):
        bitmasks.append(np.array([False] * len(uuids)))  # must pass by value otherwise we have 8 of the same thing

    #bitmasks =  [ np.zeros_like(uuids,dtype=np.bool_) for _ in range(8) ]  # ICK there must be a better way of creating bitmasks
    partition = positions > center
    
    #the 8 conbinatorial cases
    for i in range(num_points):
        index = octit(partition[i])
        bitmasks[index][i] = True

    next_leaves = []
    for i in range(8):
        branch = bitmasks[i]
        new_center = center + TREE_LOGIC[i] * side * .5  #FIXME we pay a price here when we calculate the center of an empty node
        subSet = positions[branch]
        if len(subSet):
            next_leaves.append((l2Node, subSet, uuids[branch], geomCollide[branch], new_center, side * .5, radius * .5, request_hash))

    #This method can also greatly accelerate the neighbor traversal because it reduces the total number of nodes needed
    if num_points < TREE_MAX_POINTS:
        leaf_max = np.max([len(leaf[1]) for leaf in next_leaves])
        max_leaf = next_leaves[np.where([len(leaf[1]) for leaf in next_leaves] == leaf_max)[0][:1][0]]
        ml_center = np.mean(max_leaf[1],axis=0)
        if num_points < 4:
            c = np.mean(positions, axis=0)
            dists = []
            for p1 in positions:
                for p2 in positions:
                    if p1 is not p2:
                        d = np.linalg.norm(np.array(p2) - np.array(p1))
                        dists.append(d)
            r = np.max(dists) + np.mean(geomCollide) * 2  #max dists is the diameter so this is safe
            #l2Node.setName('leaf %s.%s. %s'%(request_hash, c, int(parent.getName()[-2:]) + 1))
            l2Node.node().addSolid(CollisionSphere(c[0],c[1],c[2],r))
            l2Node.node().setIntoCollideMask(BitMask32.bit(BITMASK_COLL_MOUSE))
        elif leaf_max > num_points * .90 and np.linalg.norm(ml_center - center) < radius * 2:  # FIXME something is VERY wrong, we should NEVER be generating cases where there are leaves outside the radius!!
            for leaf in next_leaves:
                treeMe(*leaf)
            #[treeMe(*leaf) for leaf in next_leaves]
            #l2Node.setName('branch '+l2Node.getName())
            l2Node.node().addSolid(CollisionSphere(center[0],center[1],center[2],radius * 2))
            l2Node.node().setIntoCollideMask(BitMask32.bit(BITMASK_COLL_MOUSE))  # this does not collide
            if pipe:  # extremely unlikely edge case
                print("hit an early pip")
                pipe.send(l2Node)
                pipe.close()
                return None
            else:
                return l2Node  # just for kicks even though all this is in place

        else:
            #l2Node.setName('leaf '+l2Node.getName())
            l2Node.node().addSolid(CollisionSphere(center[0],center[1],center[2],radius * 2))
            l2Node.node().setIntoCollideMask(BitMask32.bit(BITMASK_COLL_MOUSE))

        for p,uuid,geom in zip(positions,uuids,geomCollide):
            childNode = l2Node.attachNewNode(CollisionNode("%s"%uuid))  #XXX TODO
            childNode.node().addSolid(CollisionSphere(p[0],p[1],p[2],geom)) # we do it this way because it keeps framerates WAY higher dont know why
            childNode.node().setIntoCollideMask(BitMask32.bit(BITMASK_COLL_CLICK))
            childNode.setTag('uuid',uuid)
        return l2Node
    else:  # we are a containing node
        #l2Node.setName('branch '+l2Node.getName())
        l2Node.node().addSolid(CollisionSphere(center[0],center[1],center[2],radius * 2))
        l2Node.node().setIntoCollideMask(BitMask32.bit(BITMASK_COLL_MOUSE))  # this does not collide

    for leaf in next_leaves:
        treeMe(*leaf)
    #[treeMe(*leaf) for leaf in next_leaves]

    if pipe:
        pipe.send(l2Node)  # TODO we are going to solve this by sending childs? no, NODE GRRR
        #for c in l2Node.getChildren():
            #pipe.send(c)
            #l2Node.removeChild(c)
        #l2Node.removeAllChildren()
        #pipe.send(l2Node)

        
        #for s in to_send:
            #pipe.send(s)
        pipe.close()
    else:
        #embed()
        return l2Node  # just for kicks even though all this is in place
  def setupPhysics(self):

    # setting up physics world and parent node path 
    self.physics_world_ = BulletWorld()
    self.world_node_ = self.render.attachNewNode('world')
    self.cam.reparentTo(self.world_node_)
    self.physics_world_.setGravity(Vec3(0, 0, -9.81))

    self.debug_node_ = self.world_node_.attachNewNode(BulletDebugNode('Debug'))
    self.debug_node_.node().showWireframe(True)
    self.debug_node_.node().showConstraints(True)
    self.debug_node_.node().showBoundingBoxes(True)
    self.debug_node_.node().showNormals(True)
    self.physics_world_.setDebugNode(self.debug_node_.node())
    self.debug_node_.hide()
    
    # setting up collision groups
    self.physics_world_.setGroupCollisionFlag(GAME_OBJECT_BITMASK.getLowestOnBit(),GAME_OBJECT_BITMASK.getLowestOnBit(),True)
    self.physics_world_.setGroupCollisionFlag(SECTOR_ENTERED_BITMASK.getLowestOnBit(),SECTOR_ENTERED_BITMASK.getLowestOnBit(),True)
    self.physics_world_.setGroupCollisionFlag(GAME_OBJECT_BITMASK.getLowestOnBit(),SECTOR_ENTERED_BITMASK.getLowestOnBit(),False)
    

    # setting up ground
    self.ground_ = self.world_node_.attachNewNode(BulletRigidBodyNode('Ground'))
    self.ground_.node().addShape(BulletPlaneShape(Vec3(0, 0, 1), 0))
    self.ground_.setPos(0,0,0)
    self.ground_.setCollideMask(GAME_OBJECT_BITMASK)
    self.physics_world_.attachRigidBody(self.ground_.node())
    
    # creating level objects    
    self.setupLevelSectors()

    # creating controlled objects
    diameter = 0.4
    sphere_visual = loader.loadModel('models/ball.egg')

    bounds = sphere_visual.getTightBounds() # start of model scaling
    extents = Vec3(bounds[1] - bounds[0])
    scale_factor = diameter/max([extents.getX(),extents.getY(),extents.getZ()])
    sphere_visual.clearModelNodes()
    sphere_visual.setScale(scale_factor,scale_factor,scale_factor) # end of model scaling

    sphere_visual.setTexture(loader.loadTexture('models/bowl.jpg'),1)
    sphere = NodePath(BulletRigidBodyNode('Sphere'))
    sphere.node().addShape(BulletSphereShape(0.5*diameter))
    sphere.node().setMass(1.0)
    #sphere.node().setLinearFactor((1,0,1))
    #sphere.node().setAngularFactor((0,1,0))
    sphere.setCollideMask(GAME_OBJECT_BITMASK)
    sphere_visual.instanceTo(sphere)
    
    self.physics_world_.attachRigidBody(sphere.node())
    self.controlled_objects_.append(sphere) 
    sphere.reparentTo(self.world_node_)
    sphere.setPos(self.level_sectors_[0],Vec3(0,0,diameter+10))
    sphere.setHpr(self.level_sectors_[0],Vec3(0,0,0))
    
    # creating bullet ghost for detecting entry into other sectors
    player_ghost = sphere.attachNewNode(BulletGhostNode('player-ghost-node'))
    ghost_box_shape = BulletSphereShape(PLAYER_GHOST_DIAMETER/2)
    ghost_box_shape.setMargin(SECTOR_COLLISION_MARGIN)
    ghost_sphere_shape = BulletSphereShape(PLAYER_GHOST_DIAMETER*0.5)
    ghost_sphere_shape.setMargin(SECTOR_COLLISION_MARGIN)
    player_ghost.node().addShape(ghost_box_shape)
    player_ghost.setPos(sphere,Vec3(0,0,0))
    player_ghost.node().setIntoCollideMask(SECTOR_ENTERED_BITMASK)
    self.physics_world_.attach(player_ghost.node())

    # creating mobile box
    size = Vec3(0.2,0.2,0.4)
    mbox_visual = loader.loadModel('models/box.egg')
    bounds = mbox_visual.getTightBounds()
    extents = Vec3(bounds[1] - bounds[0])
    scale_factor = 1/max([extents.getX(),extents.getY(),extents.getZ()])
    mbox_visual.setScale(size.getX()*scale_factor,size.getY()*scale_factor,size.getZ()*scale_factor)

    mbox = NodePath(BulletRigidBodyNode('MobileBox'))
    mbox.node().addShape(BulletBoxShape(size/2))
    mbox.node().setMass(1.0)
    #mbox.node().setLinearFactor((1,0,1))
    #mbox.node().setAngularFactor((0,1,0))
    mbox.setCollideMask(GAME_OBJECT_BITMASK)
    mbox_visual.instanceTo(mbox)    
    self.physics_world_.attachRigidBody(mbox.node())
    self.controlled_objects_.append(mbox)
    mbox.reparentTo(self.level_sectors_[0])    
    mbox.setPos(Vec3(1,0,size.getZ()+1))
    
    # switching to sector 1
    self.switchToSector(self.level_sectors_[0])
Exemple #25
0
    def addActor(self, name, position=(0,0,0), orientation=(0,0,0), 
                 scale=(1,1,1), collisionSphere=None):
        # Create the scene node path.
        actor_np = NodePath(ActorNode(name))
        actor_np.setPosHpr(position, orientation)
        actor_np.reparentTo(self.render)

        # Attach model to the node path.
        base_path  = os.path.dirname(__file__)
        model_path = os.path.join(base_path, 'models', name)
        model_path = Filename.fromOsSpecific(model_path)
        model_np   = self.loader.loadModel(model_path)
        model_np.setScale(scale)
        model_np.reparentTo(actor_np)

        #=======================================================================
        # Make actor physics collidible.
        #=======================================================================
        # Attach collision solid to the node path. 
        cn = CollisionNode(name+'PhysicsCollisionNode')
        cn.setIntoCollideMask(BitMask32.allOff())
        cn.setFromCollideMask(BitMask32.bit(0))
        cs = CollisionSphere(collisionSphere[0:3], collisionSphere[3])
        cn.addSolid(cs)
        actor_cnp = actor_np.attachNewNode(cn)
        
        # Add actor to the physics collision detection system.
        handler = PhysicsCollisionHandler()
        handler.addCollider(actor_cnp, actor_np)
        # self.cTrav.addCollider(actor_cnp, handler)

        #=======================================================================
        # Make actor AI compatible.
        #=======================================================================
        ai_character = AICharacter(name, actor_np, mass=50, movt_force=10, 
                                   max_force=30)
        self.AICharacter[name] = ai_character
        self.AIWorld.addAiChar(ai_character)
        
        #=======================================================================
        # Make actor events collidible.
        #=======================================================================
        # Attach collision solid to the node path. 
        cn = CollisionNode(name+'EventCollisionNode')
        cn.setIntoCollideMask(BitMask32.allOff())
        cn.setFromCollideMask(BitMask32.bit(1))
        cs = CollisionSphere(collisionSphere[0:3], collisionSphere[3])
        cn.addSolid(cs)
        actor_cnp = actor_np.attachNewNode(cn)
        actor_cnp.show()
        
        # Add actor to the collision event detection system.
        handler = CollisionHandlerEvent()
        handler.addInPattern('%fn-enters')
        handler.addOutPattern('%fn-exits')
        self.cTrav.addCollider(actor_cnp, handler)
        self.accept(name+'EventCollisionNode'+'-enters', self.onActorEnterEventFunc)
        self.accept(name+'EventCollisionNode'+'-exits', self.onActorExitEventFunc)

        self.actorNP[name] = actor_np
        
        # The most recently added actor becomes actor of interest.
        self.setActorOfInterest(name)

        self.taskMgr.add(self.actorOIStateUpdateTask,'actorStateUpdate',sort=50)
class Army(GameObject):
    def __init__(self,player,name,x,y,soldiers,general=None):
        global army_count
        self.my_id = army_count
        army_count += 1

        print "ARMY ID IS",self.my_id

        self.name = name
        self.x = x
        self.y = y
        self.target_x = x
        self.target_y = y
        self.scale = counter_scale
        self.range = 50.0

        self.selected = False

        self.general = general
        self.soldiers = soldiers
        self.state = "normal"
        self.speed = 25.0

        self.battle = -1

        self.stat_init = 0.0
        self.stat_hit = 0.0
        self.stat_block = 0.0
        self.stat_delay = 0.0

        self.player = player
        if self.player == 0:
            self.colour = (0.5,0.5,0.5,1)
            self.model = loader.loadModel("models/infantry_counter_grey.egg")
        if self.player == 1:
            self.colour = (1,0,0,1)
            self.model = loader.loadModel("models/infantry_counter_red.egg")
        elif self.player == 2:
            self.colour = (0,1,0,1)
            self.model = loader.loadModel("models/infantry_counter_green.egg")

        self.node_path = NodePath("army"+str(self.my_id)+"_node_path")
        self.model.reparentTo(self.node_path)
        self.node_path.setPos(x,y,0)
        self.node_path.setTag("player",str(player))
        self.node_path.setScale(self.scale,self.scale,self.scale)

        self.node_col = self.node_path.attachNewNode(CollisionNode("army"+str(self.my_id)+"_c_node"))
        self.node_col.setScale((1,1,0.5))
        self.node_col.setPos(0,0,0)
        self.node_col.node().addSolid(CollisionSphere(0,0,0,1))
        self.node_col.setTag("type","army")
        base.cTrav.addCollider(self.node_col,base.col_manager.col_handler)
        #self.node_col.show()
        self.node_path.setTag("id",str(self.my_id))
        self.army_fight_col = self.node_path.attachNewNode(CollisionNode("army"+str(self.my_id)+"_batcol_node"))
        self.army_fight_col.setScale((2,2,0.5))
        self.army_fight_col.setPos(0,0,0)
        self.army_fight_col.node().addSolid(CollisionSphere(0,0,0,1))
        self.army_fight_col.setColor(1,0,0,0.1)
        self.army_fight_col.setTag("player",str(player))
        self.army_fight_col.setTag("state","normal")
        self.army_fight_col.setTag("type","army")
        base.cTrav.addCollider(self.army_fight_col,base.col_manager.col_handler)
        #self.army_fight_col.show()

        self.selection_ring = self.selection_ring_create(size = 1.2)
        self.selection_ring.reparentTo(self.node_path)
        self.selection_ring.hide()

        self.node_path.reparentTo(render)

    def turn_start(self):
        rate = 0.5
        army_scl_up = self.model.scaleInterval(rate, Point3(1.5, 1.5, 1.5))
        army_scl_down = self.model.scaleInterval(rate, Point3(1, 1, 1))
        self.sq_army_bat = Sequence(army_scl_up,army_scl_down)
        self.sq_army_bat.loop()

    def turn_end(self):
        try:
            self.sq_army_bat.finish()
        except:
            print "no sequence to end"

    def die(self):
        if base.single_player == False and base.client == False:
            base.net_manager.server_messager("army_kill",[self.my_id])
        self.state = "dead"
        self.army_fight_col.removeNode()
        self.node_col.removeNode()
        rate = 4
        intvl_shrink = self.model.scaleInterval(rate, Point3(0, 0, 0))
        func_destroy = Func(self.destroy)
        self.sq_die = Sequence(intvl_shrink,func_destroy)
        self.sq_die.start()
        base.battles[self.battle].recenter()
        base.battles[self.battle].shrink()
        if self.selected:
            i = base.col_manager.selecteds.index(self)
            del base.col_manager.selecteds[i]

    def stop(self):
        try:
            self.sq_army_move.pause()
        except:
            print "already stopped"

    def move_to_point(self,tx,ty):
            self.target_x = tx
            self.target_y = ty
            dist = float(TCalc.dist_to_point(self.node_path.getX(),self.node_path.getY(),tx,ty))
            print dist
            #time = dist/speed
            #print dist/speed
            #print time*speed,dist
            try:
                self.sq_army_move.pause()
                self.intvl_army_move = None
            except:
                print "no sequence"

            if dist > 1:
                self.intvl_army_move = self.node_path.posInterval(dist/self.speed, Point3(self.target_x, self.target_y, 0),startPos=Point3(self.node_path.getX(), self.node_path.getY(), 0))
                self.sq_army_move = Sequence(self.intvl_army_move)
                self.sq_army_move.start()
            else:
                try:
                    self.sq_army_move.finish()
                except:
                    print "no sequence"

    def set_target(self,sender,tx,ty):
        if self.state == "normal":
            if base.single_player == False:
                base.net_manager.army_move(self.my_id,tx,ty)
            else:
                self.move_to_point(tx,ty)

    def battle_shuffle(self,tx,ty):
        if base.single_player == False:
            base.net_manager.army_move(self.my_id,tx,ty)
        else:
            self.move_to_point(tx,ty)
Exemple #27
0
    def test_door_setup(self):
        parent_np = NodePath('parent_np')
        parent_np.setPosHpr(0, 10, .5, 180, 0, 0)

        door_origin = parent_np.attachNewNode('door_origin')
        door_origin.setPos(10, -25, .5)

        block = 4
        color = Vec4(.842, .167, .361, 1)

        # Set up door_np nodes
        door_np = NodePath('door_np')

        left_hole = door_np.attachNewNode('door_0_hole_left')
        right_hole = door_np.attachNewNode('door_0_hole_right')

        left_door = door_np.attachNewNode('door_0_left')
        right_door = door_np.attachNewNode('door_0_right')

        door_flat = door_np.attachNewNode('door_0_flat')
        door_trigger = door_np.attachNewNode('door_0_trigger')

        DNADoor.setupDoor(door_np, parent_np, door_origin, self.store, block, color)

        # Check if the nodes attributes and parents are correct
        self.assertEqual(door_np.getPos(door_origin), Point3(0, 0, 0))
        self.assertEqual(door_np.getHpr(door_origin), Point3(0, 0, 0))
        self.assertEqual(door_np.getScale(door_origin), Point3(1, 1, 1))

        def verify_color(color1, color2):
            self.assertAlmostEqual(color1.getX(), color2.getX(), places=4)
            self.assertAlmostEqual(color1.getY(), color2.getY(), places=4)
            self.assertAlmostEqual(color1.getZ(), color2.getZ(), places=4)
            self.assertAlmostEqual(color1.getW(), color2.getW(), places=4)

        verify_color(color, door_np.getColor())

        self.assertEqual(left_hole.getParent(), door_flat)
        self.assertEqual(left_hole.getName(), 'doorFrameHoleLeft')

        self.assertEqual(right_hole.getParent(), door_flat)
        self.assertEqual(right_hole.getName(), 'doorFrameHoleRight')

        self.assertEqual(left_door.getParent(), parent_np)
        self.assertEqual(left_door.getName(), 'leftDoor')
        verify_color(color, right_door.getColor())

        self.assertEqual(right_door.getParent(), parent_np)
        self.assertEqual(right_door.getName(), 'rightDoor')
        verify_color(color, right_door.getColor())

        self.assertEqual(door_trigger.getParent(), parent_np)
        self.assertEqual(door_trigger.getName(), 'door_trigger_%d' % block)

        store_np = self.store.getDoorPosHprFromBlockNumber(block)
        self.assertFalse(store_np.isEmpty())

        # Testing the pos is a pain because of decimal precision
        pos = store_np.getPos()
        self.assertAlmostEqual(pos.getX(), -10, places=2)
        self.assertAlmostEqual(pos.getY(), 35, places=2)
        self.assertAlmostEqual(pos.getZ(), 1, places=2)

        # Sometimes getH() returns -180 and others 180
        # Test the modulus (better than abs I guess)
        self.assertEqual(store_np.getH() % 180, 0)
class Battle(GameObject):
    def __init__(self,counters,start=-1):
        global battle_count

        self.combatants = counters
        self.my_id = battle_count
        self.turn = 0
        self.chance_range = 100
        self.chance_success = 80

        self.col_scale_orig = 2.0
        self.col_scale = self.col_scale_orig
        self.col_scale_inc = 0.4

        battle_count += 1

        if start != -1:
            self.turn = start
            self.combatants[start].turn_start()

        coords = [(self.combatants[0].get_x(),self.combatants[0].get_y()),(self.combatants[1].get_x(),self.combatants[1].get_y())]
        self.x,self.y = TCalc.midpoint(coords)

        self.node_path = NodePath("battle"+str(self.my_id)+"_node_path")
        self.node_path.setPos(self.x,self.y,0)
        self.node_path.setTag("id",str(self.my_id))
        self.node_path.setTag("type","battle")
        self.node_path.reparentTo(render)

        self.bat_col = self.node_path.attachNewNode(CollisionNode("battle"+str(self.my_id)+"_c_node"))
        self.bat_col.setScale((self.col_scale,self.col_scale,0.2))
        self.bat_col.setPos(0,0,0)
        self.bat_col.node().addSolid(CollisionSphere(0,0,0,10))
        self.bat_col.setTag("type","battle")
        self.bat_col.show()

        self.battle_speed = 1.0

        for a in self.combatants:
            #a.turn_start()
            a.stop()
            a.state = "battle"
            a.army_fight_col.setTag("state","battle")
            a.battle = self.my_id

        if base.client == False:
            taskMgr.add(self.battle_init_rolls, "battle"+str(self.my_id)+"_task_start")

    def recenter(self):
        new_x = 0.0
        new_y = 0.0
        x_list = []
        y_list = []
        counter = 0
        try:
            for a in self.combatants:
                if a.state != "dead":
                    x_list.append(a.node_path.getX())
                    y_list.append(a.node_path.getY())
                    counter += 1
                    new_x += a.node_path.getX()
                    new_y += a.node_path.getY()
            new_x /= len(x_list)
            new_y /= len(y_list)

            self.node_path.setPos(new_x,new_y,0)
        except:
            pass

    def shrink(self):
        if len(self.combatants) <= 10:
            self.col_scale -= self.col_scale_orig*self.col_scale_inc
            self.bat_col.setScale((self.col_scale,self.col_scale,0.2))

    def battle_init_rolls(self,task):
        init_rolls = []
        highest_roll = -1
        counter = 0
        leader = 0
        for a in self.combatants:
            roll = random.randint(0,self.chance_range)+a.stat_init
            print counter,"rolled",roll
            init_rolls.append(roll)
            if roll > highest_roll:
                highest_roll = roll
                leader = counter
            counter += 1
        self.turn = leader
        print leader,"wins!"
        self.combatants[self.turn].turn_start()

        a1 = self.combatants[0]
        a2 = self.combatants[1]

        if base.client == False:
            if base.single_player == False:
                base.net_manager.server_messager("battle_start",[a1.my_id,a1.node_path.getX(),a1.node_path.getY(),
                                                                 a2.my_id,a2.node_path.getX(),a2.node_path.getY(),
                                                                 self.turn])
            taskMgr.doMethodLater(1,self.battle_loop,"battle"+str(self.my_id)+"_task_loop")
        self.get_odds()
        return task.done

    def get_odds(self):
        side1 = []
        side2 = []
        counter = 0
        for a in self.combatants:
            if a.player == 1 and a.state != "dead":
                side1.append(a)
                counter += 1
            elif a.player == 2 and a.state != "dead":
                side2.append(a)
                counter += 1
        self.odds = (100/counter)*len(side1)
        if base.col_manager.selected_node == self.node_path:
            base.vis_manager.statbar.refresh_battle(self.odds)

    def target_recheck(self):
        army = self.combatants[self.turn]
        target_id = random.randint(0,len(self.combatants)-1)
        target = self.combatants[target_id]
        while target == army or target.player == army.player or target.state == "dead":
            target_id = random.randint(0,len(self.combatants)-1)
            target = self.combatants[target_id]
            print "recheck target - aquired",target_id
        return army,target,target_id

    def turn_change(self,new_turn):
        self.combatants[self.turn].turn_end()
        self.combatants[new_turn].turn_start()
        self.turn = new_turn

    def battle_loop(self,task):
        towerBuff = 0
        battle_end = False
        army,target,target_id = self.target_recheck()

        task.delayTime = self.battle_speed+army.stat_delay
        roll = random.randint(0,self.chance_range)+army.stat_hit

        #Make towers pown arse
        for t in base.towers:
            if t.player == army.player:
                distanceToTower = base.calculator.dist_to_point(army.get_x(),army.get_y(),t.get_x(),t.get_y())
                if  distanceToTower < 80:
                    towerBuff = random.randint(0, 40)
                    roll+=towerBuff

        if roll >= self.chance_success:
            roll = random.randint(0,self.chance_range)+target.stat_block
            if roll >= self.chance_success:
                result = "block"
            else:
                result = "hit"
                target.state = "dead"
                battle_end = True
                for a in self.combatants:
                    if a.player != army.player and a.state != "dead":
                        battle_end = False
        else:
            result = "fail"

        if base.client == False and base.single_player == False:
            randomness = 80
            army.battle_shuffle(self.node_path.getX()+random.randint(0,randomness)-randomness/2,self.node_path.getY()+random.randint(0,randomness)-randomness/2)

        if base.single_player == False:
            base.net_manager.server_messager("battle_clash",[self.my_id,army.my_id,target.my_id,result,towerBuff])
        self.clash(army,target,result,towerBuff)

        army.turn_end()
        last_turn = self.turn

        if battle_end:
            if base.single_player == False:
                base.net_manager.server_messager("battle_end",[self.my_id])
            self.end()
            return task.done
        else:
            self.get_odds()
            if self.turn < len(self.combatants)-1:
                self.turn += 1
            else:
                self.turn = 0
            while self.combatants[self.turn].state == "dead":
                if self.turn < len(self.combatants)-1:
                    self.turn += 1
                else:
                    self.turn = 0
            if base.single_player == False:
                base.net_manager.server_messager("battle_turn",[self.my_id,self.turn])
            self.combatants[self.turn].turn_start()
            return task.again

    def end(self):
        if base.col_manager.selected_node == self.node_path:
                base.vis_manager.statbar.reset_statbar()
        for a in self.combatants:
            a.turn_end()
            if a.state != "dead":
                a.state = "normal"
                a.battle = -1
                a.army_fight_col.setTag("state","normal")
        self.destroy()

    def clash(self,a1,a2,result,buff):
        if buff != 0:
            buffText = "^+" +str(buff)
            TimVisuals.BattleText(self.node_path,buffText,self.x,self.y + 10,(1,1,0,1))
        if result == "block":
            TimVisuals.BattleText(self.node_path,"BLOCK!",self.x,self.y,a2.colour)
        elif result == "hit":
            TimVisuals.BattleText(self.node_path,"HIT AND KILL!",self.x,self.y,a1.colour)
            a2.state = "dead"
            a2.die()
        else:
            TimVisuals.BattleText(self.node_path,"Attack Failed!",self.x,self.y,a1.colour)

    def add_army(self,army):
        army.stop()
        army.state = "battle"
        army.army_fight_col.setTag("state","battle")
        army.battle = self.my_id
        self.combatants.append(army)
        if len(self.combatants) <= 10:
            self.col_scale += self.col_scale_orig*self.col_scale_inc
            self.bat_col.setScale((self.col_scale,self.col_scale,0.2))

        self.get_odds()
        self.recenter()

    def destroy(self):
        self.node_path.removeNode()
class Tower(GameObject):
    def __init__(self,player,name,x,y,income):
        global tower_count
        self.my_id = tower_count
        tower_count += 1
        self.player = player
        self.name = name
        self.x = x
        self.y = y
        self.state = "normal"
        self.build_progress = 0.0
        self.build_speed = 1.0
        self.gold_inc = 1.0
        if base.player == self.player:
            base.ecn_manager.gold_inc += self.gold_inc
            base.vis_manager.update()

        self.model_list = ["models/farmhouse_grey.egg","models/farmhouse_red.egg","models/farmhouse_green.egg"]
        self.model_list = ["models/tower_grey.egg","models/tower_red.egg","models/tower_green.egg"]
        self.model = loader.loadModel(self.model_list[self.player])

#        if self.player == 0:
#            self.model = loader.loadModel("models/tower_grey.egg")
#        elif self.player == 1:
#            self.model = loader.loadModel("models/tower_red.egg")
#        elif self.player == 2:
#            self.model = loader.loadModel("models/tower_green.egg")

        self.node_path = NodePath("tower"+str(self.my_id)+"_node_path")
        self.model.reparentTo(self.node_path)
        self.node_path.setPos(x,y,0)
        self.node_path.setTag("player",str(player))
        self.node_path.setScale(tower_scale,tower_scale,tower_scale)
        self.node_path.setColor(1,1,1,0.1)

        self.node_col = self.node_path.attachNewNode(CollisionNode("tower"+str(self.my_id)+"_c_node"))
        self.node_col.setScale((2,2,1))
        self.node_col.setPos(0,0,0)
        self.node_col.node().addSolid(CollisionSphere(0,0,0,1))
        self.node_col.setTag("type","tower")
        base.cTrav.addCollider(self.node_col,base.col_manager.col_handler)
        #self.node_col.show()
        self.node_path.setTag("id",str(self.my_id))
        self.tower_fight_col = self.node_path.attachNewNode(CollisionNode("tower"+str(self.my_id)+"_batcol_node"))
        self.tower_fight_col.setScale((2,2,0.5))
        self.tower_fight_col.setPos(0,0,0)
        self.tower_fight_col.node().addSolid(CollisionSphere(0,0,0,1))
        self.tower_fight_col.setColor(1,0,0,0.1)
        self.tower_fight_col.setTag("player",str(player))
        self.tower_fight_col.setTag("state","normal")
        #self.tower_fight_col.show()
        base.cTrav.addCollider(self.tower_fight_col,base.col_manager.col_handler)

        self.selection_ring = self.selection_ring_create(size = 1.5)
        self.selection_ring.reparentTo(self.node_path)
        self.selection_ring.hide()

        self.node_path.reparentTo(render)

    def capture_check(self):
        has_guard = False
        for a in base.armies:
            if a.player == self.player and (a.state == "normal" or a.state == "battle"):
                if base.calculator.dist_to_point(self.get_x(),self.get_y(),a.get_x(),a.get_y()) < 80:
                    has_guard = True
        if has_guard == True:
            return False
        else:
            return True

    def change_owner(self,new_owner):
        if self.player == base.player:
            base.ecn_manager.gold_inc -= self.gold_inc
        elif new_owner == base.player:
            base.ecn_manager.gold_inc += self.gold_inc
        base.vis_manager.update()
        self.model.remove()
        self.model = loader.loadModel(self.model_list[new_owner])
        self.node_path.setTag("player",str(new_owner))
        self.tower_fight_col.setTag("player",str(new_owner))
        self.player = new_owner
        self.model.reparentTo(self.node_path)

    def build_cancel(self):
        if self.player == base.player:
            base.ecn_manager.gold += base.ecn_manager.cost_army_gold
            base.vis_manager.update()
        if base.single_player == False and base.client == False:
                base.net_manager.server_messager("build_cancel",[self.my_id])
        taskMgr.remove("task_tower"+str(self.my_id)+"_build")
        self.build_progress = 0.0
        if base.vis_manager.statbar.focus == self:
            base.vis_manager.statbar.show_tower(self.my_id)

    def build_start(self):
        if self.player == base.player:
            base.ecn_manager.gold -= base.ecn_manager.cost_army_gold
            base.vis_manager.update()
        print "Started Building"
        if base.single_player == False and base.client == False:
                base.net_manager.server_messager("build_start",[self.my_id,self.player,"army"])
        self.build_progress = self.build_speed
        taskMgr.add(self.task_build,"task_tower"+str(self.my_id)+"_build")
        if base.vis_manager.statbar.focus == self:
            base.vis_manager.statbar.show_tower(self.my_id)

    def build_start_request(self):
        base.net_manager.client_messager("build_start_request",[self.my_id,self.player,"army"])

    def build_cancel_request(self):
        base.net_manager.client_messager("build_cancel_request",[self.my_id])

    def task_build(self,task):
        if self.build_progress < 100.00:
            self.build_progress += self.build_speed
            if base.vis_manager.statbar.focus == self:
                base.vis_manager.statbar.bar_build.set_value(self.build_progress)
            return Task.again
        else:
            self.build_progress = 0.0
            if base.vis_manager.statbar.focus == self:
                base.vis_manager.statbar.show_tower(self.my_id)
            if base.single_player == False and base.client == False:
                base.net_manager.server_messager("build_complete",[self.my_id,self.player,"army"])
            if base.client == False:
                self.create_counter()
            return Task.done

    def create_counter(self):
        new_army = Army(self.player,"Infantry",self.node_path.getX(),self.node_path.getY(),1)
        base.armies.append(new_army)
        new_army.state = "new"
        new_army.army_fight_col.setTag("state","new")
        intvl_exit = new_army.node_path.posInterval(2, Point3(self.x, self.y-24, 0),startPos=Point3(self.x, self.y, 0))

        def army_ready():
            new_army.state = "normal"
            new_army.army_fight_col.setTag("state","normal")

        func_armyready = Func(army_ready)
        sq_army_move = Sequence(intvl_exit,func_armyready)
        sq_army_move.start()
class DistributedTreasure(DistributedObject):
    notify = directNotify.newCategory('DistributedTreasure')

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.grabSoundPath = None
        self.rejectSoundPath = 'phase_4/audio/sfx/ring_miss.mp3'
        self.dropShadow = None
        self.treasureTrack = None
        self.nodePath = None
        self.modelPath = None
        self.modelChildString = None
        self.sphereRadius = 2.0
        self.scale = 1.0
        self.zOffset = 0.0
        self.playSoundForRemoteToons = True
        self.fly = True
        self.shadow = True
        self.billboard = False
        self.av = None
        return

    def announceGenerate(self):
        DistributedObject.announceGenerate(self)
        self.loadModel(self.modelPath, self.modelChildString)
        self.startAnimation()
        self.nodePath.reparentTo(render)
        self.accept(self.uniqueName('entertreasureSphere'), self.handleEnterSphere)

    def loadModel(self, mdlPath, childString = None):
        self.grabSound = base.loadSfx(self.grabSoundPath)
        self.rejectSound = base.loadSfx(self.rejectSoundPath)
        if self.nodePath == None:
            self.makeNodePath()
        else:
            self.treasure.getChildren().detach()
        model = loader.loadModel(mdlPath)
        if childString:
            model = model.find('**/' + childString)
        model.instanceTo(self.treasure)
        return

    def makeNodePath(self):
        self.nodePath = NodePath('treasure')
        if self.billboard:
            self.nodePath.setBillboardPointEye()
        self.nodePath.setScale(0.9 * self.scale)
        self.treasure = self.nodePath.attachNewNode('treasure')
        if self.shadow:
            if not self.dropShadow:
                self.dropShadow = loader.loadModel('phase_3/models/props/drop_shadow.bam')
                self.dropShadow.setColor(0, 0, 0, 0.5)
                self.dropShadow.setPos(0, 0, 0.025)
                self.dropShadow.setScale(0.4 * self.scale)
                self.dropShadow.flattenLight()
            self.dropShadow.reparentTo(self.nodePath)
        collSphere = CollisionSphere(0, 0, 0, self.sphereRadius)
        collSphere.setTangible(0)
        collNode = CollisionNode(self.uniqueName('treasureSphere'))
        collNode.setIntoCollideMask(CIGlobals.WallBitmask)
        collNode.addSolid(collSphere)
        self.collNodePath = self.nodePath.attachNewNode(collNode)
        self.collNodePath.stash()

    def handleEnterSphere(self, collEntry = None):
        localAvId = base.localAvatar.doId
        if not self.fly:
            self.setGrab(localAvId)
        self.d_requestGrab()

    def setPosition(self, x, y, z):
        if not self.nodePath:
            self.makeNodePath()
        self.nodePath.reparentTo(render)
        self.nodePath.setPos(x, y, z + self.zOffset)
        self.collNodePath.unstash()

    def setReject(self):
        self.cleanupTrack()
        base.playSfx(self.rejectSound, node=self.nodePath)
        self.treasureTrack = Sequence(LerpColorScaleInterval(self.nodePath, 0.8, colorScale=VBase4(0, 0, 0, 0), startColorScale=VBase4(1, 1, 1, 1), blendType='easeIn'), LerpColorScaleInterval(self.nodePath, 0.2, colorScale=VBase4(1, 1, 1, 1), startColorScale=VBase4(0, 0, 0, 0), blendType='easeOut', name='treasureFlyTrack'))
        self.treasureTrack.start()

    def setGrab(self, avId):
        self.collNodePath.stash()
        self.avId = avId
        if self.cr.doId2do.has_key(avId):
            self.av = self.cr.doId2do[avId]
        else:
            self.nodePath.detachNode()
            return
        if self.playSoundForRemoteToons or self.avId == base.localAvatar.doId:
            base.playSfx(self.grabSound, node=self.nodePath)
        if not self.fly:
            self.nodePath.detachNode()
            return
        self.cleanupTrack()
        avatarGoneName = self.av.uniqueName('disable')
        self.accept(avatarGoneName, self.handleUnexpectedExit)
        flyTime = 1.0
        track = Sequence(LerpPosInterval(self.nodePath, flyTime, pos=Point3(0, 0, 3), startPos=self.nodePath.getPos(self.av), blendType='easeInOut'), Func(self.nodePath.detachNode), Func(self.ignore, avatarGoneName))
        if self.shadow:
            self.treasureTrack = Sequence(HideInterval(self.dropShadow), track, ShowInterval(self.dropShadow), name='treasureFlyTrack')
        else:
            self.treasureTrack = Sequence(track, name='treasureFlyTrack')
        self.nodePath.reparentTo(self.av)
        self.treasureTrack.start()

    def handleUnexpectedExit(self):
        self.notify.warning('%s disconnected while collecting treasure.' % str(self.avId))
        self.cleanupTrack()

    def d_requestGrab(self):
        self.sendUpdate('requestGrab', [])

    def startAnimation(self):
        pass

    def disable(self):
        self.ignoreAll()
        self.nodePath.detachNode()
        DistributedObject.disable(self)

    def cleanupTrack(self):
        if self.treasureTrack:
            self.treasureTrack.finish()
            self.treasureTrack = None
        return

    def delete(self):
        self.cleanupTrack()
        DistributedObject.delete(self)
        self.nodePath.removeNode()