def changeModel(newmodel): tempParent=NodePath('') newModel=loader.loadModel(newmodel) newModel.findAllMatches('**/+GeomNode').reparentTo(tempParent) tempParent.setScale(1.5/tempParent.getBounds().getRadius()) tempParent.setPos(-tempParent.getBounds().getCenter()) tempParent.flattenStrong() tempParent.find('**/+GeomNode').node().replaceNode(model.node())
class Character(DirectObject, XMLExportable, PropertiesTableAbstract, GameEntity): def __init__(self, attributes, showCollisions, grid_currentx, grid_currenty, grid_playable_pos, parent): GameEntity.__init__(self, parent) #running parent constructor self.movtask = 0 self.showCollisions = showCollisions self.grid_currentx = grid_currentx self.grid_currenty = grid_currenty self.grid_playable_pos = grid_playable_pos self.attributes = attributes self.onPicked = '' self.onWalked = '' self.typeName = 'character' self.properties = { 'url': '', 'onWalked': '', 'onPicked': '', 'id': '', 'inclination': '', 'scale': '', 'hitboxscale': '', 'speed': '', 'playable': '', 'direction': '' } if attributes.has_key('url'): self.properties['url'] = attributes['url'].value else: print "WARNING: url not defined, loading placeholder" self.properties['url'] = 'misc/placeholder' if attributes.has_key('id'): self.properties['id'] = attributes['id'].value else: self.properties['id'] = 'all' if attributes.has_key('inclination'): self.properties['inclination'] = float( attributes['inclination'].value) else: self.properties['inclination'] = 30.0 if attributes.has_key('scale'): self.properties['scale'] = float(attributes['scale'].value) else: self.properties['scale'] = 1.0 if attributes.has_key('hitboxscale'): self.properties['hitboxscale'] = float( attributes['hitboxscale'].value) else: self.properties['hitboxscale'] = 1.0 if attributes.has_key('speed'): self.properties['speed'] = float(attributes['speed'].value) else: self.properties['speed'] = 1.0 #self.isNPC remains true while isPlayable is changable if attributes.has_key('playable'): self.playable = playable = attributes['playable'].value if self.playable == 'false': self.isNPC = False #print "setting ", self.properties['id'], " to ", self.isNPC else: self.isNPC = True #print "setting ", self.properties['id'], " to ", self.isNPC else: self.playable = playable = 'false' self.isNPC = True self.properties['playable'] = self.playable if attributes.has_key('direction'): self.properties['direction'] = attributes['direction'].value else: self.properties['direction'] = "down" if attributes.has_key('onWalked'): self.properties['onWalked'] = self.onWalked = attributes[ 'onWalked'].value else: self.properties['onWalked'] = self.onWalked = "" if attributes.has_key('onPicked'): self.properties['onPicked'] = self.onPicked = attributes[ 'onPicked'].value self.generateNode(showCollisions) def generateNode(self, showCollisions): self.destroy() #setting local variable attributes = self.attributes #defaulted to None self.pickCTrav = None #movement self.state = "still" self.showCollisions = showCollisions self.movtask = 0 self.currentlydown = [] self.currentlyfollowed = 0 self.pickRequest = False #public props self.node = NodePath("characternode") self.node.setTwoSided(True) self.wtop = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/wtop.egg')) self.wdown = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/wdown.egg')) self.wleft = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/wleft.egg')) self.wright = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/wright.egg')) self.stop = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/stop.egg')) self.sdown = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/sdown.egg')) self.sleft = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/sleft.egg')) self.sright = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/sright.egg')) #Texture.FTNearest self.wtop.reparentTo(self.node) self.wdown.reparentTo(self.node) self.wleft.reparentTo(self.node) self.wright.reparentTo(self.node) self.stop.reparentTo(self.node) self.sdown.reparentTo(self.node) self.sleft.reparentTo(self.node) self.sright.reparentTo(self.node) self.leftdown = False self.rightdown = False self.downdown = False self.topdown = False if self.playable == "true": self.setPlayable( False) #seems nonsense, triggered on grid.changeMap event self.node.setTag( "playable", "true" ) #setting this to make it recognizable from grid changeMap api self.setCollisions(True) self.setPickCollisions(True) else: self.setPlayable(False) self.node.setTag("playable", "false") self.setCollisions(False) self.setPickCollisions(False) #self.node.setX((-32/2)+0.5) self.node.setP(-(360 - int(self.properties['inclination']))) self.node.setScale(float(self.properties['scale'])) self.node.setTransparency(TransparencyAttrib.MAlpha) self.lastpos = self.node.getPos() self.showAllSubnodes() #taskMgr.doMethodLater(4, self.face, 'charload'+self.properties['id'], [self.properties['direction']]) self.face(self.properties['direction']) #set unique id self.node.setTag("id", self.properties['id']) #setting scripting part self.node.setTag("onWalked", self.onWalked) self.node.setTag("onPicked", self.onPicked) #storing a pointer of the gamenode self.node.setPythonTag("gamenode", self) self.npc_walk_stack = [] self.npc_walk_happening = False self.globalLock = False self.setX(self.grid_currentx) self.setY(self.grid_currenty) if self.isNPC != True: print "attempting creation of NPC in ", self.grid_currentx, "-", self.grid_currenty if attributes.has_key('playable'): if self.isNPC != False: if ((self.grid_playable_pos.getX() != 0) and (self.grid_playable_pos.getY() != 0)): print 'GRID: moving player to ' + str( self.grid_playable_pos) self.setX(self.grid_playable_pos.getX()) self.setY(self.grid_playable_pos.getY()) #automatic reparenting (and showing) when (re)generating node self.node.wrtReparentTo(self.parent.node) def getName(self): return 'Character: ' + self.properties['id'] def xmlAttributes(self): return self.properties def xmlTypeName(self): return self.typeName ''' Sanitize properties data to be of correct type from string ''' def sanitizeProperties(self): #sanitizing data self.properties['inclination'] = float(self.properties['inclination']) self.properties['hitboxscale'] = float(self.properties['hitboxscale']) self.properties['speed'] = float(self.properties['speed']) self.properties['scale'] = float(self.properties['scale']) self.updateTilePosition() #interface needed by PropertiesTable # regenerates the node at every change def onPropertiesUpdated(self): self.sanitizeProperties() self.generateNode(self.showCollisions) #interface needed by PropertiesTable #TODO: implement as real interface? def getPropertyList(self): return self.properties #interface needed by PropertiesTable def setProperty(self, key, value): self.properties[key] = value def setSpeed(self, s): self.properties['speed'] = s def applyNearestFilter(self, model): for tex in model.findAllTextures(): tex.setMinfilter(Texture.FT_nearest) tex.setMagfilter(Texture.FT_nearest) return model ''' make the npc walk in direction for units ''' def npc_push_walk(self, direction, units): #locking script execution self.globalLock = True script.addOneCustomLock(self) #start the walking self.npc_walk_stack.append([direction, units]) self.npc_walk_helper() #apicall def npc_walk_helper(self): x = self.node.getX() y = self.node.getZ() #concurrent protection if self.npc_walk_happening == True: return #returning if no movement has to be performed if len(self.npc_walk_stack) < 0: return movement = self.npc_walk_stack.pop(0) direction = movement[0] units = movement[1] self.npc_targetx = x self.npc_targety = y self.npc_direction = direction if (direction == "down"): self.npc_targety = self.npc_targety - units elif (direction == "up"): self.npc_targety = self.npc_targety + units elif (direction == "left"): self.npc_targetx = self.npc_targetx - units elif (direction == "right"): self.npc_targetx = self.npc_targetx + units self.setAnim(direction) self.npc_walk_happening = True self.npc_movtask = taskMgr.add(self.npc_walk_task, "npc_moveCharacterTask" + self.properties['id'], uponDeath=self.npc_walk_callback) def npc_walk_task(self, task): dt = globalClock.getDt() if (self.npc_direction == 'left'): self.node.setX(self.node.getX() - 1 * dt * self.properties['speed']) currentx = self.node.getX() if currentx <= self.npc_targetx: return task.done if (self.npc_direction == 'right'): self.node.setX(self.node.getX() + 1 * dt * self.properties['speed']) currentx = self.node.getX() if currentx >= self.npc_targetx: return task.done if (self.npc_direction == 'up'): self.node.setZ(self.node.getZ() + 1 * dt * self.properties['speed']) currenty = self.node.getZ() if currenty >= self.npc_targety: return task.done if (self.npc_direction == 'down'): self.node.setZ(self.node.getZ() - 1 * dt * self.properties['speed']) currenty = self.node.getZ() if currenty <= self.npc_targety: return task.done return task.cont def npc_walk_callback(self, task): self.face(self.npc_direction) #unlocking concurrent movement protection self.npc_walk_happening = False if len(self.npc_walk_stack) > 0: self.npc_walk_helper() else: #character ended walking, unlock self.globalLock = False ''' write destroyfunction ''' def destroy(self): #not accepting events self.ignoreAll() #destroying everything down if self.node != None: self.node.remove_node() #removing all tasks if self.movtask != 0: taskMgr.remove(self.movtask) self.movtask = 0 def face(self, direction): if direction == "left": self.hideAllSubnodes() self.sleft.show() if direction == "right": self.hideAllSubnodes() self.sright.show() if direction == "top" or direction == "up": #let's keep retrocompatibility self.hideAllSubnodes() self.stop.show() if direction == "down": self.hideAllSubnodes() self.sdown.show() def setCollisions(self, value): if value == True: b = self.node.getBounds().getRadius() self.cTrav = CollisionTraverser() self.collisionTube = CollisionSphere( b / 2, 0, b / 2, 0.035 * self.properties['hitboxscale']) self.collisionNode = CollisionNode('characterTube') self.collisionNode.addSolid(self.collisionTube) self.collisionNodeNp = self.node.attachNewNode(self.collisionNode) self.collisionHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.collisionNodeNp, self.collisionHandler) if self.showCollisions == True or main.editormode: # Uncomment this line to see the collision rays self.collisionNodeNp.show() # Uncomment this line to show a visual representation of the # collisions occuring self.cTrav.showCollisions(render) else: b = self.node.getBounds().getRadius() self.collisionTube = CollisionSphere( b / 2, 0, b / 2, 0.035 * self.properties['hitboxscale']) #allowing playables to collide with npcs if self.isNPC == True: #TODO: fix because it's completely f****d up self.collisionNode = CollisionNode('characterTube') else: self.collisionNode = CollisionNode('characterNPCTube') self.collisionNode.addSolid(self.collisionTube) self.collisionNodeNp = self.node.attachNewNode(self.collisionNode) #set if camera has to effectively follow the character #while it moves def setFollowedByCamera(self, value): #camera follow if value: if self.currentlyfollowed != True: customCamera.follow(self) self.currentlyfollowed = True else: if self.currentlyfollowed != False: customCamera.dontFollow() self.currentlyfollowed = False def setPickCollisions(self, value): if value: print "setting pick collisions" b = self.node.getBounds().getRadius() self.pickCTrav = CollisionTraverser() self.pickCollisionTube = CollisionSphere( b / 2, 0, b / 2, 0.035 * self.properties['hitboxscale'] + 0.01) self.pickCollisionNode = CollisionNode('characterPickTube') self.pickCollisionNode.addSolid(self.pickCollisionTube) self.pickCollisionNodeNp = NodePath(self.pickCollisionNode) self.pickCollisionNodeNp.reparentTo(self.node) self.pickCollisionHandler = CollisionHandlerQueue() self.pickCTrav.addCollider(self.pickCollisionNodeNp, self.pickCollisionHandler) if self.showCollisions == True: # Uncomment this line to see the collision rays self.pickCollisionNodeNp.show() # Uncomment this line to show a visual representation of the # collisions occuring self.pickCTrav.showCollisions(render) else: #dereferincing all pick colliders (must be done in order not to collide onto NPCs) self.pickCTrav = None self.pickCollisionTube = None self.pickCollisionNode = None self.pickCollisionNodeNp = None self.pickCollisionHandler = None #used to set playability in real time #useful when we want to switch context/scripted scenes def setPlayable(self, value): if self.isNPC != False: if value == True: #down events self.accept("arrow_left", self.arrowLeftDown) self.accept("arrow_right", self.arrowRightDown) self.accept("arrow_up", self.arrowUpDown) self.accept("arrow_down", self.arrowDownDown) #up events self.accept("arrow_left-up", self.arrowLeftUp) self.accept("arrow_right-up", self.arrowRightUp) self.accept("arrow_up-up", self.arrowUpUp) self.accept("arrow_down-up", self.arrowDownUp) self.accept("space", self.spaceDown) self.node.setTag("playable", "true") self.setFollowedByCamera(True) self.accept("pauseGameplay", self.setPlayable, [False]) #can pause play else: self.ignoreAll() self.node.setTag("playable", "false") self.setFollowedByCamera(False) self.resetMovement() #reset every movement happening self.accept("resumeGameplay", self.setPlayable, [True]) #can resume play if not NPC #estimate loading time 4 seconds... lol... UPDATE: seems fixed in newer panda versions, inspect def showAllSubnodes(self): self.wtop.show() self.wdown.show() self.wleft.show() self.wright.show() self.stop.show() self.sdown.show() self.sleft.show() self.sright.show() def hideAllSubnodes(self): self.wtop.hide() self.wdown.hide() self.wleft.hide() self.wright.hide() self.stop.hide() self.sdown.hide() self.sleft.hide() self.sright.hide() def setMovement(self, value): if value == True: if self.movtask == 0: self.movtask = taskMgr.add(self.moveCharacter, "moveCharacterTask") if value == False: if self.movtask != 0: if len(self.currentlydown) == 0: taskMgr.remove(self.movtask) self.movtask = 0 ''' reset every movement actually happening ''' def resetMovement(self): if self.leftdown == True: self.face("left") if self.rightdown == True: self.face("right") if self.downdown == True: self.face("down") if self.topdown == True: self.face("top") self.leftdown = False self.rightdown = False self.downdown = False self.topdown = False self.currentlydown = [] self.setMovement(False) def setAnim(self, direction=''): self.hideAllSubnodes() if direction == '': if len(self.currentlydown) > 0: if self.currentlydown[-1] == 'left': self.wleft.show() if self.currentlydown[-1] == 'right': self.wright.show() if self.currentlydown[-1] == 'top': self.wtop.show() if self.currentlydown[-1] == 'down': self.wdown.show() else: if direction == 'left': self.wleft.show() if direction == 'right': self.wright.show() if direction == 'up': self.wtop.show() if direction == 'down': self.wdown.show() #pick request function def spaceDown(self): self.pickRequest = True #movement related functions def arrowLeftDown(self): #track key down self.leftdown = True self.setMovement(True) #show changes to screen self.currentlydown.append("left") self.setAnim() def arrowLeftUp(self): self.leftdown = False self.setMovement(False) #show changes to screen if len(self.currentlydown) == 1: self.hideAllSubnodes() self.sleft.show() if "left" in self.currentlydown: self.currentlydown.remove("left") if len(self.currentlydown) > 0: self.setAnim() def arrowRightDown(self): #track key down self.rightdown = True self.setMovement(True) #show changes to screen self.currentlydown.append("right") self.setAnim() def arrowRightUp(self): self.setMovement(False) self.rightdown = False #show changes to screen if len(self.currentlydown) == 1: self.hideAllSubnodes() self.sright.show() if "right" in self.currentlydown: self.currentlydown.remove("right") if len(self.currentlydown) > 0: self.setAnim() def arrowDownDown(self): #track key down self.downdown = True self.setMovement(True) #show changes to screen self.currentlydown.append("down") self.setAnim() def arrowDownUp(self): self.downdown = False self.setMovement(False) #show changes to screen if len(self.currentlydown) == 1: self.hideAllSubnodes() self.sdown.show() if "down" in self.currentlydown: self.currentlydown.remove("down") if len(self.currentlydown) > 0: self.setAnim() def arrowUpDown(self): #track key down self.topdown = True self.setMovement(True) #show changes to screen self.currentlydown.append("top") self.setAnim() def arrowUpUp(self): self.topdown = False self.setMovement(False) #show changes to screen if len(self.currentlydown) == 1: self.hideAllSubnodes() self.stop.show() if "top" in self.currentlydown: self.currentlydown.remove("top") if len(self.currentlydown) > 0: self.setAnim() def moveCharacter(self, task): dt = globalClock.getDt() if len(self.currentlydown) > 0: if self.currentlydown[-1] == 'left': self.node.setX(self.node.getX() - 1 * dt * self.properties['speed']) if self.currentlydown[-1] == 'right': self.node.setX(self.node.getX() + 1 * dt * self.properties['speed']) if self.currentlydown[-1] == 'top': self.node.setZ(self.node.getZ() + 1 * dt * self.properties['speed']) if self.currentlydown[-1] == 'down': self.node.setZ(self.node.getZ() - 1 * dt * self.properties['speed']) #check collisions if self.cTrav != None: self.cTrav.traverse(render) if self.pickCTrav != None: self.pickCTrav.traverse(render) #entries python list entries = list(self.collisionHandler.getEntries()) pickentries = list(self.pickCollisionHandler.getEntries()) for e in entries[:]: if e.getIntoNodePath().getName() == "characterPickTube": entries.remove(e) for e in pickentries[:]: if e.getIntoNodePath().getName() == "characterTube": pickentries.remove(e) if len(entries) == 0: self.lastpos = self.node.getPos() else: sp = entries[0].getSurfacePoint(self.node) #surface point objectNode = entries[0].getIntoNodePath().getParent( ) #into object node groundNode = entries[0].getIntoNodePath() #into object node if objectNode.hasTag("collideandwalk"): if objectNode.getTag("collideandwalk") != "yes": self.node.setPos(self.lastpos) else: self.node.setPos(self.lastpos) #if node is a real object (not a wall) if objectNode.hasTag("avoidable"): if objectNode.getTag( "avoidable" ) == "true": #see if object is intelligently avoidable if objectNode.hasTag("xscaled") and objectNode.hasTag( "yscaled"): if len( self.currentlydown ) > 0: #at least 1, avoids list index out of range exception if self.currentlydown[ -1] == 'left' or self.currentlydown[ -1] == 'right': #TODO: fix the shiet, not always working bottomObjPos = objectNode.getZ() - ( float(objectNode.getTag("yscaled")) / 2) topObjPos = objectNode.getZ() + ( float(objectNode.getTag("yscaled")) / 2) if self.node.getZ() < bottomObjPos: self.node.setZ(self.node.getZ() - 1 * dt * self.properties['speed']) if self.node.getZ() > topObjPos: self.node.setZ(self.node.getZ() + 1 * dt * self.properties['speed']) pass if self.currentlydown[ -1] == 'top' or self.currentlydown[ -1] == 'down': leftObjPos = objectNode.getX() - ( float(objectNode.getTag("xscaled")) / 2) rightObjPos = objectNode.getX() + ( float(objectNode.getTag("xscaled")) / 2) if self.node.getX() < leftObjPos: self.node.setX(self.node.getX() - 1 * dt * self.properties['speed']) if self.node.getX() > rightObjPos: self.node.setX(self.node.getX() + 1 * dt * self.properties['speed']) self.lastpos = self.node.getPos() for entry in entries: objectNode = entry.getIntoNodePath().getParent() onWalked = objectNode.getTag("onWalked") if len(onWalked) > 0: eval(onWalked) #oh lol, danger detected here evaluatedOnce = False if self.pickRequest == True: for entry in pickentries: objectNode = entry.getIntoNodePath().getParent() onPicked = objectNode.getTag("onPicked") if len(onPicked) > 0 and evaluatedOnce == False: eval(onPicked) #oh lol, danger detected again here evaluatedOnce = True else: if hasattr(objectNode.getPythonTag('gamenode'), 'name'): print "WARNING: picking on this object is not defined: ", objectNode.getPythonTag( 'gamenode').name print "X: ", objectNode.getX() print "Y: ", objectNode.getZ() self.pickRequest = False #resetting request #this is needed for empty pick if self.pickRequest == True: self.pickRequest = False #resetting request return Task.cont def getWorldPos(self): return self.node.getPos(render) def setX(self, x): self.node.setX(x) self.lastpos.setX(x) def setY(self, y): self.node.setZ(y) self.lastpos.setZ(y) #here for polymorph def getTileX(self): return self.parent.getX() #here for polymorph def getTileY(self): return self.parent.getY()