From 33c8db149d6d42fd1a4d2e3316640973cdc0284b Mon Sep 17 00:00:00 2001 From: Mark Mine Date: Tue, 8 May 2001 04:56:19 +0000 Subject: [PATCH] *** empty log message *** --- direct/src/leveleditor/LevelEditor.py | 294 ++++++++++++++++++++++++-- 1 file changed, 282 insertions(+), 12 deletions(-) diff --git a/direct/src/leveleditor/LevelEditor.py b/direct/src/leveleditor/LevelEditor.py index 56bef0dff7..107dd588e6 100644 --- a/direct/src/leveleditor/LevelEditor.py +++ b/direct/src/leveleditor/LevelEditor.py @@ -19,6 +19,8 @@ import sys import whrandom import __builtin__ +visualizeZones = base.config.GetBool("visualize-zones", 0) + # Colors used by all color menus DEFAULT_COLORS = [ Vec4(1,1,1,1), @@ -501,6 +503,10 @@ class LevelEditor(NodePath, PandaObject): base.cam.node().setNear(1.0) base.cam.node().setFar(3000) direct.camera.setPos(0,-10,10) + # Initialize drive mode + self.configureDriveModeCollisionData() + # Init visibility variables + self.__zoneId = None # Hide (disable) grid initially self.showGrid(0) # Create variable for vis groups panel @@ -626,9 +632,10 @@ class LevelEditor(NodePath, PandaObject): # Destory old toplevel node path and DNA # First the toplevel DNA self.DNAData.remove(self.DNAToplevel) - # Then the toplevel Node Path - self.NPToplevel.reparentTo(hidden) - self.NPToplevel.removeNode() + if self.NPToplevel.hasArcs(): + # Then the toplevel Node Path + self.NPToplevel.reparentTo(hidden) + self.NPToplevel.removeNode() def createToplevel(self, dnaNode, nodePath = None): # When you create a new level, data is added to this node @@ -659,6 +666,16 @@ class LevelEditor(NodePath, PandaObject): def useDirectFly(self): """ Disable player camera controls/enable direct camera control """ + # Turn off collision traversal + self.traversalOff() + # Turn on collisions + self.collisionsOff() + # Turn on visiblity + self.visibilityOff() + # Reset cam + base.camera.iPos(base.cam) + base.cam.iPosHpr() + # Renable mouse self.enableMouse() direct.enable() @@ -677,10 +694,17 @@ class LevelEditor(NodePath, PandaObject): """ Disable direct camera manipulation and enable player drive mode """ direct.minimumConfiguration() direct.manipulationControl.disableManipulation() + # Update vis data + self.initVisibilityData() + # Switch to drive mode base.useDrive() + # Move cam up and back + base.cam.setPos(0,-5,4) + # And move down and forward to compensate + base.camera.setPos(base.camera, 0, 5, -4) # Make sure we're where we want to be pos = direct.camera.getPos() - pos.setZ(4.0) + pos.setZ(0.0) hpr = direct.camera.getHpr() hpr.set(hpr[0], 0.0, 0.0) # Fine tune the drive mode @@ -688,7 +712,232 @@ class LevelEditor(NodePath, PandaObject): base.mouseInterface.node().setHpr(hpr) base.mouseInterface.node().setForwardSpeed(20.0) base.mouseInterface.node().setReverseSpeed(20.0) + # Turn on collisions + if self.panel.fColl.get(): + self.collisionsOn() + # Turn on visiblity + if self.panel.fVis.get(): + self.visibilityOn() + # Turn on collision traversal + if self.panel.fColl.get() or self.panel.fVis.get(): + self.traversalOn() + def configureDriveModeCollisionData(self): + """initializeCollisions(self) + Set up the local avatar for collisions + """ + # Set up the collision sphere + # This is a sphere on the ground to detect barrier collisions + self.cSphere = CollisionSphere(0.0, 0.0, 0.0, 1.5) + self.cSphereNode = CollisionNode('cSphereNode') + self.cSphereNode.addSolid(self.cSphere) + self.cSphereNodePath = camera.attachNewNode(self.cSphereNode) + self.cSphereNodePath.hide() + self.cSphereBitMask = BitMask32.bit(0) + self.cSphereNode.setFromCollideMask(self.cSphereBitMask) + self.cSphereNode.setIntoCollideMask(BitMask32.allOff()) + + # Set up the collison ray + # This is a ray cast from your head down to detect floor polygons + self.cRay = CollisionRay(0.0, 0.0, 6.0, 0.0, 0.0, -1.0) + self.cRayNode = CollisionNode('cRayNode') + self.cRayNode.addSolid(self.cRay) + self.cRayNodePath = camera.attachNewNode(self.cRayNode) + self.cRayNodePath.hide() + self.cRayBitMask = BitMask32.bit(1) + self.cRayNode.setFromCollideMask(self.cRayBitMask) + self.cRayNode.setIntoCollideMask(BitMask32.allOff()) + + # set up wall collision mechanism + self.pusher = CollisionHandlerPusher() + self.pusher.setInPattern("enter%in") + self.pusher.setOutPattern("exit%in") + + # set up floor collision mechanism + self.lifter = CollisionHandlerFloor() + self.lifter.setInPattern("on-floor") + self.lifter.setOutPattern("off-floor") + self.floorOffset = 0.1 + self.lifter.setOffset(self.floorOffset) + + # Limit our rate-of-fall with the lifter. + # If this is too low, we actually "fall" off steep stairs + # and float above them as we go down. I increased this + # from 8.0 to 16.0 to prevent this + self.lifter.setMaxVelocity(16.0) + + # set up the collision traverser + self.cTrav = CollisionTraverser() + + # activate the collider with the traverser and pusher + self.pusher.addCollider(self.cSphereNode, base.drive.node()) + self.lifter.addCollider(self.cRayNode, base.drive.node()) + # A map of zone ID's to a list of nodes that are visible from + # that zone. + self.nodeDict = {} + # A map of zone ID's to the particular node that corresponds + # to that zone. + self.zoneDict = {} + # A list of all visible nodes + self.nodeList = [] + # Flag for bootstrapping visibility + self.fVisInit = 0 + + def traversalOn(self): + base.cTrav = self.cTrav + + def traversalOff(self): + base.cTrav = 0 + + def collisionsOff(self): + self.cTrav.removeCollider(self.cSphereNode) + + def collisionsOn(self): + self.collisionsOff() + self.cTrav.addCollider(self.cSphereNode, self.pusher) + + def toggleCollisions(self): + if self.panel.fColl.get(): + print 'ON' + self.collisionsOn() + self.traversalOn() + else: + self.collisionsOff() + if (not (self.panel.fColl.get() or self.panel.fVis.get())): + self.traversalOff() + + def initVisibilityData(self): + # First make sure everything is shown + self.showAllVisibles() + # A map of zone ID's to a list of nodes that are visible from + # that zone. + self.nodeDict = {} + # A map of zone ID's to the particular node that corresponds + # to that zone. + self.zoneDict = {} + # A list of all visible nodes + self.nodeList = [] + # NOTE: this should change to find the groupnodes in + # the dna storage instead of searching through the tree + for i in range(DNASTORE.getNumDNAVisGroups()): + groupFullName = DNASTORE.getDNAVisGroupName(i) + groupName = self.extractGroupName(groupFullName) + zoneId = int(groupName) + self.nodeDict[zoneId] = [] + self.zoneDict[zoneId] = self.NPToplevel.find("**/" + groupName) + + # TODO: we only need to look from the top of the hood + # down one level to find the vis groups as an optimization + groupNode = self.NPToplevel.find("**/" + groupFullName) + if groupNode.isEmpty(): + print "Could not find visgroup" + self.nodeList.append(groupNode) + for j in range(DNASTORE.getNumVisiblesInDNAVisGroup(i)): + visName = DNASTORE.getVisibleName(i, j) + visNode = self.NPToplevel.find("**/" + visName) + self.nodeDict[zoneId].append(visNode) + # Rename the floor polys to have the same name as the + # visgroup they are in... This makes visibility possible. + self.renameFloorPolys(self.nodeList) + # Init vis flag + self.fVisInit = 1 + + def extractGroupName(self, groupFullName): + # The Idea here is that group names may have extra flags associated + # with them that tell more information about what is special about + # the particular vis zone. A normal vis zone might just be "13001", + # but a special one might be "14356:safe_zone" or + # "345:safe_zone:exit_zone"... These are hypotheticals. The main + # idea is that there are colon separated flags after the initial + # zone name. + return(string.split(groupFullName, ":", 1)[0]) + + def renameFloorPolys(self, nodeList): + for i in nodeList: + # Get all the collision nodes in the vis group + collNodePaths = i.findAllMatches("**/+CollisionNode") + numCollNodePaths = collNodePaths.getNumPaths() + visGroupName = i.node().getName() + for j in range(numCollNodePaths): + collNodePath = collNodePaths.getPath(j) + bitMask = collNodePath.node().getIntoCollideMask() + if bitMask.getBit(1): + # Bit 1 is the floor collision bit. This renames + # all floor collision polys to the same name as their + # visgroup. + collNodePath.node().setName(visGroupName) + + def hideAllVisibles(self): + for i in self.nodeList: + i.hide() + + def showAllVisibles(self): + for i in self.nodeList: + i.show() + + def visibilityOn(self): + self.visibilityOff() + # Accept event + self.accept("on-floor", self.enterZone) + # Add collider + self.cTrav.addCollider(self.cRayNode, self.lifter) + # Reset lifter + self.lifter.clear() + # Reset flag + self.fVisInit = 1 + + def visibilityOff(self): + self.ignore("on-floor") + self.cTrav.removeCollider(self.cRayNode) + self.showAllVisibles() + + def toggleVisibility(self): + if self.panel.fVis.get(): + self.visibilityOn() + self.traversalOn() + else: + self.visibilityOff() + if (not (self.panel.fColl.get() or self.panel.fVis.get())): + self.traversalOff() + + def enterZone(self, newZone): + """ + Puts the toon in the indicated zone. newZone may either be a + CollisionEntry object as determined by a floor polygon, or an + integer zone id. It may also be None, to indicate no zone. + """ + # First entry into a zone, hide everything + if self.fVisInit: + self.hideAllVisibles() + self.fVisInit = 0 + # Get zone id + if isinstance(newZone, CollisionEntry): + # Get the name of the collide node + newZoneId = int(newZone.getIntoNode().getName()) + else: + newZoneId = newZone + # Ensure we have vis data + assert(self.nodeDict) + # Hide the old zone (if there is one) + if self.__zoneId != None: + for i in self.nodeDict[self.__zoneId]: + i.hide() + # Show the new zone + if newZoneId != None: + for i in self.nodeDict[newZoneId]: + i.show() + # Make sure we changed zones + if newZoneId != self.__zoneId: + if visualizeZones: + # Set a color override on our zone to make it obvious what + # zone we're in. + if self.__zoneId != None: + self.zoneDict[self.__zoneId].clearColor() + if newZoneId != None: + self.zoneDict[newZoneId].setColor(0, 0, 1, 1, 100) + # The new zone is now old + self.__zoneId = newZoneId + def enableMouse(self): """ Enable Pie Menu interaction (and disable player camera control) """ # Turn off player camera control @@ -4463,13 +4712,6 @@ class LevelEditorPanel(Pmw.MegaToplevel): buttonFrame4 = Frame(hull) self.driveMode = IntVar() self.driveMode.set(1) - self.driveModeButton = Radiobutton( - buttonFrame4, - text = 'Drive Mode', - value = 0, - variable = self.driveMode, - command = self.levelEditor.useDriveMode) - self.driveModeButton.pack(side = LEFT, fill = X, expand = 1) self.directModeButton = Radiobutton( buttonFrame4, text = 'DIRECT Fly', @@ -4477,7 +4719,35 @@ class LevelEditorPanel(Pmw.MegaToplevel): variable = self.driveMode, command = self.levelEditor.useDirectFly) self.directModeButton.pack(side = LEFT, fill = X, expand = 1) - buttonFrame4.pack(fill = X, padx = 60) + self.driveModeButton = Radiobutton( + buttonFrame4, + text = 'Drive Mode', + value = 0, + variable = self.driveMode, + command = self.levelEditor.useDriveMode) + self.driveModeButton.pack(side = LEFT, fill = X, expand = 1) + + self.fColl = IntVar() + self.fColl.set(1) + direct.collButton = Checkbutton( + buttonFrame4, + text = 'Collide', + width = 6, + variable = self.fColl, + command = self.levelEditor.toggleCollisions) + direct.collButton.pack(side = LEFT, expand = 1, fill = X) + + self.fVis = IntVar() + self.fVis.set(1) + direct.visButton = Checkbutton( + buttonFrame4, + text = 'Visibility', + width = 6, + variable = self.fVis, + command = self.levelEditor.toggleVisibility) + direct.visButton.pack(side = LEFT, expand = 1, fill = X) + + buttonFrame4.pack(fill = X, padx = 15) # Make sure input variables processed self.initialiseoptions(LevelEditorPanel)