Tower Defense V-2.1 Le code a été optimisé pour s’exécuter le plus vite possible et pour prendre le moins de place possible sur votre calcultrice.
Bon jeu !!
from kandinsky import fill_rect,draw_string,get_pixel,set_pixel from ion import keydown from time import monotonic from random import randint from math import sqrt pdb=[25,75,150,450,2500] lVl=0 Wave=[0,0,0,0] Perso=0 gr1=(75,)*3;gr2=(175,)*3 ro=(255,0,0);ja=(252,216,0);bc=(0,255,255);gr=(125,)*3;no=(0,)*3;bl=(255,)*3;be=(255,204,115) enemy=[];tower=[];Epos=[];Tpos=[];wave=0;money=50 path1=[(0,42,100,10,be),(90,52,10,80,be),(10,122,80,10,be),(10,132,10,60,be),(10,192,140,10,be),(150,62,10,140,be),(160,62,120,10,be),(280,62,10,120,be),(290,172,30,10,be)] reset=True alive=0 def draw(o): for i in o:fill_rect(i[0],i[1],i[2],i[3],i[4]) def Info(ready,wave,money): mo="∞" if money>10**999 else money if ready:draw_string("Wave:"+str(wave)+"-In progress",0,1,no,gr) else:draw_string("Wave:"+str(wave)+" "*12,0,1,no,gr) draw_string("Money:"+str(mo),260-10*len(str(mo)),1,ja,gr);fill_rect(0,21,320,1,bl) def cursor(x,y,c): c2=get_pixel(x+2,y) fill_rect(x,y,10,1,c);fill_rect(x,y,1,10,c);fill_rect(x+9,y,1,10,c);fill_rect(x,y+9,10,1,c) fill_rect(x+2,y,6,1,c2);fill_rect(x,y+2,1,6,c2);fill_rect(x+9,y+2,1,6,c2);fill_rect(x+2,y+9,6,1,c2) def init(ready,wave,money): fill_rect(0,0,320,222,gr);Info(ready,wave,money);draw(path1) for t in tower:t.Draw() E=[(10,.5,3),(50,.5,15),(5,1,1),(3,2,2)] turn={(92,172,252,322,462,592,722,832)[i]:(2,0,2,3,1,3,2,3)[i] for i in range(8)} # turn as dict for O(1) lookup turn_keys=set(turn) class Enemy: __slots__=('dam','n','ID','Lvl','HP','V','R','Tr','D','Ef') def __init__(sf,n,lvl): sf.dam=0;sf.n=n;sf.ID=len(enemy);sf.Lvl=lvl sf.HP=int(E[n][0]*(1+2.5*lvl));sf.V=E[n][1];sf.R=int(E[n][2]*2*(lvl+1)) sf.Tr=-10*(sf.ID+1);sf.D=3;sf.Ef=0 def Move(sf,Epos): ce=[(0,150,0),(50,)*3,(100,200,100),(0,150,255)] if sf.dam>0:c=ro;sf.dam-=1 else:c=ce[sf.n] v=sf.V if sf.Tr in turn_keys:sf.D=turn[sf.Tr] ex,ey=Epos[sf.ID] fill_rect(int(ex),int(ey),6,6,be) d=sf.D if d==0:ex-=v elif d==1:ey-=v elif d==2:ey+=v else:ex+=v Epos[sf.ID]=(ex,ey) fill_rect(int(ex),int(ey),6,6,c);sf.Tr+=v T=[ [(50,2,25,2),(100,3,25,2),(200,3,17,2.25),(400,3,17,2.5),(800,5,17,2.5),(1600,10,15,2.5),(3200,12,12,2.5),("--",15,12,3),("--",)*4], [(150,10,150,3),(300,20,150,3),(600,50,150,4),(1200,100,150,4),(2400,100,75,5),(4800,150,75,5),(9600,150,65,5),("--",200,65,5),("--",)*4], [(250,1,5,1.5),(500,2,5,1.5),(1000,2,3,1.5),(2000,3,3,1.5),(4000,3,3,1.75),(8000,4,3,2),(16000,5,3,2),("--",5,2,2.25),("--",)*4], [(900,2,10,1.5),(1800,3,10,1.5),(3600,3,7,2.5),(7200,4,7,2.5),(14400,5,7,3),(28800,6,7,3),(47600,6,7,3.5),("--",6,5,3.5),("--",)*4], [(5000,10**100,1000,5),(10000,10**100,950,5.1),(20000,10**100,900,5.2),(40000,10**100,800,5.5),(80000,10**100,700,5.75),(160000,10**100,600,6),(320000,10**100,500,6),("--",10**100,500,10),("--",)*4]] name=["Soldat","Sniper","Lance-flamme","Minigunner","Anihilateur"] class Tower: __slots__=('ID','n','Lvl','Stats','T') def __init__(sf,n,lvl=0):sf.ID=len(tower);sf.n=n;sf.Lvl=lvl;sf.Stats=T[n][lvl];sf.T=0 def Draw(sf): ct=[(255,255,0),(255,0,255),(0,255,255),(255,255,255),(0,0,0)] x,y=Tpos[sf.ID];fill_rect(x+2,y+2,6,6,ct[sf.n]) def Attack(sf,Tpos,enemy,Epos,ready,wave): global reset,alive,money if reset:reset=False;sf.T=0 st=sf.Stats;dM=0;cible=None x,y=Tpos[sf.ID];cx=x+5;cy=y+5 r2=(st[3]*10)**2 for i in range(len(Epos)): if enemy[i].HP>0 and enemy[i].Tr>dM: ex,ey=Epos[i];dx=cx-ex-3;dy=cy-ey-3 if dx*dx+dy*dy<=r2:dM=enemy[i].Tr;cible=i if cible is not None and sf.T>=st[2]: sf.T=0 e=enemy[cible] e.dam=5;e.HP-=st[1] if e.HP<=0: ID=e.ID;money+=e.R;alive-=1;Info(ready,wave,money) ex,ey=Epos[ID];fill_rect(int(ex),int(ey),6,6,be) del enemy[cible];del Epos[ID] for e2 in enemy: if e2.ID>ID:e2.ID-=1 else:sf.T+=1 def Remplir(Wave=[0,0,0,0]): global alive,reset,Perso,Epos,enemy,lVl,wave reset=True if Perso:Perso=0 else: wav=wave-20*(wave//20);lVl=wave//20 if wav==0:Wave=[0,0,2,0] elif wav==1:Wave=[0,0,0,2] elif wav==2:Wave=[2,0,0,0] else:Wave=[wav//4+lVl//3,wav//10+wave//50,wav//2+lVl//3,wav//2-1+lVl//3] j1=0 for j,i in enumerate(Wave): for _ in range(i): alive+=1;j1+=1 Epos.append((-10*j1,44)) enemy.append(Enemy(j,lVl)) def cercle(x0,y0,r,c1,e): r2=r*r for i in range(e): ri=r-i;ri2=ri*ri xd=x0-int(ri/1.4142) xf=x0+int(ri/1.4142)+1 for x in range(xd,xf): dx=x-x0;dy=int(sqrt(ri2-dx*dx)) x1=x;y1=y0+dy for _ in range(4): set_pixel(x1,y1,c1) x1,y1=x0+y1-y0,y0+x0-x1 def Info2(x,y): if (x,y) not in Tpos:return bc ID=Tpos.index((x,y));t=None for t2 in tower: if t2.ID==ID:t=t2;break if t is None:return bc st=t.Stats;d1=st[1];d2=T[t.n][t.Lvl+1][1] if d1>10000:d1=d2="∞" draw_string(name[t.n]+"/Level: "+str(t.Lvl),0,100) draw_string("Upgrade: "+str(st[0]),0,120) draw_string("Damage: "+str(d1)+"-->"+str(d2),0,140) draw_string("Reload delay: "+str(st[2])+"-->"+str(T[t.n][t.Lvl+1][2]),0,160) draw_string("Range: "+str(st[3])+"-->"+str(T[t.n][t.Lvl+1][3]),0,180) return ro def Play(tm=0,Wave=[0,0,0,0]): global wave,Perso,alive,money,Tpos,tower,enemy,Epos money=10**1000 if tm else 50 Perso=1 if tm else 0 eff=efff=rd=0;x=40;y=42;ready=0;PV=100;can_place=0 pt={42:0,43:1,44:2,36:3,37:4};prt={42:25,43:75,44:125,36:450,37:2500} ts=1;de=[-10,-10,10,10] wave=0;tower=[];Epos=[];Tpos=[];enemy=[] init(ready,wave,money) co=get_pixel(x,y);cursor(x,y,ro) path_color=get_pixel(0,42) while PV>0: fps=int(1/ts) T0=monotonic() if keydown(14): while keydown(14):draw_string(str(PV)+" PV",290-10*len(str(PV)),202,bl,gr) elif keydown(12): while keydown(12):draw_string(str(fps)+" fps",280-10*len(str(fps)),202,bl,gr) elif keydown(13) and (x,y) in Tpos: while keydown(13):col=Info2(x,y) init(ready,wave,money);cursor(x,y,col) rd+=1 if rd==5: rd=0 for k in (0,1,2,3,52): if keydown(k): if k==52 and not ready: ready=1;Info(ready,wave,money) if Perso:Remplir(Wave) else:Remplir() cursor(x,y,co) if k in (0,3):x+=de[k] elif k in (1,2):y+=de[k] if x>300:x=0 elif x<0:x=310 if y>202:y=22 elif y<22:y=212 co=get_pixel(x,y) can_place=0 if co==path_color or len(tower)>=30 or (x,y) in Tpos else 1 cursor(x,y,bc) if can_place else cursor(x,y,ro) efff=1 while keydown(k):pass if (x,y) in Tpos: ID=Tpos.index((x,y));to=None for t2 in tower: if t2.ID==ID:to=t2;break if to: eff=1;ra=to.Stats[3];cercle(x+5,y+5,ra*10,ro,1) if keydown(4) and to.Lvl<7: if money>=to.Stats[0]:to.Lvl+=1;money-=to.Stats[0];to.Stats=T[to.n][to.Lvl];Info(ready,wave,money) while keydown(4):pass elif keydown(17): a=to.ID;money+=int(3*((to.Lvl+1)*(to.n+1))**2.5) tower.remove(to);Tpos.remove((x,y)) for t2 in tower: if t2.ID>a:t2.ID-=1 fill_rect(x,y,10,10,gr) elif eff:init(ready,wave,money);eff=0;cursor(x,y,bc) if can_place else cursor(x,y,ro) if efff and eff:init(ready,wave,money);efff=0;cursor(x,y,ro) if keydown(48):input();init(ready,wave,money) if can_place: for k in (42,43,44,36,37): if keydown(k): if money>=prt[k]: tower.append(Tower(pt[k]));Tpos.append((x,y));money-=prt[k] for t2 in tower:t2.Draw() else:draw_string("Money:"+str(money),260-10*len(str(money)),1,ro,gr) can_place=0 if co==path_color or len(tower)>=30 or (x,y) in Tpos else 1 cursor(x,y,bc) if can_place else cursor(x,y,ro) for t2 in tower:t2.Attack(Tpos,enemy,Epos,ready,wave) for e in enemy[:]: e.Move(Epos) ex=Epos[e.ID][0] if ex==322: PV-=e.HP;e.HP=0;alive-=1 if e.Ef:fill_rect(int(ex),int(Epos[e.ID][1]),6,6,be);e.Ef=0 if alive==0 and ready: if tm: tower.clear();Tpos.clear();Epos.clear();enemy.clear() while not keydown(52):pass break else:wave+=1;money+=5*wave;ready=0;Epos.clear();enemy.clear();Info(ready,wave,money) ts=monotonic()-T0 def Help(): tp=1;col=[0,255,255] fill_rect(0,0,320,222,gr) pages=[ "Tower Defense\nPar FIXEM Version: 2.0", "[shift]->FPS [alpha]->Stats tour\n[cut]->PV [OK]->Ameliorer\nFleches->Curseur [EXE]->Vague\n1-5->Placer tours [del]->Vendre", "1->Soldat(25) 2->Sniper(75)\n3->Lance-Flamme(125)\n4->Minigunner(450)\n5->Anihilateur(2500)" ] for pg in pages: fill_rect(0,0,320,222,gr) while not keydown(4): if col[2]>150 and tp==1:col[2]-=1 else: col[2]+=1 tp=0 if col[2]<255 else 1 draw_string(pg,2,60,bl,gr) draw_string("[OK] pour continuer",65,202,col,gr) while keydown(4):pass fill_rect(0,0,320,222,gr) def Train(): Wave=Choose();Play(1,Wave) def Choose(): global lVl,Perso Wave=[0,0,0,0];Perso=1;pos=0 ne=["Lent: ","Boss: ","Normal: ","Rapide: ","Niveau: "] while not keydown(4): for i in range(5): draw_string(ne[i],25,2+30*i,gr1,gr) tx=str(Wave[i]) if i<4 else str(lVl) draw_string(tx,25+10*len(ne[i]),2+30*i,gr1,gr) if keydown(1) and pos:draw_string(" ",2,2+30*pos,gr1,gr);pos-=1; elif keydown(2) and pos!=3:draw_string(" ",2,2+30*pos,gr1,gr);pos+=1 while keydown(1) or keydown(2):pass if keydown(0) and Wave[pos]:Wave[pos]-=1 elif keydown(3) and sum(Wave)<40:Wave[pos]+=1 while keydown(0) or keydown(3):pass if keydown(46) and lVl:lVl-=1 elif keydown(45):lVl+=1 while keydown(46) or keydown(45):pass if keydown(52):Wave=[0,0,0,0];lVl=0 draw_string("->",2,2+30*pos,gr1,gr) return Wave def Inventory(): ct=[(255,255,0),(255,0,255),(0,255,255),(255,255,255),(0,0,0)] fill_rect(0,0,320,222,gr);pos=0 inv=[Tower(i) for i in range(5)] while True: t=inv[pos];t.Stats=T[t.n][t.Lvl] st=t.Stats s1=st[1] if st[1]<=100000 else "∞" draw_string(name[pos],2,2,gr1,gr) draw_string("Niveau: "+str(t.Lvl)+" "*9,12+10*len(name[pos]),2,gr2,gr) draw_string("Prix->niv "+str(t.Lvl+1)+": "+str(st[0])+" "*6,2,42,gr2,gr) draw_string("Prix base: "+str(pdb[pos])+" "*6,2,62,gr2,gr) draw_string("Attaque: "+str(s1)+" "*6,2,82,gr2,gr) draw_string("Delai: "+str(st[2])+" "*6,2,102,gr2,gr) draw_string("Portee: "+str(st[3])+" "*6,2,122,gr2,gr) draw_string("Symbole:",2,152,gr2,gr);fill_rect(92,147,30,30,ct[pos]) if keydown(0): pos=(pos-1)%5 while keydown(0):pass;fill_rect(0,0,320,222,gr) elif keydown(3): pos=(pos+1)%5 while keydown(3):pass;fill_rect(0,0,320,222,gr) if keydown(1) and t.Lvl<7:t.Lvl+=1 elif keydown(2) and t.Lvl:t.Lvl-=1 while keydown(1) or keydown(2):pass if keydown(4):break def Menu(): global Perso,Wave action=[Play,Train,Inventory,Help] txt=["Play","Training","Towers","Help"] xy=[(35,22),(15,57),(25,77),(35,97)] pos=0 def info(): fill_rect(0,0,320,222,gr);fill_rect(5,7,100,120,gr1);fill_rect(10,12,90,110,gr) draw_string("TOWER DEFENSE",188,2,gr2,gr);draw_string("V2.1",278,22,gr2,gr);draw_string("Par FIXEM",2,200,gr2,gr) info() while True: if keydown(1): pos=(pos-1)%len(xy) while keydown(1):pass elif keydown(2): pos=(pos+1)%len(xy) while keydown(2):pass for i in range(len(txt)): draw_string(txt[i],xy[i][0],xy[i][1],gr1 if pos==i else gr2,gr) if keydown(4): while keydown(4):pass wave=0 try:action[pos]() except KeyboardInterrupt: from time import sleep;sleep(0.4) tower.clear();Tpos.clear();Epos.clear();enemy.clear();Perso=0;Wave=[0,0,0,0] info() try:Menu() except KeyboardInterrupt:pass