def line_model(self, r, g, b): line = LineNodePath(self.render2d, 'box', 2) line.reparentTo(self.render) line.setColor(r, g, b, 1.) line.setTransparency(TransparencyAttrib.MAlpha) line.setAlphaScale(0.5) return line
def draw_lines(lines: LineNodePath, *paths: dict, origin=None, relative=True): if origin is None: origin = lines.getCurrentPosition() lines.reset() for path in paths: if 'color' in path: lines.setColor(*path['color']) points = path['points'] lines.moveTo(*origin) for point in points: if relative: point += origin lines.drawTo(*point) lines.create()
class NodeConnector: def __init__(self, socketA, socketB): self.connectorID = uuid4() self.socketA = socketA self.socketB = socketB self.line = LineNodePath(ShowBaseGlobal.aspect2d, thickness=2, colorVec=(0.8, 0.8, 0.8, 1)) self.draw() self.show = self.line.show self.hide = self.line.hide def update(self): self.line.reset() self.draw() def draw(self): self.line.moveTo(self.socketA.plug.getPos(ShowBaseGlobal.aspect2d)) self.line.drawTo(self.socketB.plug.getPos(ShowBaseGlobal.aspect2d)) self.line.create() def has(self, socket): """Returns True if one of the sockets this connector connects is the given socket""" return socket == self.socketA or socket == self.socketB def connects(self, a, b): """Returns True if this connector connects socket a and b""" return (a == self.socketA or a == self.socketB) and (b == self.socketA or b == self.socketB) def disconnect(self): self.line.reset() self.socketA.setConnected(False) self.socketB.setConnected(False) def setChecked(self): self.line.setColor(0, 1, 0, 1) self.update() def setError(self, hasError): self.line.setColor(1, 0, 0, 1) self.update() def __str__(self): return f"Connection {self.socketA.name} to {self.socketB.name}"
class Fisherman(Toon.Toon): numFishTypes = 3 def __init__(self, id, toNpcId=20001, fAutonomous=1): # Default NPC ID is Flippy Toon.Toon.__init__(self) self.id = id self.fAutonomous = fAutonomous npcInfo = NPCToons.NPCToonDict[toNpcId] dnaList = npcInfo[2] gender = npcInfo[3] dna = ToonDNA.ToonDNA() dna.newToonFromProperties(*dnaList) self.setDNA(dna) self.reparentTo(render) self.angleNP = self.find('**/actorGeom') # Create pole self.pole = Actor.Actor() self.pole.loadModel('phase_4/models/props/fishing-pole-mod') self.pole.loadAnims({'cast': 'phase_4/models/props/fishing-pole-chan'}) # Get the top of the pole. self.ptop = self.pole.find('**/joint_attachBill') self.pole.pose('cast', 0) # Prepare Pole self.poleNode = [] self.holdPole() self.createCastTrack() self.castIval = None # Prepare actor self.setupNeutralBlend() self.targetInterval = None # Start automatic casting or create cast button if self.fAutonomous: self.castButton = None self.targetButton = None self.startCasting() else: # Starts casting mode when mouse enters button region self.castButton = DirectButton(text='CAST', relief=None, scale=0.1, pos=(0, 0, -0.2)) self.castButton.bind(DGG.ENTER, self.showCancelFrame) # A big screen encompassing frame to catch the button releases self.cancelFrame = DirectFrame(parent=self.castButton, frameSize=(-1, 1, -1, 1), relief=None, state='normal') # Make sure this is on top of all the other widgets self.cancelFrame.setBin('gui-popup', 0) self.cancelFrame.bind(DGG.B1PRESS, self.startAdjustingCastTask) self.cancelFrame.bind(DGG.B1RELEASE, self.finishCast) self.cancelFrame.hide() # Create bob self.bob = loader.loadModel('phase_4/models/props/fishing_bob') self.bobSpot = Point3(0) # Parameters to control bob motion self.vZeroMax = 30.0 self.angleMax = 30.0 # Ripple effect self.ripples = Ripples.Ripples(self.angleNP) self.ripples.hide() # Target self.buttonFrame = DirectFrame() self.target = base.distributedFishingTarget.fishingTargetNode self.fishPivot = self.attachNewNode('fishPivot') self.fish = loader.loadModel('models/misc/smiley') self.fish.reparentTo(self.fishPivot) self.fish.setScale(0.3, 1, 0.3) self.wiggleIval = None self.circleIval = None self.initFish() self.targetButton = DirectButton(parent=self.buttonFrame, text='MOVE', relief=DGG.RAISED, scale=0.1, pos=(0, 0, -0.9), command=self.moveTarget) self.targetTypeButton = DirectCheckButton(parent=self.buttonFrame, text='MOVING', relief=DGG.RAISED, scale=0.085, pos=(0.4, 0, -0.895), command=self.setfMove) self.fMovingTarget = 0 self.targetModeButton = DirectCheckButton( parent=self.buttonFrame, text='dTASK', relief=DGG.RAISED, scale=0.085, pos=(0.8, 0, -0.895), command=self.setfTargetMode) self.fTargetMode = 0 # Vector line self.line = LineNodePath(render2d) self.line.setColor(VBase4(1, 0, 0, 1)) self.line.moveTo(0, 0, 0) self.line.drawTo(1, 0, 0) self.line.create() self.moveTarget() def showCancelFrame(self, event): # Also display cancel frame to catch clicks outside of the popup self.cancelFrame.show() def startAdjustingCastTask(self, event): # Start task to adjust power of cast self.getMouse() self.initMouseX = self.mouseX self.initMouseY = self.mouseY self.initMouseX = 0 self.initMouseY = -0.2 self.line.lineSegs.setVertex(0, self.initMouseX, 0, self.initMouseY) self.angleNP.setH(0) self.__hideBob() taskMgr.remove('distCheck') # Position and scale cancel frame to fill entire window self.cancelFrame.setPos(render2d, 0, 0, 0) self.cancelFrame.setScale(render2d, 1, 1, 1) self.castTrack.finish() self.castTrack.setT(0) self.castTrack.start(startT=0, endT=0.4) self.castIval = Sequence( Wait(0.4), Func(taskMgr.add, self.adjustingCastTask, 'adjustCastTask')) self.castIval.start() def adjustingCastTask(self, state): self.getMouse() deltaX = self.mouseX - self.initMouseX deltaY = self.mouseY - self.initMouseY self.line.lineSegs.setVertex(1, self.mouseX, 0, self.mouseY) dist = math.sqrt(deltaX * deltaX + deltaY * deltaY) delta = (dist / 0.5) if deltaY > 0: delta *= -1 p = max(min(delta, 1.0), 0.0) self.power = p self.castTrack.setT(0.4 + p * 0.5) self.bobSpot = Point3(0, 6.5 + p * 25.0, -1.9) # Calc angle if deltaY == 0: angle = 0 else: angle = rad2Deg(math.atan(deltaX / deltaY)) self.angleNP.setH(-angle) return Task.cont def stopAdjustingCastTask(self): taskMgr.remove('adjustingTask') def setupNeutralBlend(self): self.stop() self.loop('neutral') self.enableBlend() self.pose('cast', 0) self.setControlEffect('neutral', 0.2) self.setControlEffect('cast', 0.8) def startCasting(self): if self.fAutonomous: self.castIval = Sequence( ActorInterval(self, 'cast'), Func(self.catchFish), Parallel( ActorInterval(self, 'neutral', loop=1, duration=100), Sequence( Wait(random.random() * 20.0), Func(self.startCasting), ))) else: self.castIval = Sequence( ActorInterval(self, 'cast'), Func(self.catchFish), ActorInterval(self, 'neutral', loop=1, duration=100)) self.castIval.play() def stopCasting(self): if self.castIval: self.castIval.pause() if self.targetInterval: self.stopTargetInterval() taskMgr.remove('distCheck') def catchFish(self): fishNum = int(round(random.random() * self.numFishTypes)) messenger.send('caughtFish', sentArgs=[self.id, fishNum]) def setupNeutralBlend(self): self.stop() self.loop('neutral') self.enableBlend() self.pose('cast', 0) self.setControlEffect('neutral', 0.2) self.setControlEffect('cast', 0.8) def getPole(self): toonTrack = Sequence( # Blend in neutral anim Func(self.setupNeutralBlend), # Pull out pole Func(self.holdPole), Parallel( ActorInterval(self, 'cast', playRate=0.5, duration=27. / 12.), ActorInterval(self.pole, 'cast', playRate=0.5, duration=27. / 12.), LerpScaleInterval(self.pole, duration=2.0, scale=1.0, startScale=0.01)), ) toonTrack.play() def putAwayPole(self): Sequence( Parallel( ActorInterval(self, 'cast', duration=1.0, startTime=1.0, endTime=0.0), ActorInterval(self.pole, 'cast', duration=1.0, startTime=1.0, endTime=0.0), LerpScaleInterval(self.pole, duration=0.5, scale=0.01, startScale=1.0)), Func(self.dropPole)).start() def holdPole(self): if self.poleNode != []: self.dropPole() # One node, instanced to each of the toon's three right hands, # will hold the pole. np = NodePath('pole-holder') hands = self.getRightHands() for h in hands: self.poleNode.append(np.instanceTo(h)) self.pole.reparentTo(self.poleNode[0]) def dropPole(self): self.__hideBob() #self.__hideLine() if self.pole != None: self.pole.clearMat() self.pole.detachNode() for pn in self.poleNode: pn.removeNode() self.poleNode = [] def createCastTrack(self): self.castTrack = Sequence( Parallel( ActorInterval(self, 'cast', duration=2.0, startTime=1.0), ActorInterval(self.pole, 'cast', duration=2.0, startTime=1.0), )) def cast(self): self.castTrack.start() def finishCast(self, event=None): #self.line.lineSegs.setVertex(1,self.initMouseX,0,self.initMouseY) self.cancelFrame.hide() if not self.castTrack: self.createCastTrack() self.castIval.finish() taskMgr.remove('adjustCastTask') taskMgr.remove('moveBobTask') self.castTrack.pause() #self.castTrack.start(self.castTrack.getT()) p = self.power startT = 0.9 + (1 - p) * 0.3 self.castTrack.start(startT) self.bobStartPos = Point3(0.017568, 7.90371, 6.489) Sequence(Wait(1.2 - startT), Func(self.startMoveBobTask)).start() def startMoveBobTask(self): self.__showBob() self.bobStartT = globalClock.getFrameTime() taskMgr.add(self.moveBobTask, 'moveBobTask') def moveBobTask(self, state): # Accel due to gravity g = 32.2 # Elapsed time of cast t = globalClock.getFrameTime() - self.bobStartT # Scale bob velocity and angle based on power of cast vZero = self.power * self.vZeroMax angle = deg2Rad(self.power * self.angleMax) # How far has bob moved from start point? deltaY = vZero * math.cos(angle) * t deltaZ = vZero * math.sin(angle) * t - (g * t * t) / 2.0 deltaPos = Point3(0, deltaY, deltaZ) # Current bob position pos = self.bobStartPos + deltaPos # Have we reached end condition? if pos[2] < -1.9: pos.setZ(-1.9) self.ripples.reparentTo(self.angleNP) self.ripples.setPos(pos) self.ripples.play() returnVal = Task.done if self.fTargetMode: taskMgr.add(self.distCheck, 'distCheck') else: self.distCheck() else: returnVal = Task.cont self.bob.setPos(pos) return returnVal def distCheck(self, state=None): # Check to see if we hit the target bPos = self.bob.getPos() # Check target returnVal = self.__distCheck(bPos, self.target) if returnVal == Task.done: return returnVal # Check fish return self.__distCheck(bPos, self.fish) def __distCheck(self, bPos, target): def flashTarget(): self.stopTargetInterval() self.target.getChild(0).setColor(0, 0, 1) def flashFish(): taskMgr.remove('turnTask') self.fish.lerpScale(Point3(0.01), 0.5, task='flashFish') tPos = target.getPos(self.angleNP) tDist = Vec3(tPos - bPos) tDist.setZ(0) dist = tDist.length() if target == self.target: flashFunc = flashTarget moveFunc = self.moveTarget else: flashFunc = flashFish moveFunc = self.turnFish if dist < 2.5: fBite = (random.random() < 0.4) or (not self.fTargetMode) delay = self.fTargetMode * 0.25 if fBite: print('BITE') Sequence( Wait(random.random() * delay), Func(flashFunc), Func(self.catchFish), Wait(2.0), Func(moveFunc), ).play() else: print('MISS') def moveIt(): moveFunc(targetPos=target.getPos()) Sequence(Wait(random.random() * delay), Func(moveIt)).play() return Task.done return Task.cont def stopTargetInterval(self): if self.targetInterval: self.targetInterval.pause() self.targetInterval = None def __showBob(self): # Put the bob in the water and make it gently float. self.__hideBob() self.bob.reparentTo(self.angleNP) self.bob.setPos(self.ptop, 0, 0, 0) def __hideBob(self): if self.bob != None: self.bob.detachNode() def getMouse(self): if (base.mouseWatcherNode.hasMouse()): self.mouseX = base.mouseWatcherNode.getMouseX() self.mouseY = base.mouseWatcherNode.getMouseY() else: self.mouseX = 0 self.mouseY = 0 def setfMove(self, fMoving): self.fMovingTarget = fMoving def setfTargetMode(self, fTargetMode): self.fTargetMode = fTargetMode def moveTarget(self, targetPos=None): base.distributedFishingTarget.sendUpdate('bobEnter', []) # self.stopTargetInterval() # self.target.clearColor() # if not targetPos: # x = -87.0 + random.random() * 15.0 # y = 25.0 + random.random() * 20.0 # z = -4.8 # self.targetPos = Point3(x,y,z) # else: # self.targetPos.assign(targetPos) # if self.fMovingTarget: # self.makeTargetInterval() # else: # #self.target.setPos(self.targetPos) def initFish(self): x = -10.0 + random.random() * 20.0 y = 00.0 + random.random() * 30.0 z = -1.6 self.fishPivot.setPos(x, y, z) self.turningRadius = 5.0 + random.random() * 5.0 self.fish.setPos(self.turningRadius, 0, -0.4) if self.wiggleIval: self.wiggleIval.pause() self.wiggleIval = Sequence( self.fish.hprInterval(0.5, hpr=Point3(10, 0, 0), startHpr=Point3(-10, 0, 0), blendType='easeInOut'), self.fish.hprInterval(0.5, hpr=Point3(-10, 0, 0), startHpr=Point3(10, 0, 0), blendType='easeInOut')) self.wiggleIval.loop() if self.circleIval: self.circleIval.pause() self.circleIval = self.fishPivot.hprInterval(20, Point3(360, 0, 0), startHpr=Point3(0)) self.circleIval.loop() taskMgr.remove('turnTask') taskMgr.doMethodLater(3.0 + random.random() * 3.0, self.turnFish, 'turnTask') taskMgr.remove('fishBoundsCheck') taskMgr.add(self.fishBoundsCheck, 'fishBoundsCheck') def fishBoundsCheck(self, state): pos = self.fish.getPos(self) if pos[0] < -20: self.fishPivot.setX(self.fishPivot.getX() + 40.0) elif pos[0] > 20: self.fishPivot.setX(self.fishPivot.getX() - 40.0) if pos[1] < -10: self.fishPivot.setY(self.fishPivot.getY() + 50.0) elif pos[1] > 40: self.fishPivot.setY(self.fishPivot.getY() - 50.0) return Task.cont def turnFish(self, state=None, targetPos=None): self.fish.setScale(0.3, 1, 0.3) if self.circleIval: self.circleIval.pause() newTurningRadius = 5.0 + random.random() * 5.0 fRightTurn = random.random() < 0.5 if fRightTurn: newTurningRadius *= -1.0 offset = self.turningRadius - newTurningRadius self.fishPivot.setX(self.fishPivot, offset) self.turningRadius = newTurningRadius self.fish.setX(self.turningRadius) currH = self.fishPivot.getH() % 360.0 if fRightTurn: self.circleIval = self.fishPivot.hprInterval( 20, Point3(currH - 360, 0, 0), startHpr=Point3(currH, 0, 0)) else: self.circleIval = self.fishPivot.hprInterval( 20, Point3(currH + 360, 0, 0), startHpr=Point3(currH, 0, 0)) self.circleIval.loop() taskMgr.doMethodLater(3.0 + random.random() * 3.0, self.turnFish, 'turnTask') return Task.done def makeTargetInterval(self): x = -10.0 + random.random() * 20.0 y = 0.0 + random.random() * 30.0 z = -1.6 self.targetEndPos = Point3(x, y, z) dist = Vec3(self.targetEndPos - self.targetPos).length() dur = dist / 1.5 dur = dur * (0.75 + random.random() * 0.5) self.targetInterval = Sequence( self.target.posInterval(dur, self.targetEndPos, startPos=self.targetPos, blendType='easeInOut'), self.target.posInterval(dur, self.targetPos, startPos=self.targetEndPos, blendType='easeInOut'), name='moveInterval') offsetDur = dur / random.randint(1, 4) amplitude = 0.1 + random.random() * 1.0 self.targetInterval.loop() def destroy(self): if not self.fAutonomous: self.castButton.destroy() self.buttonFrame.destroy() self.line.removeNode() taskMgr.remove('turnTask') taskMgr.remove('fishBoundsCheck') self.stopCasting() self.removeNode()
class DirectGrid(NodePath, DirectObject): def __init__(self, parent, gridSize=100.0, gridSpacing=5.0, planeColor=(0.5, 0.5, 0.5, 0.5)): # Initialize superclass NodePath.__init__(self) self.assign(hidden.attachNewNode('DirectGrid')) # Don't wireframe or light #useDirectRenderStyle(self) self.setLightOff(0) self.setRenderModeFilled() self.parent = parent # Load up grid parts to initialize grid object # Polygon used to mark grid plane self.gridBack = loader.loadModel('models/misc/gridBack.egg.pz') self.gridBack.reparentTo(self) self.gridBack.setColor(*planeColor) # Grid Lines self.lines = self.attachNewNode('gridLines') self.minorLines = LineNodePath(self.lines) self.minorLines.lineNode.setName('minorLines') self.minorLines.setColor(VBase4(0.3, 0.55, 1, 1)) self.minorLines.setThickness(1) self.majorLines = LineNodePath(self.lines) self.majorLines.lineNode.setName('majorLines') self.majorLines.setColor(VBase4(0.3, 0.55, 1, 1)) self.majorLines.setThickness(5) self.centerLines = LineNodePath(self.lines) self.centerLines.lineNode.setName('centerLines') self.centerLines.setColor(VBase4(1, 0, 0, 0)) self.centerLines.setThickness(3) # Small marker to hilight snap-to-grid point self.snapMarker = loader.loadModel('models/misc/sphere.egg.pz') self.snapMarker.node().setName('gridSnapMarker') self.snapMarker.reparentTo(self) self.snapMarker.setColor(1, 0, 0, 1) self.snapMarker.setScale(0.3) self.snapPos = Point3(0) # Initialize Grid characteristics self.fXyzSnap = 1 self.fHprSnap = 1 self.gridSize = gridSize self.gridSpacing = gridSpacing self.snapAngle = 15.0 self.enable() def enable(self): self.reparentTo(self.parent) self.updateGrid() self.fEnabled = 1 def disable(self): self.reparentTo(hidden) self.fEnabled = 0 def toggleGrid(self): if self.fEnabled: self.disable() else: self.enable() def isEnabled(self): return self.fEnabled def updateGrid(self): # Update grid lines based upon current grid spacing and grid size # First reset existing grid lines self.minorLines.reset() self.majorLines.reset() self.centerLines.reset() # Now redraw lines numLines = int(math.ceil(self.gridSize / self.gridSpacing)) scaledSize = numLines * self.gridSpacing center = self.centerLines minor = self.minorLines major = self.majorLines for i in range(-numLines, numLines + 1): if i == 0: center.moveTo(i * self.gridSpacing, -scaledSize, 0) center.drawTo(i * self.gridSpacing, scaledSize, 0) center.moveTo(-scaledSize, i * self.gridSpacing, 0) center.drawTo(scaledSize, i * self.gridSpacing, 0) else: if (i % 5) == 0: major.moveTo(i * self.gridSpacing, -scaledSize, 0) major.drawTo(i * self.gridSpacing, scaledSize, 0) major.moveTo(-scaledSize, i * self.gridSpacing, 0) major.drawTo(scaledSize, i * self.gridSpacing, 0) else: minor.moveTo(i * self.gridSpacing, -scaledSize, 0) minor.drawTo(i * self.gridSpacing, scaledSize, 0) minor.moveTo(-scaledSize, i * self.gridSpacing, 0) minor.drawTo(scaledSize, i * self.gridSpacing, 0) center.create() minor.create() major.create() if (self.gridBack): self.gridBack.setScale(scaledSize) def setXyzSnap(self, fSnap): self.fXyzSnap = fSnap def getXyzSnap(self): return self.fXyzSnap def setHprSnap(self, fSnap): self.fHprSnap = fSnap def getHprSnap(self): return self.fHprSnap def computeSnapPoint(self, point): # Start of with current point self.snapPos.assign(point) # Snap if necessary if self.fXyzSnap: self.snapPos.set(ROUND_TO(self.snapPos[0], self.gridSpacing), ROUND_TO(self.snapPos[1], self.gridSpacing), ROUND_TO(self.snapPos[2], self.gridSpacing)) # Move snap marker to this point self.snapMarker.setPos(self.snapPos) # Return the hit point return self.snapPos def computeSnapAngle(self, angle): return ROUND_TO(angle, self.snapAngle) def setSnapAngle(self, angle): self.snapAngle = angle def getSnapAngle(self): return self.snapAngle def setGridSpacing(self, spacing): self.gridSpacing = spacing self.updateGrid() def getGridSpacing(self): return self.gridSpacing def setGridSize(self, size): # Set size of grid back and redraw lines self.gridSize = size self.updateGrid() def getGridSize(self): return self.gridSize
class DirectGrid(NodePath, DirectObject): def __init__(self,parent,gridSize=100.0,gridSpacing=5.0,planeColor=(0.5,0.5,0.5,0.5)): # Initialize superclass NodePath.__init__(self) self.assign(hidden.attachNewNode('DirectGrid')) # Don't wireframe or light #useDirectRenderStyle(self) self.setLightOff(0) self.setRenderModeFilled() self.parent = parent # Load up grid parts to initialize grid object # Polygon used to mark grid plane self.gridBack = loader.loadModel('models/misc/gridBack.egg.pz') self.gridBack.reparentTo(self) self.gridBack.setColor(*planeColor) # Grid Lines self.lines = self.attachNewNode('gridLines') self.minorLines = LineNodePath(self.lines) self.minorLines.lineNode.setName('minorLines') self.minorLines.setColor(VBase4(0.3, 0.55, 1, 1)) self.minorLines.setThickness(1) self.majorLines = LineNodePath(self.lines) self.majorLines.lineNode.setName('majorLines') self.majorLines.setColor(VBase4(0.3, 0.55, 1, 1)) self.majorLines.setThickness(5) self.centerLines = LineNodePath(self.lines) self.centerLines.lineNode.setName('centerLines') self.centerLines.setColor(VBase4(1, 0, 0, 0)) self.centerLines.setThickness(3) # Small marker to hilight snap-to-grid point self.snapMarker = loader.loadModel('models/misc/sphere.egg.pz') self.snapMarker.node().setName('gridSnapMarker') self.snapMarker.reparentTo(self) self.snapMarker.setColor(1, 0, 0, 1) self.snapMarker.setScale(0.3) self.snapPos = Point3(0) # Initialize Grid characteristics self.fXyzSnap = 1 self.fHprSnap = 1 self.gridSize = gridSize self.gridSpacing = gridSpacing self.snapAngle = 15.0 self.enable() def enable(self): self.reparentTo(self.parent) self.updateGrid() self.fEnabled = 1 def disable(self): self.reparentTo(hidden) self.fEnabled = 0 def toggleGrid(self): if self.fEnabled: self.disable() else: self.enable() def isEnabled(self): return self.fEnabled def updateGrid(self): # Update grid lines based upon current grid spacing and grid size # First reset existing grid lines self.minorLines.reset() self.majorLines.reset() self.centerLines.reset() # Now redraw lines numLines = int(math.ceil(self.gridSize/self.gridSpacing)) scaledSize = numLines * self.gridSpacing center = self.centerLines minor = self.minorLines major = self.majorLines for i in range(-numLines, numLines + 1): if i == 0: center.moveTo(i * self.gridSpacing, -scaledSize, 0) center.drawTo(i * self.gridSpacing, scaledSize, 0) center.moveTo(-scaledSize, i * self.gridSpacing, 0) center.drawTo(scaledSize, i * self.gridSpacing, 0) else: if (i % 5) == 0: major.moveTo(i * self.gridSpacing, -scaledSize, 0) major.drawTo(i * self.gridSpacing, scaledSize, 0) major.moveTo(-scaledSize, i * self.gridSpacing, 0) major.drawTo(scaledSize, i * self.gridSpacing, 0) else: minor.moveTo(i * self.gridSpacing, -scaledSize, 0) minor.drawTo(i * self.gridSpacing, scaledSize, 0) minor.moveTo(-scaledSize, i * self.gridSpacing, 0) minor.drawTo(scaledSize, i * self.gridSpacing, 0) center.create() minor.create() major.create() if (self.gridBack): self.gridBack.setScale(scaledSize) def setXyzSnap(self, fSnap): self.fXyzSnap = fSnap def getXyzSnap(self): return self.fXyzSnap def setHprSnap(self, fSnap): self.fHprSnap = fSnap def getHprSnap(self): return self.fHprSnap def computeSnapPoint(self, point): # Start of with current point self.snapPos.assign(point) # Snap if necessary if self.fXyzSnap: self.snapPos.set( ROUND_TO(self.snapPos[0], self.gridSpacing), ROUND_TO(self.snapPos[1], self.gridSpacing), ROUND_TO(self.snapPos[2], self.gridSpacing)) # Move snap marker to this point self.snapMarker.setPos(self.snapPos) # Return the hit point return self.snapPos def computeSnapAngle(self, angle): return ROUND_TO(angle, self.snapAngle) def setSnapAngle(self, angle): self.snapAngle = angle def getSnapAngle(self): return self.snapAngle def setGridSpacing(self, spacing): self.gridSpacing = spacing self.updateGrid() def getGridSpacing(self): return self.gridSpacing def setGridSize(self, size): # Set size of grid back and redraw lines self.gridSize = size self.updateGrid() def getGridSize(self): return self.gridSize
class World(ShowBase): fps_text = fps_text2 = fps_text3 = fps_text4 = None room_dimentions = [0, 0] camera_position = [290., 1609., 370, -1980, -15, 0] # x y z h p r drone = None drone_instance = None markers = {} marker_lines = {} marker_lines_observed = {} active_keys = {} loop_callback = None joy = None simulation = True drone_started = False def __init__(self, width=6.78, length=5.82, simulation=True, video=True): ShowBase.__init__(self) width *= 100 length *= 100 self.room_dimentions = [width, length] self.simulation = simulation self.wall1 = self.wall_model(0, 0, 0, width, 0) self.wall2 = self.wall_model(0, 0, 0, length, 90) self.wall3 = self.wall_model(width, length, 0, width, 180) self.wall4 = self.wall_model(width, length, 0, length, -90) self.root_3d = self.marker_model(position=[0., 0., 0.], orientation=[90, 90, 0]) self.drone = self.drone_model() self.drone_instance = Drone(simulation=simulation, video=video) self.lx_drone = LineNodePath(self.render2d, 'box', 2) self.lx_drone.reparentTo(self.drone) self.lx_drone.setColor(1., 0., 0., 1.) self.lx_drone.setTransparency(TransparencyAttrib.MAlpha) self.lx_drone.setAlphaScale(0.5) self.lx_drone.drawLines([[(0., 0., 0.), (4., 0., 0.)]]) self.lx_drone.create() self.ly_drone = LineNodePath(self.render2d, 'box', 2) self.ly_drone.reparentTo(self.drone) self.ly_drone.setColor(0., 1., 0., 1.) self.ly_drone.setTransparency(TransparencyAttrib.MAlpha) self.ly_drone.setAlphaScale(0.5) self.ly_drone.drawLines([[(0., 0., 0.), (0., 0., 4.)]]) self.ly_drone.create() self.lz_drone = LineNodePath(self.render2d, 'box', 2) self.lz_drone.reparentTo(self.drone) self.lz_drone.setColor(0., 0., 1., 1.) self.lz_drone.setTransparency(TransparencyAttrib.MAlpha) self.lz_drone.setAlphaScale(0.5) self.lz_drone.drawLines([[(0., 0., 0.), (0., 4., 0.)]]) self.lz_drone.create() try: self.joy = xbox.Joystick() joy_ready = False if not self.joy.A(): joy_ready = True if not joy_ready: raise Exception("Joy not ready!") else: print("ready") except: pass # Add the spinCameraTask procedure to the task manager. self.tick_loop = self.taskMgr.add(self.tick, "tick_loop") self.accept("space", self.control_drone, [" "]) self.accept("c", self.control_drone, ["c"]) self.accept("x", self.control_drone, ["x"]) self.accept("w", self.control_drone, ["w"]) self.accept("a", self.control_drone, ["a"]) self.accept("s", self.control_drone, ["s"]) self.accept("d", self.control_drone, ["d"]) self.accept("q", self.control_drone, ["q"]) self.accept("e", self.control_drone, ["e"]) self.accept("m", self.control_drone, ["m"]) self.accept("r", self.control_drone, ["r"]) self.accept("f", self.control_drone, ["f"]) self.keypress_repeat("4", self.move_camera, ["x", -1]) self.keypress_repeat("6", self.move_camera, ["x", 1]) self.keypress_repeat("8", self.move_camera, ["y", 1]) self.keypress_repeat("5", self.move_camera, ["y", -1]) self.keypress_repeat("1", self.move_camera, ["z", 1]) self.keypress_repeat("3", self.move_camera, ["z", -1]) self.keypress_repeat("7", self.move_camera, ["h", -1]) self.keypress_repeat("9", self.move_camera, ["h", 1]) self.keypress_repeat("arrow_up", self.move_camera, ["p", 1]) self.keypress_repeat("arrow_down", self.move_camera, ["p", -1]) def control_drone(self, key): if key == " ": if not self.drone_started: self.drone_started = True self.drone_instance.takeoff() else: self.drone_started = False self.drone_instance.land() if key == "x": self.drone_instance.emergency() elif key == "c": self.drone_instance.move(0., 0., 0., 0.) elif key == "w": self.drone_instance.move(0., 0.08, 0., 0.) elif key == "s": self.drone_instance.move(0., -0.08, 0., 0.) elif key == "d": self.drone_instance.move(0.08, 0., 0., 0.) elif key == "a": self.drone_instance.move(-0.08, 0., 0., 0.) elif key == "q": self.drone_instance.move(0., 0., 0., 0.3) elif key == "e": self.drone_instance.move(0., 0., 0., -0.3) elif key == "m": self.drone_instance.mtrim() elif key == "r": self.drone_instance.move(0., 0., 0.14, 0.) elif key == "f": self.drone_instance.move(0., 0., -0.15, 0.) def keypress_repeat(self, key, callback, parameter): self.accept(key, self.keypress_start, [key, callback, parameter]) self.accept(key + "-up", self.keypress_stop, [key]) def keypress_start(self, key, callback, parameter): self.active_keys[key] = [callback, parameter] def keypress_stop(self, key): self.active_keys[key] = None def move_camera(self, parameter): if parameter[0] == "x": self.camera_position[0] += 10 * np.cos( np.deg2rad(self.camera_position[3])) * parameter[1] self.camera_position[1] += -10 * np.sin( np.deg2rad(self.camera_position[3])) * parameter[1] if parameter[0] == "y": self.camera_position[0] += 10 * np.sin( np.deg2rad(self.camera_position[3])) * parameter[1] self.camera_position[1] += 10 * np.cos( np.deg2rad(self.camera_position[3])) * parameter[1] if parameter[0] == "z": self.camera_position[2] += 10 * parameter[1] if parameter[0] == "h": self.camera_position[3] += parameter[1] if parameter[0] == "p": self.camera_position[4] += parameter[1] def joy_block(self, xbox_key): """ blocks the xbox key until it's released """ while xbox_key(): pass def tick(self, task): for key in self.active_keys: if self.active_keys[key] is not None: self.active_keys[key][0](self.active_keys[key][1]) if self.joy is not None: if self.joy.Back(): self.closeWindow(self.win) self.userExit() self.shutdown() self.destroy() # takeoff: if self.joy.A(): print "takeoff" self.drone_instance.takeoff() self.joy_block(self.joy.A) # emergency: if self.joy.X(): print "emergency" self.drone_instance.emergency() self.joy_block(self.joy.X) # emergency: if self.joy.B(): print "land" self.drone_instance.land() self.joy_block(self.joy.B) (roll, throttle) = self.joy.leftStick() (yaw, pitch) = self.joy.rightStick() print roll, pitch, throttle, yaw self.drone_instance.move(roll, pitch, throttle, yaw) if self.loop_callback is not None: self.loop_callback(self, task) self.camera.setPos(self.camera_position[0], self.camera_position[1], self.camera_position[2]) self.camera.setHpr(-self.camera_position[3], self.camera_position[4], self.camera_position[5]) drone_position = self.convert_position( self.drone_instance.get_position()) drone_orientation = self.drone_instance.get_orientation() self.drone.setPos(drone_position[0], drone_position[1], drone_position[2]) self.drone.setHpr(drone_orientation[0], drone_orientation[1], drone_orientation[2]) if task.time > 0: if self.fps_text is not None: self.fps_text.destroy() self.fps_text = OnscreenText(text="Tick-Rate: " + str(int(task.frame / task.time)), pos=(0.05, 0.05), scale=0.05, align=TextNode.ALeft, parent=self.a2dBottomLeft) if self.fps_text2 is not None: self.fps_text2.destroy() self.fps_text2 = OnscreenText(text="Camera Position: " + str(self.camera_position), pos=(0.05, 0.1), scale=0.05, align=TextNode.ALeft, parent=self.a2dBottomLeft) if self.fps_text3 is not None: self.fps_text3.destroy() self.fps_text3 = OnscreenText( text="Drone Position: " + str(self.drone_instance.get_position()), pos=(0.05, 0.15), scale=0.05, align=TextNode.ALeft, parent=self.a2dBottomLeft) return Task.cont def drone_model(self): drone = self.loader.loadModel("resources/models_3d/drone") drone.setScale(15, 15, 10) drone.reparentTo(self.render) return drone def wall_model(self, x, y, z, length, orientation): wall = self.loader.loadModel("resources/models_3d/plane") wall.reparentTo(self.render) wall.setScale(length, 0, 290) wall.setPos(x, y, z) wall.setH(orientation) wall.setTransparency(TransparencyAttrib.MAlpha) wall.setAlphaScale(0.1) return wall def marker_model(self, position, orientation): marker = self.loader.loadModel("resources/models_3d/plane") marker.reparentTo(self.render) marker.setScale(21, 0, 21) marker.setPos(position[0], position[1], position[2]) marker.setHpr(orientation[0], orientation[1], orientation[2]) marker.setTransparency(TransparencyAttrib.MAlpha) marker.setAlphaScale(0.5) marker.setColor(1., 0., 0., 1.) return marker def line_model(self, r, g, b): line = LineNodePath(self.render2d, 'box', 2) line.reparentTo(self.render) line.setColor(r, g, b, 1.) line.setTransparency(TransparencyAttrib.MAlpha) line.setAlphaScale(0.5) return line def point_model(self, position, color): marker = self.loader.loadModel("resources/models_3d/sphere") marker.reparentTo(self.render) marker.setScale(5, 5, 5) marker.setPos(position[0], position[1], position[2]) marker.setTransparency(TransparencyAttrib.MAlpha) marker.setAlphaScale(0.5) marker.setColor(color[0], color[1], color[2], 1.) def line_draw(self, line, from_position, to_position): line.reset() line.drawLines([[(from_position[0], from_position[1], from_position[2]), (to_position[0], to_position[1], to_position[2])]]) line.create() def get_dimensions(self): return [self.room_dimentions[0] / 100., self.room_dimentions[1] / 100.] def get_drone(self): return self.drone_instance def set_markers(self, markers): self.markers = {} for key, marker in markers.iteritems(): self.markers[key] = self.marker_model( self.convert_position(marker[0]), marker[1]) def set_default_markers(self): dimensions = self.get_dimensions() self.set_markers({ 0: [[dimensions[0] / 2, 1.5, 0.01], [0, 0, 0]], 1: [[dimensions[0] / 2, 1.5, dimensions[1] - 0.01], [0, 0, 0]], 2: [[dimensions[0] - 0.01, 1.5, dimensions[1] / 2], [90, 0, 0]], 3: [[0.01, 1.5, dimensions[1] / 2], [90, 0, 0]] }) def get_markers(self): return self.markers def convert_position(self, position): return [position[0] * 100, position[2] * 100, position[1] * 100] def hook_init(self, callback): callback(self) def hook_loop(self, callback): self.loop_callback = callback