class Hero(DirectObject): def __init__(self,no): self.HeroStats(no) self.display() # self.displaynot() self.SetupEvents() self.Collision() self.Loader() self.SkillStatus() self.sec=0 self.min=0 self.heroPace=None self.timesec = OnscreenText(text = '', pos = (1.2,-0.725),fg=(1,1,1,1),mayChange=1,scale=0.05) self.timemin = OnscreenText(text = '', pos = (1,-0.725),fg=(1,1,1,1),mayChange=1,scale=0.05) self.deathtxt=OnscreenText(text="",pos=(0.5,0.9),scale=0.5) taskMgr.add(self.update,"update") taskMgr.doMethodLater(1,self.Second,"second") taskMgr.add(self.MousePos,"mouse") def HeroStats(self,no): self.char={} self.char=hero[no] self.name=self.char['name'] self.model=Actor(MYDIRMODEL+self.char['model']+'.egg') self.type=None self.heroicon=self.char['icon'][0] self.skillicons=(self.char['icon'][1],self.char['icon'][2],self.char['icon'][3],self.char['icon'][4]) self.StartPos=Point3(25,25,0) self.gold=4000 self.goldrate = 1 self.items=[-1,-1,-1,-1,-1,-1] #each stores the no of the item self.itemindex=0 self.itemname="self.itemb" self.range=self.char['range'] self.strdt=self.char['strdt'] self.agidt=self.char['agidt'] self.intdt=self.char['intdt'] self.type=self.char['type'] self.Delta1=0 self.Delta2=0 self.Delta3=0 self.Delta4=0 self.Delta5=0 self.lvl=0 self.xp=0 self.Input=None self.str=self.char['str']+(self.strdt*self.lvl) self.agi=self.char['agi'] + (self.agidt*self.lvl) self.int=self.char['int'] +(self.intdt*self.lvl) self.basehp=590+self.str*19 self.basemp=220+(self.int*13) self.maxhp=590 +(self.str*19) self.curhp=self.maxhp self.maxmp=220 +(self.int*13) self.curmp=self.maxmp self.armor=self.char['armor'] +(self.agi/7) self.atkspeed=1.5/self.agi if self.type=='str': self.TYPESTR() if self.type=='agi': self.TYPEAGI() if self.type=='int': self.TYPEINT() self.healrate=0.003 *self.str self.mprate=0.02 *self.int self.res=0.25 self.speed=self.char['speed'] self.skill=0 self.isDead=False self.lon=pi*(self.getX()+10)*(self.getY()+10) def Loader(self): self.model=Actor("models/ralph", {"run": "models/ralph-run"}) # self.model=Actor(MYDIRMODEL+self.model+'.egg') self.model.setScale(3) # self.model.setHpr(90,270,0) self.model.setTransparency(0.5) # self.model.setScale(0.1) self.model.setPos(self.StartPos) self.model.reparentTo(render) # self.model.setColor(0, 0, 0, 0) self.model.loop("run") # self.Input=Input(self.model) Flame(self,self.model) #-------------------------------------------------------------Display Function---------------------------------------------------# def TYPESTR(self): self.mindamage=self.char['min']+self.str+self.Delta1 self.maxdamage=self.char['max']+self.str+self.Delta1 self.damage=range(int(self.mindamage),int(self.maxdamage)) def TYPEAGI(self): self.mindamage=self.char['min']+self.agi+self.Delta1 self.maxdamage=self.char['max']+self.agi+self.Delta1 self.damage=range(int(self.mindamage),int(self.maxdamage)) def TYPEINT(self): self.mindamage=self.char['min']+self.int+self.Delta1 self.maxdamage=self.char['max']+self.int+self.Delta1 self.damage=range(int(self.mindamage),int(self.maxdamage)) def TYPE(self): pass def display(self): x,y,z=self.model.getX(),self.model.getY(),self.model.getZ() base.camera.setPos(x,y,z+180) base.camera.setP(-30) base.camera.lookAt(self.model) self.panel=aspect2d.attachNewNode("panel") self.panel.setTransparency(1) self.SKNode=aspect2d.attachNewNode("skl") self.SKNode.setTransparency(0) self.HP=DirectLabel(text='',parent = self.panel,text_fg=(0,0.9,0,1),frameColor=(0,0,0,0),pos=(-0.41,0,-0.850),scale=0.04) self.MP=DirectLabel(text='',parent = self.panel,text_fg=(0,0,0.8,1),frameColor=(0,0,0,0),pos=(-0.41,0,-0.912),scale=0.04) self.LVL=DirectLabel(text ="Level %d"%(self.lvl+1),parent = self.panel,text_fg=(0,0,0,1),frameColor=(0,0,0,0),pos =(-0.5,0,-0.79),scale=Sc) Text1(self,"Damage",-0.26,-0.02,-1) Text1(self,"Armor",-0.27,0.03,-1) Text1(self,"Str",-0.25,0.085,-1) Text1(self,"Agi",-0.25,0.13,-1) Text1(self,"Int",-0.25,0.17,-1) self.DAM=Text2(self,"%d-%d",(self.mindamage-self.Delta1,self.maxdamage-self.Delta1),-0.40,-0.02,-1) self.ARM=Text2(self,"%d",(self.armor-self.Delta2),-0.40,0.03,-1) self.STR=Text2(self,"%d",(self.str-self.Delta3),-0.40,0.085,-1) self.AGI=Text2(self,"%d",(self.agi-self.Delta4),-0.40,0.13,-1) self.INT=Text2(self,"%d",(self.int-self.Delta5),-0.40,0.17,-1) if self.Delta1!=0: self.damdelta=Text3(self,"%d",self.Delta1,-0.4,-0.02,-1) if self.Delta2!=0: self.armdelta=Text3(self,"%d",self.Delta2,-0.4,0.03,-1) if self.Delta3!=0: self.strdelta=Text3(self,"%d",self.Delta3,-0.36,0.085,-1) if self.Delta4!=0: self.agidelta=Text3(self,"%d",self.Delta4,-0.44,0.13,-1) if self.Delta5!=0: self.intdelta=Text3(self,"%d",self.Delta5,-0.44,0.17,-1) self.hpbar = DirectWaitBar(barColor=(0,0.176470,0,1),parent = self.panel,scale=(0.3,0,0.23), frameColor=(0,0,0,1),pos = (0,0,-0.84)) self.mpbar=DirectWaitBar(barColor=(0,0,0.6,1),parent = self.panel,scale=(0.3,0,0.23), frameColor=(0,0,0,1),pos = (0,0,-0.90)) self.lvlbar=DirectWaitBar(barColor=(0,0,0.2,1),parent = self.panel,image='glue/lvlbar.png',image_scale=(1.1,0,0.2),scale=0.35, pos = (0,0,-0.8)) self.lvlbar.setTransparency(1) self.lvlbar.detachNode() self.skbtn1=DirectButton(image=self.skillicons[0]+'.png',parent=self.SKNode,pos=(posx-1.3,0,posy-1.2),pad=(-0.1,-0.1),scale=biconscale,command=self.SkillNo,extraArgs=[0]) self.skbtn2=DirectButton(image=self.skillicons[1]+'.png',parent=self.SKNode,pos=(posx-1.3+0.14,0,posy-1.2),pad=(-0.1,-0.1),scale=biconscale,command=self.SkillNo,extraArgs=[1]) self.skbtn3=DirectButton(image=self.skillicons[2]+'.png',parent=self.SKNode,pos=(posx-1.3+0.28,0,posy-1.2),pad=(-0.1,-0.1),scale=biconscale,command=self.SkillNo,extraArgs=[2]) self.skbtn4=DirectButton(image=self.skillicons[3]+'.png',parent=self.SKNode,pos=(posx-1.3+0.42,0,posy-1.2),pad=(-0.1,-0.1),scale=biconscale,command=self.SkillNo,extraArgs=[3]) self.b2 = DirectButton(text ="dam",parent = self.panel,pos=(-0.5,0,0),enableEdit=1,scale=(0.25,0,0.1),command=self.hurt,extraArgs=[200]) self.b3 = DirectButton(text ="",image='tome.tga',pos=(0.5,0,0),frameColor=(0,0,0,0),pad=(-0.1,-0.1),enableEdit=1,scale=(0.07,0,0.07),command=self.itemBuy,extraArgs=[0,300]) self.GOLD=OnscreenText(text='',fg=(1,1,1,1),pos=(1.225,-0.84),scale=0.05) # self.escapeEvent = OnscreenText(text=HELPTEXT, font = font,style=1, fg=(1,1,1,1), pos=(-0.82, -0.725),align=TextNode.ALeft, scale = .045) def displaynot(self): self.panel.detachNode() self.SKNode.detachNode() #------------------------------------------------------------Set Functions--------------------------------------------------------# def setDamage(self,amt): if delta >1: self.damage+=delta else: self.damage=self.damage+self.damage*delta def Delta(self,amt1,amt2,amt3,amt4,amt5): if amt1!=0: #After changes occur for that period the taks sets the values to zero self.Delta1+=amt1 if amt2!=0: self.Delta2+=amt2 if amt3!=0: self.Delta3+=amt3 if amt4!=0: self.Delta4+=amt3 if amt5!=0: self.Delta5+=amt3 def hurt(self,amt): if self.curhp>0: if self.curhp<=self.maxhp: self.curhp-=amt*1 def hurtMag(self,delta): if self.curhp>0: if self.curhp<=self.maxhp: self.curhp-=delta*self.res def heal(self,delta): if self.curhp!=self.maxhp: if self.curhp < self.maxhp: self.curhp+=delta def replenish(self,delta): if self.curmp!=self.maxmp: if self.curmp < self.maxmp: if self.curmp>0: self.curmp+=delta def manaspend(self,amt): if self.curmp>amt: self.curmp-=amt def setSpeed(self,delta): if delta > 1: self.speed+=delta else: self.speed=self.speed+self.speed*delta def setArmor(self,delta): self.armor+=delta def setPos(self,x,y,z): self.model.setPos(x,y,z) def setHPColor(self): if self.curhp<0.25*self.maxhp: self.hpbar['barColor']=(1,0,0,1) elif self.curhp<0.5*self.maxhp: self.hpbar['barColor']=(1,0.5,0,1) elif self.curhp<0.75*self.maxhp: self.hpbar['barColor']=(1,1,0,1) else: self.hpbar['barColor']=(0,0.176470,0,1) #-------------------------------------------------------------Setup Keys And EVENTS--------------------------------------------------# def SetupEvents(self): self.dt=0 self.keyMap = {"left":0, "right":0, "forward":0} self.isMoving = False self.Change=False self.Animate=False self.pos3d=None self.target=Point3() self.dist=0 self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) self.Text = OnscreenText(text="Set PanRate",pos=(-1.25,-0.15),scale=0.1) self.slider = DirectSlider(range=(20,100), value=50, pageSize=2, pos=(-1.25,0,-0.2),scale= (0.2,0.2,0.2), command=self.setScrollSpeed) self.dumm=loader.loadModel("models/panda.egg") self.dumm.reparentTo(render) self.dumm.setTag("Unit",'1') self.dumm.setPos(0,0,0) self.mini=0 self.x1,self.y1=self.model.getX(),self.model.getY() self.x2,self.y2=self.dumm.getX(),self.dumm.getY() self.fired=False self.atk=Attack(self.model,self.dumm,1.4) self.accept("arrow_left", self.setKey1, ["left",1,True]) self.accept("arrow_right", self.setKey1, ["right",1,True]) self.accept("arrow_up", self.setKey1, ["forward",1,True]) self.accept("arrow_left-up", self.setKey1, ["left",0,False]) self.accept("arrow_right-up", self.setKey1, ["right",0,False]) self.accept("arrow_up-up", self.setKey1, ["forward",0,False]) self.accept("mouse1",self.ObjectClick) self.accept("mouse3",self.MoveHero) def MoveHero(self): self.startR=self.model.getHpr() self.target=self.mpos3d x2,y2,z2=self.target.getX(),self.target.getY(),self.target.getZ() h1,p1,r1=self.model.getH(),self.model.getP(),self.model.getR() self.dist=sqrt(pow(self.x1-x2,2)+pow(self.y1-y2,2)) self.sptime=self.dist/(self.speed) self.hall=270-degrees(y2/x2) # self.model.setPos(self.model,self.spd,0,self.spd) self.Inter=LerpPosHprInterval(self.model,self.sptime,pos=self.target ,startPos=self.model.getPos(),startHpr=self.startR,hpr=self.startR)#(h1,p1,self.hall)) #Inter2=Func(self.model.lookAt(self.target),Wait(0.3)) self.heroPace = Sequence(self.Inter,name="heroPace") self.heroPace.start() def Collision(self): self.mpos3d=0 self.plane = Plane(Vec3(0, 0, 1), Point3(0, 0, 0)) base.cTrav = CollisionTraverser() self.collHandler = CollisionHandlerQueue() self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) base.cTrav.addCollider(self.pickerNP, self.collHandler) def ObjectClick(self): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) base.cTrav.traverse(render) # Assume for simplicity's sake that myHandler is a CollisionHandlerQueue. if self.collHandler.getNumEntries() > 0: # This is so we get the closest object. self.collHandler.sortEntries() self.pickedObj = self.collHandler.getEntry(0).getIntoNodePath() self.pickedObj = self.pickedObj.findNetTag('Unit') if not self.pickedObj.isEmpty(): self.Attack(self.pickedObj.getPos()) #Handles the object def setKey1(self, key, value,value2): self.keyMap[key] = value self.Change=value2 def checkKeys(self): if (self.keyMap["left"]!=0): self.model.setH(self.model.getH() + self.dt*300) if (self.keyMap["right"]!=0): self.model.setH(self.model.getH() - self.dt*300) if (self.keyMap["forward"]!=0): self.model.setX(self.model, +(self.dt*25*SPEED)) def checkAnim(self): if self.Change: #(self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0): if self.isMoving is False: self.model.loop("run") self.isMoving = True else: if self.isMoving: self.model.stop() self.model.pose("walk",5) self.isMoving = False if self.Animate: pass def Attack(self,pos): self.atk.setWeil(self.model) self.atk.setTarg(self.dumm) self.atk.setDist(self.mini) if self.mini<=60: self.Animate=self.atk.ATT() else: messenger.send('mouse3') if self.mini<=60: self.atk.ATT() def setScrollSpeed(self): SCROLLSPEED=self.slider['value'] def UnSetupEvents(self): self.ignore("arrow_left") self.ignore("arrow_right") self.ignore("arrow_up") self.ignore("arrow_left-up") self.ignore("arrow_right-up") self.ignore("arrow_up-up") self.ignore("enter") self.ignore("mouse1") self.ignore("mouse3") taskMgr.remove("update") taskMgr.remove("second") taskMgr.remove("mouse") #--------------------------------------------------------------Return Functions------------------------------------------------------# def getDamage(self): return self.damage def getPos(self): return self.model.getPos() def getX(self): return self.model.getX() def getY(self): return self.model.getY() def getZ(self): return self.model.getZ() def getlvl(self): return self.lvl def getModel(self): return self.model def gainxp(self,unit): self.xp+=unit def gainGold(self,gain): self.gold+=gain def sendTime(self,min,sec): self.min=min self.sec=sec #----------------------------------------------------------------ITEM FUNCTIONS--------------------------------------------------------# def itemBuy(self,arg,cost): if self.gold>=0: if self.itemindex<=5: del self.items[self.itemindex] self.items.insert(self.itemindex,arg) self.gainGold(-cost) if self.items[self.itemindex]!=-1: if self.itemindex==0: self.itm0= aspect2d.attachNewNode("item0") DirectButton(text ="",parent=self.itm0,image='tome.tga',pos=(0+0.12*self.itemindex,0,-0.90),pad=(-0.1,-0.1),scale=(0.05,0,0.05),extraArgs=[arg,cost],command=self.itemSold)#,commandButtons=DGG.RMB) if self.itemindex==1: self.itm1= aspect2d.attachNewNode("item1") DirectButton(text ="",parent=self.itm1,image='tome.tga',pos=(0+0.12*self.itemindex,0,-0.90),pad=(-0.1,-0.1),scale=(0.05,0,0.05),extraArgs=[arg,cost],command=self.itemSold)#,commandButtons=DGG.RMB) if self.itemindex==2: self.itm2= aspect2d.attachNewNode("item2") DirectButton(text ="",parent=self.itm2,image='tome.tga',pos=(0+0.12*self.itemindex,0,-0.90),pad=(-0.1,-0.1),scale=(0.05,0,0.05),extraArgs=[arg,cost],command=self.itemSold)#,commandButtons=DGG.RMB) if self.itemindex==3: self.itm3= aspect2d.attachNewNode("item3") DirectButton(text ="",parent=self.itm3,image='tome.tga',pos=(0+0.12*self.itemindex,0,-0.90),pad=(-0.1,-0.1),scale=(0.05,0,0.05),extraArgs=[arg,cost],command=self.itemSold)#,commandButtons=DGG.RMB) if self.itemindex==4: self.itm4= aspect2d.attachNewNode("item4") DirectButton(text ="",parent=self.itm4,image='tome.tga',pos=(0+0.12*self.itemindex,0,-0.90),pad=(-0.1,-0.1),scale=(0.05,0,0.05),extraArgs=[arg,cost],command=self.itemSold)#,commandButtons=DGG.RMB) if self.itemindex==5: self.itm5= aspect2d.attachNewNode("item5") DirectButton(text ="",parent=self.itm5,image='tome.tga',pos=(0+0.12*self.itemindex,0,-0.90),pad=(-0.1,-0.1),scale=(0.05,0,0.05),extraArgs=[arg,cost],command=self.itemSold)#,commandButtons=DGG.RMB) self.itemindex+=1 else: Error("No Empty Slots") else: Error("No Gold") def itemSold(self,itemtosell,cost): self.ind=self.items.index(itemtosell) del self.items[self.ind] self.items.insert(self.ind,-1) self.gainGold(cost/2) if self.ind==0: self.itm0.detachNode() if self.ind==1: self.itm1.detachNode() if self.ind==2: self.itm2.detachNode() if self.ind==3: self.itm3.detachNode() if self.ind==4: self.itm4.detachNode() if self.ind==5: self.itm5.detachNode() self.itemindex-=1 def lvlup(self): self.lvl+=1 self.str=self.char['str'] +(self.strdt*self.lvl) self.str=self.char['str'] +(self.agidt*self.lvl) self.int=self.char['int'] +(self.intdt*self.lvl) self.hpgain=(self.strdt+self.Delta1)*19 self.mpgain=(self.intdt+self.Delta3)*13 self.maxhp=590+self.str*19 self.maxmp=290+self.int*13 #some error here self.heal(self.hpgain) self.replenish(self.mpgain) self.xp =0 #---------------------------------------------------------SKILL FUNCTIONS-------------------------------------# def SkillStatus(self): self.sp1=0 self.sp2=0 self.sp3=0 self.sp4=0 self.sp1dam=0 self.sp2dam=0 self.sp3dam=0 self.sp4dam=0 if self.sp1==1: self.range=400 self.sp1dam=130 self.raduis=100 self.sp2dam=30 self.sp3dam=90 self.pulses=6 def SkillNo(self,arg): if arg==0: if self.curmp>=100: self.accept("mouse1",Blink,extraArgs=[self]) self.skbtn1['image']='cancel.png' # self.skbtn1['command']=self.setOpen() else: Error("NO MANA") elif arg==1: StatUp(self) elif arg==2: StatDn(self) else: Ulti(self) def setOpen(self): self.open=False self.ignore("mouse1") self.skbtn1['image']=self.skillicons[0]+'.png' self.accept("mouse1",self.ObjectClick) #----------------------------------------TASK FUNCTIONS------------------------------------------------------# def Delay(self,task): self.Delta(-2,-2,-2) return task.done def Second(self,task): self.gainGold(self.goldrate) self.heal(self.healrate) self.replenish(self.mprate) return task.again def update(self,task): self.timemin.setText(str(self.min)) self.timesec.setText(str(self.sec)) self.str=self.char['str'] +(self.strdt*self.lvl)+self.Delta3 self.agi=self.char['agi'] + (self.agidt*self.lvl)+self.Delta4 self.int=self.char['int']+(self.intdt*self.lvl)+self.Delta5 self.hpgain=(self.strdt+self.Delta1)*19 self.mpgain=(self.intdt+self.Delta3)*13 self.maxhp=590+self.str*19 self.maxmp=290+self.int*13 #some error here # self.heal(self.hpgain) # self.replenish(self.mpgain) self.armor=self.char['armor'] +(self.agi/7)+self.Delta2 self.atkspeed=1.5/self.agi if self.type=='str': self.TYPESTR() if self.type=='agi': self.TYPEAGI() if self.type=='int': self.TYPEINT() self.healrate=0.03 *self.str self.mprate=0.02 *self.int self.GOLD.setText(str(self.gold)) self.hpbar['range']=int(self.maxhp) self.hpbar['value']=int(self.curhp) self.mpbar['range']=int(self.maxmp) self.mpbar['value']=int(self.curmp) self.lvlbar['range']=int(10*self.lvl) self.lvlbar['value']=int(self.xp) self.HP['text']="HP"+str(int(self.curhp))+"/"+str(int(self.maxhp)) self.MP['text']="MP"+str(int(self.curmp))+"/"+str(int(self.maxmp)) self.DAM['text']=str(int(self.mindamage))+'-'+str(int(self.maxdamage)) self.ARM['text']=str(int(self.armor)) self.STR['text']=str(int(self.str)) self.AGI['text']=str(int(self.agi)) self.INT['text']=str(int(self.int)) self.LVL['text']="LEVEL "+str(int(self.lvl)) if self.xp>=20*20: self.lvlup() if self.curhp<=0: taskMgr.add(self.Death,"death") self.x1,self.y1=self.model.getX(),self.model.getY() self.x2,self.y2=self.dumm.getX(),self.dumm.getY() self.mini=sqrt(pow(self.x1-self.x2,2)+pow(self.y1-self.y2,2)) Debug2(self,str(self.mini)) elapsed = globalClock.getDt() self.dt=elapsed self.setHPColor() self.checkAnim() self.checkKeys() # base.camera.lookAt(self.model) # self.floater.setPos(self.model.getPos()) # base.camera.lookAt(self.floater) return task.cont def Death(self,task): self.isDead=True Debug2(self,str(task.time)) if self.isDead==True: self.model.reparentTo(hidden) self.panel.detachNode() self.deathtime=(self.lvl+1)*3 self.isDead=False if int(task.time)==self.deathtime: self.model.setPos(self.StartPos) self.model.reparentTo(render) self.curhp=self.maxhp self.model.loop("walk") self.display() taskMgr.remove("death") # self.deathtxt.destroy() return task.cont def MousePos(self, task): #This Took me 1.5 Months to Learn if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.mpos3d = Point3() nearPoint = Point3() farPoint = Point3() base.camLens.extrude(mpos, nearPoint, farPoint) if self.plane.intersectsLine(self.mpos3d, render.getRelativePoint(camera, nearPoint),render.getRelativePoint(camera, farPoint)): pass return task.again def destroy(self): self.panel.detachNode() self.t1.destroy() self.t2.destroy() self.model.remove() self.timesec.destroy() self.timemin.destroy() self.UnsetupEvents()
class MoveCursor(object): _EDGES = 40 _zPos = 0 _movingUp = False _movingDown = False _color = Vec4(0.3, 0.3, 0.8, 1) _currentPos = Vec3(0, 0, 0) def __init__(self, parent, entity, foot=1): # We keep a reference to the entity self.entity = entity # Setup the components of the cursor self._moveRadCircleNP = NodePath("Movement Radius Node") self._moveLine = LineSegs() self._moveLineNP = NodePath("Movement Direction Line Node") self._moveZLine = LineSegs() self._moveZLineNP = NodePath("Movement Z Line Node") self._moveZFootNP = NodePath("Movement Z Foot Node") self._moveFootCircle = LineSegs() self._moveFootCircleNP = NodePath("Movement Foot Circle Node") self._np = NodePath("Movement Node") self.aaLevel = 16 self.parent = parent self.start = Vec3(0, 0, 0) self.moveRad = entity.moveRadius self.footRad = foot self.plane = Plane(Vec3(0, 0, 1), Point3(0, 0, 0)) if self.aaLevel > 0: self._np.setAntialias(AntialiasAttrib.MLine, self.aaLevel) x = 0 y = 0 z = 0 # Draw movement radius moveRadLine = LineSegs() moveRadLine.setThickness(1) moveRadLine.setColor(self._color) moveRadLine.moveTo(self.moveRad, 0, 0) for i in range(self._EDGES + 1): newX = (self.moveRad * math.cos((2*math.pi/self._EDGES)*i)) newY = (self.moveRad * math.sin((2*math.pi/self._EDGES)*i)) moveRadLine.drawTo(newX, newY, 0) moveRadGeom = moveRadLine.create() self._moveRadCircleNP = NodePath(moveRadGeom) self._moveRadCircleNP.reparentTo(self._np) # Draw movement foot circle self._moveFootCircle.setThickness(1) self._moveFootCircle.setColor(self._color) self._moveFootCircle.moveTo(self.footRad, 0, 0) for i in range(self._EDGES): newX = (self.footRad * math.cos((2*math.pi/self._EDGES)*i)) newY = (self.footRad * math.sin((2*math.pi/self._EDGES)*i)) self._moveFootCircle.drawTo(newX, newY, 0) self._moveFootCircle.drawTo(self.footRad, 0, 0) moveFootCircleGeom = self._moveFootCircle.create() self._moveFootCircleNP = NodePath(moveFootCircleGeom) self._moveFootCircleNP.reparentTo(self._np) # Draw movement direction line self._moveLine.setThickness(1) self._moveLine.setColor(self._color) self._moveLine.moveTo(0, 0, 0) self._moveLine.drawTo(x, y, z) self.moveLineGO = self._moveLine.create(True) self._moveLineNP = NodePath(self.moveLineGO) self._moveLineNP.reparentTo(self._np) def updateMovePos(self, Task): # endPos must be transformed in the the coord sys of the model m_pos = self.getMouseXY() if m_pos is not None: # Transform current mouse pos endPos = self.parent.getRelativePoint(render, m_pos) # Adjust Z coord if needed if self._movingUp: self._zPos += 0.1 elif self._movingDown: self._zPos -= 0.1 endPos.setZ(self._zPos) # Check if we're trying to move too far, if not update pos dist = math.sqrt(endPos.getX()**2 + endPos.getY()**2 + 2*(endPos.getZ()**2)) if dist <= self.moveRad: self._moveLine.setVertex(1, endPos) self._moveFootCircleNP.setPos(endPos) #self._currentPos = self.parent.getRelativePoint(self.parent, endPos) #print("endPos=%s"%endPos) #print("myRelPos=%s"%self._currentPos) self._currentPos = endPos return Task.cont def getMouseXY(self): # NOTE - this returns the mouse pos in the ships coord sys if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() pos3d = Point3() nearPoint = Point3() farPoint = Point3() base.camLens.extrude(mpos, nearPoint, farPoint) if self.plane.intersectsLine(pos3d, render.getRelativePoint(camera, nearPoint), render.getRelativePoint(camera, farPoint)): return pos3d return None def getPosition(self): return self._currentPos def startDrawing(self): self._np.reparentTo(self.parent) taskMgr.add(self.updateMovePos, 'Movement Indicator Update Task') def stopDrawing(self): taskMgr.remove('Movement Indicator Update Task') self._np.detachNode()
class CameraHandler(DirectObject.DirectObject): def __init__(self, showbase): self.showbase = showbase self.showbase.disableMouse() # This disables the default mouse based camera control used by panda. This default control is awkward, and won't be used. self.showbase.camera.setPos(0, -150, 200) self.showbase.camera.lookAt(0, 0, 0) # Gives the camera an initial position and rotation. self.mx, self.my = 0, 0 # Sets up variables for storing the mouse coordinates self.orbiting = False # A boolean variable for specifying whether the camera is in orbiting mode. Orbiting mode refers to when the camera is being moved # because the user is holding down the right mouse button. self.target = Vec3() # sets up a vector variable for the camera's target. The target will be the coordinates that the camera is currently focusing on. self.camDist = 150 # A variable that will determine how far the camera is from it's target focus self.panRateDivisor = 10 # This variable is used as a divisor when calculating how far to move the camera when panning. Higher numbers will yield slower panning # and lower numbers will yield faster panning. This must not be set to 0. self.panZoneSize = .1 # This variable controls how close the mouse cursor needs to be to the edge of the screen to start panning the camera. It must be less than 1, # and I recommend keeping it less than .2 self.panLimitsX = Vec2(-1000, 1000) self.panLimitsY = Vec2(-1000, 1000) # These two vairables will serve as limits for how far the camera can pan, so you don't scroll away from the map. self.maxZoomOut = 500 self.maxZoomIn = 25 #These two variables set the max distance a person can zoom in or out self.orbitRate = 75 # This is the rate of speed that the camera will rotate when middle mouse is pressed and mouse moved # recommended rate 50-100 self.setTarget(0, 0, 0) # calls the setTarget function to set the current target position to the origin. self.turnCameraAroundPoint(0, 0) # calls the turnCameraAroundPoint function with a turn amount of 0 to set the camera position based on the target and camera distance self.accept("mouse2", self.startOrbit) # sets up the camrea handler to accept a right mouse click and start the "drag" mode. self.accept("mouse2-up", self.stopOrbit) # sets up the camrea handler to understand when the right mouse button has been released, and ends the "drag" mode when # the release is detected. self.storeX = 0 self.storeY = 0 # for storing of the x and y for the orbit # The next pair of lines use lambda, which creates an on-the-spot one-shot function. self.accept("wheel_up", self.zoomIn) # sets up the camera handler to detet when the mouse wheel is rolled upwards and uses a lambda function to call the # adjustCamDist function with the argument 0.9 self.accept("wheel_down", self.zoomOut) # sets up the camera handler to detet when the mouse wheel is rolled upwards and uses a lambda function to call the # adjustCamDist function with the argument 1.1 # Keys array (down if 1, up if 0) self.keys = {"cam-left": 0, "cam-right": 0, "cam-up": 0, "cam-down": 0} # Using Arrow Keys self.accept("arrow_left", self.setValue, [self.keys, "cam-left", 1]) self.accept("arrow_right", self.setValue, [self.keys, "cam-right", 1]) self.accept("arrow_up", self.setValue, [self.keys, "cam-up", 1]) self.accept("arrow_down", self.setValue, [self.keys, "cam-down", 1]) self.accept("arrow_left-up", self.setValue, [self.keys, "cam-left", 0]) self.accept("arrow_right-up", self.setValue, [self.keys, "cam-right", 0]) self.accept("arrow_up-up", self.setValue, [self.keys, "cam-up", 0]) self.accept("arrow_down-up", self.setValue, [self.keys, "cam-down", 0]) self.keyPanRate = 1.5 # pan rate for when user presses the arrow keys # set up plane for checking collision with for mouse-3d world self.plane = Plane(Vec3(0, 0, 1), Point3(0, 0, 0)) def destroy(self): self.ignoreAll() def setValue(self, array, key, value): array[key] = value def clamp(self, val, minVal, maxVal): val = min(max(val, minVal), maxVal) return val def zoomOut(self): if self.camDist <= self.maxZoomOut: self.adjustCamDist(1.1) return True def zoomIn(self): if self.camDist >= self.maxZoomIn: self.adjustCamDist(0.9) return True def turnCameraAroundPoint(self, deltaX, deltaY): # This function performs two important tasks. First, it is used for the camera orbital movement that occurs when the # right mouse button is held down. It is also called with 0s for the rotation inputs to reposition the camera during the # panning and zooming movements. # The delta inputs represent the change in rotation of the camera, which is also used to determine how far the camera # actually moves along the orbit. newCamHpr = Vec3() newCamPos = Vec3() # Creates temporary containers for the new rotation and position values of the camera. camHpr = self.showbase.camera.getHpr() # Creates a container for the current HPR of the camera and stores those values. newCamHpr.setX(camHpr.getX() + deltaX) newCamHpr.setY(self.clamp(camHpr.getY() - deltaY, -85, -10)) newCamHpr.setZ(camHpr.getZ()) # Adjusts the newCamHpr values according to the inputs given to the function. The Y value is clamped to prevent # the camera from orbiting beneath the ground plane and to prevent it from reaching the apex of the orbit, which # can cause a disturbing fast-rotation glitch. self.showbase.camera.setHpr(newCamHpr) # Sets the camera's rotation to the new values. angleradiansX = newCamHpr.getX() * (math.pi / 180.0) angleradiansY = newCamHpr.getY() * (math.pi / 180.0) # Generates values to be used in the math that will calculate the new position of the camera. newCamPos.setX(self.camDist * math.sin(angleradiansX) * math.cos(angleradiansY) + self.target.getX()) newCamPos.setY(-self.camDist * math.cos(angleradiansX) * math.cos(angleradiansY) + self.target.getY()) newCamPos.setZ(-self.camDist * math.sin(angleradiansY) + self.target.getZ()) self.showbase.camera.setPos(newCamPos.getX(), newCamPos.getY(), newCamPos.getZ()) # Performs the actual math to calculate the camera's new position and sets the camera to that position. #Unfortunately, this math is over my head, so I can't fully explain it. self.showbase.camera.lookAt(self.target.getX(), self.target.getY(), self.target.getZ()) # Points the camera at the target location. def getTarget(self): return self.target # returns the cur def setTarget(self, x, y, z): #This function is used to give the camera a new target position. x = self.clamp(x, self.panLimitsX.getX(), self.panLimitsX.getY()) self.target.setX(x) y = self.clamp(y, self.panLimitsY.getX(), self.panLimitsY.getY()) self.target.setY(y) self.target.setZ(z) # Stores the new target position values in the target variable. The x and y values are clamped to the pan limits. def setPanLimits(self, xMin, xMax, yMin, yMax): # This function is used to set the limitations of the panning movement. self.panLimitsX = (xMin, xMax) self.panLimitsY = (yMin, yMax) # Sets the inputs into the limit variables. def startOrbit(self): # This function puts the camera into orbiting mode. # Get windows properties props = WindowProperties() # Set Hide Cursor Property #props.setCursorHidden(True) # Set properties self.showbase.win.requestProperties(props) # hide cursor if self.showbase.mouseWatcherNode.hasMouse(): # We're going to use the mouse, so we have to make sure it's in the game window. If it's not and we try to use it, we'll get # a crash error. mpos = self.showbase.mouseWatcherNode.getMouse() self.storeX = mpos.getX() self.storeY = mpos.getY() # take current cursor values self.showbase.win.movePointer(0, self.showbase.win.getXSize() / 2, self.showbase.win.getYSize() / 2) # set to center self.mx = 0 self.my = 0 self.orbiting = True # Sets the orbiting variable to true to designate orbiting mode as on. def stopOrbit(self): # This function takes the camera out of orbiting mode. self.orbiting = False # Sets the orbiting variable to false to designate orbiting mode as off. self.showbase.win.movePointer( 0, int((self.storeX + 1.0) / 2 * self.showbase.win.getXSize()), int(self.showbase.win.getYSize() - ((self.storeY + 1.0) / 2 * self.showbase.win.getYSize()))) # set to taken cursor values from startOrbit if self.showbase.mouseWatcherNode.hasMouse(): # We're going to use the mouse, so we have to make sure it's in the game window. If it's not and we try to use it, we'll get # a crash error. mpos = self.showbase.mouseWatcherNode.getMouse() self.mx = mpos.getX() self.my = mpos.getY() # Get windows properties props = WindowProperties() # Set Hide Cursor Property props.setCursorHidden(False) # Set properties self.showbase.win.requestProperties(props) # reshow cursor def adjustCamDist(self, distFactor): # This function increases or decreases the distance between the camera and the target position to simulate zooming in and out. # The distFactor input controls the amount of camera movement. # For example, inputing 0.9 will set the camera to 90% of it's previous distance. self.camDist = self.camDist * distFactor # Sets the new distance into self.camDist. self.turnCameraAroundPoint(0, 0) # Calls turnCameraAroundPoint with 0s for the rotation to reset the camera to the new position. def camMoveTask(self, dt): # This task is the camera handler's work house. It's set to be called every frame and will control both orbiting and panning the camera. if self.showbase.mouseWatcherNode.hasMouse(): # We're going to use the mouse, so we have to make sure it's in the game window. If it's not and we try to use it, we'll get # a crash error. mpos = self.showbase.mouseWatcherNode.getMouse() # Gets the mouse position if self.orbiting: # Checks to see if the camera is in orbiting mode. Orbiting mode overrides panning, because it would be problematic if, while # orbiting the camera the mouse came close to the screen edge and started panning the camera at the same time. self.turnCameraAroundPoint( (self.mx - mpos.getX()) * self.orbitRate * dt, (self.my - mpos.getY()) * self.orbitRate * dt) else: # If the camera isn't in orbiting mode, we check to see if the mouse is close enough to the edge of the screen to start panning moveY = False moveX = False # these two booleans are used to denote if the camera needs to pan. X and Y refer to the mouse position that causes the # panning. X is the left or right edge of the screen, Y is the top or bottom. if self.my > (1 - self.panZoneSize): angleradiansX1 = self.showbase.camera.getH() * (math.pi / 180.0) panRate1 = (1 - self.my - self.panZoneSize) * ( self.camDist / self.panRateDivisor) moveY = True if self.my < (-1 + self.panZoneSize): angleradiansX1 = self.showbase.camera.getH() * ( math.pi / 180.0) + math.pi panRate1 = (1 + self.my - self.panZoneSize) * ( self.camDist / self.panRateDivisor) moveY = True if self.mx > (1 - self.panZoneSize): angleradiansX2 = self.showbase.camera.getH() * ( math.pi / 180.0) + math.pi * 0.5 panRate2 = (1 - self.mx - self.panZoneSize) * ( self.camDist / self.panRateDivisor) moveX = True if self.mx < (-1 + self.panZoneSize): angleradiansX2 = self.showbase.camera.getH() * ( math.pi / 180.0) - math.pi * 0.5 panRate2 = (1 + self.mx - self.panZoneSize) * ( self.camDist / self.panRateDivisor) moveX = True # These four blocks check to see if the mouse cursor is close enough to the edge of the screen to start panning and then # perform part of the math necessary to find the new camera position. Once again, the math is a bit above my head, so # I can't properly explain it. These blocks also set the move booleans to true so that the next lines will move the camera. # If up or down keys are pressed if self.keys["cam-up"] ^ self.keys["cam-down"]: moveY = True panRate1 = self.keyPanRate # Update warlock position on z plane if self.keys["cam-up"]: angleradiansX1 = self.showbase.camera.getH() * ( math.pi / 180.0) + math.pi if self.keys["cam-down"]: angleradiansX1 = self.showbase.camera.getH() * ( math.pi / 180.0) # If left or right keys are pressed if self.keys["cam-left"] ^ self.keys["cam-right"]: moveX = True panRate2 = self.keyPanRate # Update warlock position on x plane if self.keys["cam-left"]: angleradiansX2 = self.showbase.camera.getH() * ( math.pi / 180.0) + math.pi * 0.5 if self.keys["cam-right"]: angleradiansX2 = self.showbase.camera.getH() * ( math.pi / 180.0) - math.pi * 0.5 if moveY: tempX = self.target.getX( ) + math.sin(angleradiansX1) * panRate1 * dt * 50 tempX = self.clamp(tempX, self.panLimitsX.getX(), self.panLimitsX.getY()) self.target.setX(tempX) tempY = self.target.getY( ) - math.cos(angleradiansX1) * panRate1 * dt * 50 tempY = self.clamp(tempY, self.panLimitsY.getX(), self.panLimitsY.getY()) self.target.setY(tempY) self.turnCameraAroundPoint(0, 0) if moveX: tempX = self.target.getX( ) - math.sin(angleradiansX2) * panRate2 * dt * 50 tempX = self.clamp(tempX, self.panLimitsX.getX(), self.panLimitsX.getY()) self.target.setX(tempX) tempY = self.target.getY( ) + math.cos(angleradiansX2) * panRate2 * dt * 50 tempY = self.clamp(tempY, self.panLimitsY.getX(), self.panLimitsY.getY()) self.target.setY(tempY) self.turnCameraAroundPoint(0, 0) # These two blocks finalize the math necessary to find the new camera position and apply the transformation to the # camera's TARGET. Then turnCameraAroundPoint is called with 0s for rotation, and it resets the camera position based # on the position of the target. The x and y values are clamped to the pan limits before they are applied. #print(self.target) self.mx = mpos.getX() self.my = mpos.getY() # The old mouse positions are updated to the current mouse position as the final step. # Finds 3d world point on the z = 0 plane for destination/target def getMouse3D(self): # make sure process has the mouse to not cause error if self.showbase.mouseWatcherNode.hasMouse(): # get screen coordinates of mouse mpos = self.showbase.mouseWatcherNode.getMouse() pos3d = Point3() nearPoint = Point3() farPoint = Point3() # find vector of cameras facing from mouse screen coordinates and get near and far points on frustrum self.showbase.camLens.extrude(mpos, nearPoint, farPoint) # check for intersection with z = 0 plane if self.plane.intersectsLine( pos3d, self.showbase.render.getRelativePoint( self.showbase.camera, nearPoint), self.showbase.render.getRelativePoint( self.showbase.camera, farPoint)): # return this position if exists return pos3d # or return (-1, -1, -1) return Vec3(-1, -1, -1)
class CameraHandler(DirectObject.DirectObject): def __init__(self, showbase): self.showbase = showbase self.showbase.disableMouse() # This disables the default mouse based camera control used by panda. This default control is awkward, and won't be used. self.showbase.camera.setPos(0, -150, 200) self.showbase.camera.lookAt(0, 0, 0) # Gives the camera an initial position and rotation. self.mx, self.my = 0, 0 # Sets up variables for storing the mouse coordinates self.orbiting = False # A boolean variable for specifying whether the camera is in orbiting mode. Orbiting mode refers to when the camera is being moved # because the user is holding down the right mouse button. self.target = Vec3() # sets up a vector variable for the camera's target. The target will be the coordinates that the camera is currently focusing on. self.camDist = 150 # A variable that will determine how far the camera is from it's target focus self.panRateDivisor = 10 # This variable is used as a divisor when calculating how far to move the camera when panning. Higher numbers will yield slower panning # and lower numbers will yield faster panning. This must not be set to 0. self.panZoneSize = .1 # This variable controls how close the mouse cursor needs to be to the edge of the screen to start panning the camera. It must be less than 1, # and I recommend keeping it less than .2 self.panLimitsX = Vec2(-1000, 1000) self.panLimitsY = Vec2(-1000, 1000) # These two vairables will serve as limits for how far the camera can pan, so you don't scroll away from the map. self.maxZoomOut = 500 self.maxZoomIn = 25 #These two variables set the max distance a person can zoom in or out self.orbitRate = 75 # This is the rate of speed that the camera will rotate when middle mouse is pressed and mouse moved # recommended rate 50-100 self.setTarget(0, 0, 0) # calls the setTarget function to set the current target position to the origin. self.turnCameraAroundPoint(0, 0) # calls the turnCameraAroundPoint function with a turn amount of 0 to set the camera position based on the target and camera distance self.accept("mouse2", self.startOrbit) # sets up the camrea handler to accept a right mouse click and start the "drag" mode. self.accept("mouse2-up", self.stopOrbit) # sets up the camrea handler to understand when the right mouse button has been released, and ends the "drag" mode when # the release is detected. self.storeX = 0 self.storeY = 0 # for storing of the x and y for the orbit # The next pair of lines use lambda, which creates an on-the-spot one-shot function. self.accept("wheel_up", self.zoomIn) # sets up the camera handler to detet when the mouse wheel is rolled upwards and uses a lambda function to call the # adjustCamDist function with the argument 0.9 self.accept("wheel_down", self.zoomOut) # sets up the camera handler to detet when the mouse wheel is rolled upwards and uses a lambda function to call the # adjustCamDist function with the argument 1.1 # Keys array (down if 1, up if 0) self.keys = { "cam-left": 0, "cam-right": 0, "cam-up": 0, "cam-down": 0 } # Using Arrow Keys self.accept("arrow_left", self.setValue, [self.keys, "cam-left", 1]) self.accept("arrow_right", self.setValue, [self.keys, "cam-right", 1]) self.accept("arrow_up", self.setValue, [self.keys, "cam-up", 1]) self.accept("arrow_down", self.setValue, [self.keys, "cam-down", 1]) self.accept("arrow_left-up", self.setValue, [self.keys, "cam-left", 0]) self.accept("arrow_right-up", self.setValue, [self.keys, "cam-right", 0]) self.accept("arrow_up-up", self.setValue, [self.keys, "cam-up", 0]) self.accept("arrow_down-up", self.setValue, [self.keys, "cam-down", 0]) self.keyPanRate = 1.5 # pan rate for when user presses the arrow keys # set up plane for checking collision with for mouse-3d world self.plane = Plane(Vec3(0, 0, 1), Point3(0, 0, 0)) def destroy(self): self.ignoreAll() def setValue(self, array, key, value): array[key] = value def clamp(self, val, minVal, maxVal): val = min(max(val, minVal), maxVal) return val def zoomOut(self): if self.camDist <= self.maxZoomOut: self.adjustCamDist(1.1) return True def zoomIn(self): if self.camDist >= self.maxZoomIn: self.adjustCamDist(0.9) return True def turnCameraAroundPoint(self, deltaX, deltaY): # This function performs two important tasks. First, it is used for the camera orbital movement that occurs when the # right mouse button is held down. It is also called with 0s for the rotation inputs to reposition the camera during the # panning and zooming movements. # The delta inputs represent the change in rotation of the camera, which is also used to determine how far the camera # actually moves along the orbit. newCamHpr = Vec3() newCamPos = Vec3() # Creates temporary containers for the new rotation and position values of the camera. camHpr = self.showbase.camera.getHpr() # Creates a container for the current HPR of the camera and stores those values. newCamHpr.setX(camHpr.getX() + deltaX) newCamHpr.setY(self.clamp(camHpr.getY() - deltaY, -85, -10)) newCamHpr.setZ(camHpr.getZ()) # Adjusts the newCamHpr values according to the inputs given to the function. The Y value is clamped to prevent # the camera from orbiting beneath the ground plane and to prevent it from reaching the apex of the orbit, which # can cause a disturbing fast-rotation glitch. self.showbase.camera.setHpr(newCamHpr) # Sets the camera's rotation to the new values. angleradiansX = newCamHpr.getX() * (math.pi / 180.0) angleradiansY = newCamHpr.getY() * (math.pi / 180.0) # Generates values to be used in the math that will calculate the new position of the camera. newCamPos.setX(self.camDist * math.sin(angleradiansX) * math.cos(angleradiansY) + self.target.getX()) newCamPos.setY(-self.camDist * math.cos(angleradiansX) * math.cos(angleradiansY) + self.target.getY()) newCamPos.setZ(-self.camDist * math.sin(angleradiansY) + self.target.getZ()) self.showbase.camera.setPos(newCamPos.getX(), newCamPos.getY(), newCamPos.getZ()) # Performs the actual math to calculate the camera's new position and sets the camera to that position. #Unfortunately, this math is over my head, so I can't fully explain it. self.showbase.camera.lookAt(self.target.getX(), self.target.getY(), self.target.getZ()) # Points the camera at the target location. def getTarget(self): return self.target # returns the cur def setTarget(self, x, y, z): #This function is used to give the camera a new target position. x = self.clamp(x, self.panLimitsX.getX(), self.panLimitsX.getY()) self.target.setX(x) y = self.clamp(y, self.panLimitsY.getX(), self.panLimitsY.getY()) self.target.setY(y) self.target.setZ(z) # Stores the new target position values in the target variable. The x and y values are clamped to the pan limits. def setPanLimits(self, xMin, xMax, yMin, yMax): # This function is used to set the limitations of the panning movement. self.panLimitsX = (xMin, xMax) self.panLimitsY = (yMin, yMax) # Sets the inputs into the limit variables. def startOrbit(self): # This function puts the camera into orbiting mode. # Get windows properties props = WindowProperties() # Set Hide Cursor Property #props.setCursorHidden(True) # Set properties self.showbase.win.requestProperties(props) # hide cursor if self.showbase.mouseWatcherNode.hasMouse(): # We're going to use the mouse, so we have to make sure it's in the game window. If it's not and we try to use it, we'll get # a crash error. mpos = self.showbase.mouseWatcherNode.getMouse() self.storeX = mpos.getX() self.storeY = mpos.getY() # take current cursor values self.showbase.win.movePointer(0, self.showbase.win.getXSize() / 2, self.showbase.win.getYSize() / 2) # set to center self.mx = 0 self.my = 0 self.orbiting = True # Sets the orbiting variable to true to designate orbiting mode as on. def stopOrbit(self): # This function takes the camera out of orbiting mode. self.orbiting = False # Sets the orbiting variable to false to designate orbiting mode as off. self.showbase.win.movePointer(0, int((self.storeX + 1.0) / 2 * self.showbase.win.getXSize()), int(self.showbase.win.getYSize() - ((self.storeY + 1.0) / 2 * self.showbase.win.getYSize()))) # set to taken cursor values from startOrbit if self.showbase.mouseWatcherNode.hasMouse(): # We're going to use the mouse, so we have to make sure it's in the game window. If it's not and we try to use it, we'll get # a crash error. mpos = self.showbase.mouseWatcherNode.getMouse() self.mx = mpos.getX() self.my = mpos.getY() # Get windows properties props = WindowProperties() # Set Hide Cursor Property props.setCursorHidden(False) # Set properties self.showbase.win.requestProperties(props) # reshow cursor def adjustCamDist(self, distFactor): # This function increases or decreases the distance between the camera and the target position to simulate zooming in and out. # The distFactor input controls the amount of camera movement. # For example, inputing 0.9 will set the camera to 90% of it's previous distance. self.camDist = self.camDist * distFactor # Sets the new distance into self.camDist. self.turnCameraAroundPoint(0, 0) # Calls turnCameraAroundPoint with 0s for the rotation to reset the camera to the new position. def camMoveTask(self, dt): # This task is the camera handler's work house. It's set to be called every frame and will control both orbiting and panning the camera. if self.showbase.mouseWatcherNode.hasMouse(): # We're going to use the mouse, so we have to make sure it's in the game window. If it's not and we try to use it, we'll get # a crash error. mpos = self.showbase.mouseWatcherNode.getMouse() # Gets the mouse position if self.orbiting: # Checks to see if the camera is in orbiting mode. Orbiting mode overrides panning, because it would be problematic if, while # orbiting the camera the mouse came close to the screen edge and started panning the camera at the same time. self.turnCameraAroundPoint((self.mx - mpos.getX()) * self.orbitRate * dt, (self.my - mpos.getY()) * self.orbitRate * dt) else: # If the camera isn't in orbiting mode, we check to see if the mouse is close enough to the edge of the screen to start panning moveY = False moveX = False # these two booleans are used to denote if the camera needs to pan. X and Y refer to the mouse position that causes the # panning. X is the left or right edge of the screen, Y is the top or bottom. if self.my > (1 - self.panZoneSize): angleradiansX1 = self.showbase.camera.getH() * (math.pi / 180.0) panRate1 = (1 - self.my - self.panZoneSize) * (self.camDist / self.panRateDivisor) moveY = True if self.my < (-1 + self.panZoneSize): angleradiansX1 = self.showbase.camera.getH() * (math.pi / 180.0) + math.pi panRate1 = (1 + self.my - self.panZoneSize) * (self.camDist / self.panRateDivisor) moveY = True if self.mx > (1 - self.panZoneSize): angleradiansX2 = self.showbase.camera.getH() * (math.pi / 180.0) + math.pi * 0.5 panRate2 = (1 - self.mx - self.panZoneSize) * (self.camDist / self.panRateDivisor) moveX = True if self.mx < (-1 + self.panZoneSize): angleradiansX2 = self.showbase.camera.getH() * (math.pi / 180.0) - math.pi * 0.5 panRate2 = (1 + self.mx - self.panZoneSize) * (self.camDist / self.panRateDivisor) moveX = True # These four blocks check to see if the mouse cursor is close enough to the edge of the screen to start panning and then # perform part of the math necessary to find the new camera position. Once again, the math is a bit above my head, so # I can't properly explain it. These blocks also set the move booleans to true so that the next lines will move the camera. # If up or down keys are pressed if self.keys["cam-up"] ^ self.keys["cam-down"]: moveY = True panRate1 = self.keyPanRate # Update warlock position on z plane if self.keys["cam-up"]: angleradiansX1 = self.showbase.camera.getH() * (math.pi / 180.0) + math.pi if self.keys["cam-down"]: angleradiansX1 = self.showbase.camera.getH() * (math.pi / 180.0) # If left or right keys are pressed if self.keys["cam-left"] ^ self.keys["cam-right"]: moveX = True panRate2 = self.keyPanRate # Update warlock position on x plane if self.keys["cam-left"]: angleradiansX2 = self.showbase.camera.getH() * (math.pi / 180.0) + math.pi * 0.5 if self.keys["cam-right"]: angleradiansX2 = self.showbase.camera.getH() * (math.pi / 180.0) - math.pi * 0.5 if moveY: tempX = self.target.getX() + math.sin(angleradiansX1) * panRate1 * dt * 50 tempX = self.clamp(tempX, self.panLimitsX.getX(), self.panLimitsX.getY()) self.target.setX(tempX) tempY = self.target.getY() - math.cos(angleradiansX1) * panRate1 * dt * 50 tempY = self.clamp(tempY, self.panLimitsY.getX(), self.panLimitsY.getY()) self.target.setY(tempY) self.turnCameraAroundPoint(0, 0) if moveX: tempX = self.target.getX()-math.sin(angleradiansX2) * panRate2 * dt * 50 tempX = self.clamp(tempX, self.panLimitsX.getX(), self.panLimitsX.getY()) self.target.setX(tempX) tempY = self.target.getY() + math.cos(angleradiansX2) * panRate2 * dt * 50 tempY = self.clamp(tempY, self.panLimitsY.getX(), self.panLimitsY.getY()) self.target.setY(tempY) self.turnCameraAroundPoint(0, 0) # These two blocks finalize the math necessary to find the new camera position and apply the transformation to the # camera's TARGET. Then turnCameraAroundPoint is called with 0s for rotation, and it resets the camera position based # on the position of the target. The x and y values are clamped to the pan limits before they are applied. #print(self.target) self.mx = mpos.getX() self.my = mpos.getY() # The old mouse positions are updated to the current mouse position as the final step. # Finds 3d world point on the z = 0 plane for destination/target def getMouse3D(self): # make sure process has the mouse to not cause error if self.showbase.mouseWatcherNode.hasMouse(): # get screen coordinates of mouse mpos = self.showbase.mouseWatcherNode.getMouse() pos3d = Point3() nearPoint = Point3() farPoint = Point3() # find vector of cameras facing from mouse screen coordinates and get near and far points on frustrum self.showbase.camLens.extrude(mpos, nearPoint, farPoint) # check for intersection with z = 0 plane if self.plane.intersectsLine(pos3d, self.showbase.render.getRelativePoint(self.showbase.camera, nearPoint), self.showbase.render.getRelativePoint(self.showbase.camera, farPoint)): # return this position if exists return pos3d # or return (-1, -1, -1) return Vec3(-1, -1, -1)
class MoveCursor(object): _EDGES = 40 _zPos = 0 _movingUp = False _movingDown = False _color = Vec4(0.3, 0.3, 0.8, 1) _currentPos = Vec3(0, 0, 0) def __init__(self, parent, entity, foot=1): self.entity = entity self._moveRadCircleNP = NodePath("Movement Radius Node") self._moveLine = LineSegs() self._moveLineNP = NodePath("Movement Direction Line Node") self._moveZLine = LineSegs() self._moveZLineNP = NodePath("Movement Z Line Node") self._moveZFootNP = NodePath("Movement Z Foot Node") self._moveFootCircle = LineSegs() self._moveFootCircleNP = NodePath("Movement Foot Circle Node") self._attackRadCircle = LineSegs() self._attackRadCircleNP = NodePath("Attack Radius Node") self._np = NodePath("Movement Node") self.attackables = [] Event.Dispatcher().register(self, 'E_Key_ZUp', self.onZChange) Event.Dispatcher().register(self, 'E_Key_ZDown', self.onZChange) Event.Dispatcher().register(self, 'E_Key_ZUp-up', self.onZChange) Event.Dispatcher().register(self, 'E_Key_ZDown-up', self.onZChange) self.aaLevel = int(GameSettings().getSetting('ANTIALIAS')) self.parent = parent self.start = Vec3(0, 0, 0) self.moveRad = entity.moveRad self.footRad = foot self.attackRad = entity.attackRad self.plane = Plane(Vec3(0, 0, 1), Point3(0, 0, 0)) self.draw() self._np.reparentTo(self.parent) if self.aaLevel > 0: self._np.setAntialias(AntialiasAttrib.MLine, self.aaLevel) taskMgr.add(self.updateMovePos, 'Movement Indicator Update Task') def draw(self): # Setup curr mouse pos in 3d space posXY = self.getMouseXY() x = posXY.getX() y = posXY.getY() z = 0 # Draw movement radius moveRadLine = LineSegs() moveRadLine.setThickness(1) moveRadLine.setColor(self._color) moveRadLine.moveTo(self.moveRad, 0, 0) for i in range(self._EDGES + 1): newX = (self.moveRad * math.cos((2 * math.pi / self._EDGES) * i)) newY = (self.moveRad * math.sin((2 * math.pi / self._EDGES) * i)) moveRadLine.drawTo(newX, newY, 0) moveRadGeom = moveRadLine.create() self._moveRadCircleNP = NodePath(moveRadGeom) self._moveRadCircleNP.reparentTo(self._np) # Draw movement foot circle self._moveFootCircle.setThickness(1) self._moveFootCircle.setColor(self._color) self._moveFootCircle.moveTo(self.footRad, 0, 0) for i in range(self._EDGES): newX = (self.footRad * math.cos((2 * math.pi / self._EDGES) * i)) newY = (self.footRad * math.sin((2 * math.pi / self._EDGES) * i)) self._moveFootCircle.drawTo(newX, newY, 0) self._moveFootCircle.drawTo(self.footRad, 0, 0) moveFootCircleGeom = self._moveFootCircle.create() self._moveFootCircleNP = NodePath(moveFootCircleGeom) self._moveFootCircleNP.reparentTo(self._np) # Draw movement direction line self._moveLine.setThickness(1) self._moveLine.setColor(self._color) self._moveLine.moveTo(0, 0, 0) self._moveLine.drawTo(x, y, z) moveLine = self._moveLine.create() self._moveLineNP = NodePath(moveLine) self._moveLineNP.reparentTo(self._np) # Draw Z line self._moveZLine.setThickness(1) self._moveZLine.setColor(self._color) self._moveZLine.moveTo(self.start) self._moveZLine.drawTo(x, y, z) moveZLine = self._moveZLine.create() self._moveZLineNP = NodePath(moveZLine) self._moveZLineNP.reparentTo(self._np) # Draw Attack Radius self._attackRadCircle.setThickness(1) self._attackRadCircle.setColor(0.8, 0.0, 0.0, 1) self._attackRadCircle.moveTo(self.attackRad, 0, 0) for i in range(self._EDGES + 1): newX = (self.attackRad * math.cos((2 * math.pi / self._EDGES) * i)) newY = (self.attackRad * math.sin((2 * math.pi / self._EDGES) * i)) self._attackRadCircle.drawTo(newX, newY, 0) attackRadCircleGeom = self._attackRadCircle.create() self._attackRadCircleNP = NodePath(attackRadCircleGeom) self._attackRadCircleNP.reparentTo(self._np) def updateMovePos(self, Task): # endPos must be transformed in the the coord sys of the model m_pos = self.getMouseXY() if m_pos is not None: # Transform current mouse pos endPos = self.parent.getRelativePoint(render, m_pos) # Adjust Z coord if needed if self._movingUp: self._zPos += 0.1 elif self._movingDown: self._zPos -= 0.1 endPos.setZ(self._zPos) # Check if we're trying to move too far, if not update pos dist = math.sqrt(endPos.getX()**2 + endPos.getY()**2 + 2 * (endPos.getZ()**2)) if dist <= self.moveRad: self._moveLine.setVertex(1, endPos) self._moveFootCircleNP.setPos(endPos) self._moveZLine.setVertex( 0, Point3(endPos.getX(), endPos.getY(), 0)) self._moveZLine.setVertex(1, endPos) self._attackRadCircleNP.setPos(endPos) self._currentPos = render.getRelativePoint(self._np, endPos) # Check for attackable ships in range of current pos attackables = Entity.EntityManager().getEntitiesWithin( self._currentPos, self.attackRad) # Unhighlight ships no longer in range for e in self.attackables: if e not in attackables and isinstance( e, Entity.EntityShip): e.representation.unsetAttackable() # Highlight ships in range for e in attackables: if isinstance( e, Entity.EntityShip ) and e != self.entity and e.owner != self.entity.owner: e.representation.setAttackable() self.attackables = attackables return Task.cont def onZChange(self, event): if event.type == 'E_Key_ZUp': self._movingDown = False self._movingUp = True if event.type == 'E_Key_ZDown': self._movingUp = False self._movingDown = True if event.type == 'E_Key_ZUp-up': self._movingUp = False self._movingDown = False if event.type == 'E_Key_ZDown-up': self._movingUp = False self._movingDown = False def getMouseXY(self): # NOTE - this returns the mouse pos in the ships coord sys if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() pos3d = Point3() nearPoint = Point3() farPoint = Point3() base.camLens.extrude(mpos, nearPoint, farPoint) if self.plane.intersectsLine( pos3d, render.getRelativePoint(camera, nearPoint), render.getRelativePoint(camera, farPoint)): #print("Mouse ray intersects ground plane at " + str(pos3d)) return pos3d def getPosition(self): return self._currentPos def removeNode(self): taskMgr.remove('Movement Indicator Update Task') for e in self.attackables: if isinstance(e, Entity.EntityShip): e.representation.unsetAttackable() self._moveRadCircleNP.removeNode() self._moveLineNP.removeNode() self._moveZLineNP.removeNode() self._moveZFootNP.removeNode() self._moveFootCircleNP.removeNode() self._attackRadCircleNP.removeNode() self._np.removeNode() def __del__(self): # TODO - This isn't calling self.removeNode() correctly self._np.removeNode()
class MoveCursor(object): _EDGES = 40 _zPos = 0 _movingUp = False _movingDown = False _color = Vec4(0.3, 0.3, 0.8, 1) _currentPos = Vec3(0, 0, 0) def __init__(self, parent, entity, foot=1): self.entity = entity self._moveRadCircleNP = NodePath("Movement Radius Node") self._moveLine = LineSegs() self._moveLineNP = NodePath("Movement Direction Line Node") self._moveZLine = LineSegs() self._moveZLineNP = NodePath("Movement Z Line Node") self._moveZFootNP = NodePath("Movement Z Foot Node") self._moveFootCircle = LineSegs() self._moveFootCircleNP = NodePath("Movement Foot Circle Node") self._attackRadCircle = LineSegs() self._attackRadCircleNP= NodePath("Attack Radius Node") self._np = NodePath("Movement Node") self.attackables = [] Event.Dispatcher().register(self, 'E_Key_ZUp', self.onZChange) Event.Dispatcher().register(self, 'E_Key_ZDown', self.onZChange) Event.Dispatcher().register(self, 'E_Key_ZUp-up', self.onZChange) Event.Dispatcher().register(self, 'E_Key_ZDown-up', self.onZChange) self.aaLevel= int(GameSettings().getSetting('ANTIALIAS')) self.parent = parent self.start = Vec3(0, 0, 0) self.moveRad = entity.moveRad self.footRad = foot self.attackRad = entity.attackRad self.plane = Plane(Vec3(0, 0, 1), Point3(0, 0, 0)) self.draw() self._np.reparentTo(self.parent) if self.aaLevel > 0: self._np.setAntialias(AntialiasAttrib.MLine, self.aaLevel) taskMgr.add(self.updateMovePos, 'Movement Indicator Update Task') def draw(self): # Setup curr mouse pos in 3d space posXY = self.getMouseXY() x = posXY.getX() y = posXY.getY() z = 0 # Draw movement radius moveRadLine = LineSegs() moveRadLine.setThickness(1) moveRadLine.setColor(self._color) moveRadLine.moveTo(self.moveRad, 0, 0) for i in range(self._EDGES + 1): newX = (self.moveRad * math.cos((2*math.pi/self._EDGES)*i)) newY = (self.moveRad * math.sin((2*math.pi/self._EDGES)*i)) moveRadLine.drawTo(newX, newY, 0) moveRadGeom = moveRadLine.create() self._moveRadCircleNP = NodePath(moveRadGeom) self._moveRadCircleNP.reparentTo(self._np) # Draw movement foot circle self._moveFootCircle.setThickness(1) self._moveFootCircle.setColor(self._color) self._moveFootCircle.moveTo(self.footRad, 0, 0) for i in range(self._EDGES): newX = (self.footRad * math.cos((2*math.pi/self._EDGES)*i)) newY = (self.footRad * math.sin((2*math.pi/self._EDGES)*i)) self._moveFootCircle.drawTo(newX, newY, 0) self._moveFootCircle.drawTo(self.footRad, 0, 0) moveFootCircleGeom = self._moveFootCircle.create() self._moveFootCircleNP = NodePath(moveFootCircleGeom) self._moveFootCircleNP.reparentTo(self._np) # Draw movement direction line self._moveLine.setThickness(1) self._moveLine.setColor(self._color) self._moveLine.moveTo(0, 0, 0) self._moveLine.drawTo(x, y, z) moveLine = self._moveLine.create() self._moveLineNP = NodePath(moveLine) self._moveLineNP.reparentTo(self._np) # Draw Z line self._moveZLine.setThickness(1) self._moveZLine.setColor(self._color) self._moveZLine.moveTo(self.start) self._moveZLine.drawTo(x, y, z) moveZLine = self._moveZLine.create() self._moveZLineNP = NodePath(moveZLine) self._moveZLineNP.reparentTo(self._np) # Draw Attack Radius self._attackRadCircle.setThickness(1) self._attackRadCircle.setColor(0.8, 0.0, 0.0, 1) self._attackRadCircle.moveTo(self.attackRad, 0, 0) for i in range(self._EDGES + 1): newX = (self.attackRad * math.cos((2*math.pi/self._EDGES)*i)) newY = (self.attackRad * math.sin((2*math.pi/self._EDGES)*i)) self._attackRadCircle.drawTo(newX, newY, 0) attackRadCircleGeom = self._attackRadCircle.create() self._attackRadCircleNP = NodePath(attackRadCircleGeom) self._attackRadCircleNP.reparentTo(self._np) def updateMovePos(self, Task): # endPos must be transformed in the the coord sys of the model m_pos = self.getMouseXY() if m_pos is not None: # Transform current mouse pos endPos = self.parent.getRelativePoint(render, m_pos) # Adjust Z coord if needed if self._movingUp: self._zPos += 0.1 elif self._movingDown: self._zPos -= 0.1 endPos.setZ(self._zPos) # Check if we're trying to move too far, if not update pos dist = math.sqrt(endPos.getX()**2 + endPos.getY()**2 + 2*(endPos.getZ()**2)) if dist <= self.moveRad: self._moveLine.setVertex(1, endPos) self._moveFootCircleNP.setPos(endPos) self._moveZLine.setVertex(0, Point3(endPos.getX(), endPos.getY(), 0)) self._moveZLine.setVertex(1, endPos) self._attackRadCircleNP.setPos(endPos) self._currentPos = render.getRelativePoint(self._np, endPos) # Check for attackable ships in range of current pos attackables = Entity.EntityManager().getEntitiesWithin(self._currentPos, self.attackRad) # Unhighlight ships no longer in range for e in self.attackables: if e not in attackables and isinstance(e, Entity.EntityShip): e.representation.unsetAttackable() # Highlight ships in range for e in attackables: if isinstance(e, Entity.EntityShip) and e != self.entity and e.owner != self.entity.owner: e.representation.setAttackable() self.attackables = attackables return Task.cont def onZChange(self, event): if event.type == 'E_Key_ZUp': self._movingDown = False self._movingUp = True if event.type == 'E_Key_ZDown': self._movingUp = False self._movingDown = True if event.type == 'E_Key_ZUp-up': self._movingUp = False self._movingDown = False if event.type == 'E_Key_ZDown-up': self._movingUp = False self._movingDown = False def getMouseXY(self): # NOTE - this returns the mouse pos in the ships coord sys if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() pos3d = Point3() nearPoint = Point3() farPoint = Point3() base.camLens.extrude(mpos, nearPoint, farPoint) if self.plane.intersectsLine(pos3d, render.getRelativePoint(camera, nearPoint), render.getRelativePoint(camera, farPoint)): #print("Mouse ray intersects ground plane at " + str(pos3d)) return pos3d def getPosition(self): return self._currentPos def removeNode(self): taskMgr.remove('Movement Indicator Update Task') for e in self.attackables: if isinstance(e, Entity.EntityShip): e.representation.unsetAttackable() self._moveRadCircleNP.removeNode() self._moveLineNP.removeNode() self._moveZLineNP.removeNode() self._moveZFootNP.removeNode() self._moveFootCircleNP.removeNode() self._attackRadCircleNP.removeNode() self._np.removeNode() def __del__(self): # TODO - This isn't calling self.removeNode() correctly self._np.removeNode()