tower_defense_v2.py

Created by fixem

Created on May 31, 2025

13 KB

V2.0 de mon jeu de tower defense. MAJ majeure: mise en place d’un menu. /!\ Un bug -> si vous quittez la partie au milieu d’une vague vous ne pourrez pas en relancez une depuis le menu et vous devrez quitter le jeu et le relancer. (en gros vous ne pourrez lancer que une seule vague sinon).


from kandinsky import*
from ion import*
from time import*
from random import*
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,ja,bc,gr,no,bl,be=(255,0,0),(252,216,0),(0,255,255),(125,)*3,(0,)*3,(255,)*3,(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
def init(ready,wave,money):
 fill_rect(0,0,320,222,gr);Info(ready,wave,money);draw(path1)
 for t in tower:t.Draw()
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 Play(tm=0,Wave=[0,0,0,0]):
 global wave,Perso,alive,money,Tpos,tower,enemy,Epos
 money=10**1000 if tm else 50
 if tm:Perso=1
 else:Perso=0
 eff,efff,x,y,ready,PV,rd,can_place=0,0,40,42,0,100,0,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)
 while 1:
   if PV<=0:break
   fps=int(1/ts)
   Time=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)
         if co==get_pixel(0,42) or len(tower)>=30 or (x,y) in Tpos:can_place=0
         else:can_place=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))
       for t in tower:
         if t.ID==ID:
            eff=1;to=t;ra=t.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 t in tower:
           if t.ID>a:t.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 t in tower:t.Draw()
         else:draw_string("Money:"+str(money),260-10*len(str(money)),1,ro,gr)
         if co==get_pixel(0,42) or len(tower)>=30 or (x,y) in Tpos:can_place=0
         else:can_place=1
         cursor(x,y,bc) if can_place else cursor(x,y,ro)
   for t in tower:
     cible=t.Attack(Tpos,enemy,Epos,ready,wave)
   for e in enemy:
     e.Move(Epos)
     if Epos[e.ID][0]==322:
       PV-=e.HP;e.HP=0;alive-=1
     if e.Ef==1:fill_rect(int(Epos[e.ID][0]),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()-Time
def draw(o):
  for i in range(len(o)):fill_rect(o[i][0],o[i][1],o[i][2],o[i][3],o[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)
name=["Soldat","Sniper","Lance-flamme","Minigunner","Anihilateur"]
class Tower:
  def __init__(sf,n,lvl=0):sf.ID=len(tower);sf.n=n;sf.Lvl=lvl;sf.Stats=T[n][sf.Lvl];sf.T=0
  def Draw(sf):
    ct=[(255,255,0),(255,0,255),(0,255,255),(255,255,255),(0,0,0)]
    fill_rect(Tpos[sf.ID][0]+2,Tpos[sf.ID][1]+2,6,6,ct[sf.n])
  def Attack(sf,Tpos,enemy,Epos,ready,wave):
    global reset,alive,money;dM=0;cible=None;x,y=Tpos[sf.ID];x+=5;y+=5
    if reset:reset=False;sf.T=0
    for i in range(len(Epos)):
      ex,ey=Epos[i];ex+=3;ey+=3;dist=sqrt((x-ex)**2+(y-ey)**2)
      if dist<=sf.Stats[3]*10 and enemy[i].HP>0 and enemy[i].Tr>dM:dM=enemy[i].Tr;cible=i
    if cible!=None and sf.T>=sf.Stats[2]:
      sf.T=0
      try:
        enemy[cible].dam=5;enemy[cible].HP-=sf.Stats[1]
        if enemy[cible].HP<=0:
          ID=enemy[cible].ID;money+=enemy[cible].R;alive-=1;Info(ready,wave,money);fill_rect(int(Epos[cible][0]),int(Epos[cible][1]),6,6,be);enemy.remove(enemy[cible]);Epos.remove(Epos[ID])
          for e in enemy:
            if e.ID>ID:e.ID-=1
      except TypeError:pass
    else:sf.T+=1
# Health,Speed,Reward
# lent,boss,normal,rapide
E=[(10,.5,3),(50,.5,15),(5,1,1),(3,2,2)]
turn=[(92,2),(172,0),(252,2),(322,3),(462,1),(592,3),(722,2),(832,3)]
class Enemy:
  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*(sf.Lvl+1))
    sf.Tr=-10*(sf.ID+1)
    sf.D=3
    sf.Ef=0
  def Move(sf,Epos):
    if sf.dam>0:ce=[(255,0,0),(255,0,0),(255,0,0),(255,0,0)];sf.dam-=1
    else:ce=[(0,150,0),(50,)*3,(100,200,100),(0,150,255)]
    v=sf.V;de=[-v,-v,v,v]
    for i in turn:
      if sf.Tr==i[0]:sf.D=i[1]
    fill_rect(int(Epos[sf.ID][0]),int(Epos[sf.ID][1]),6,6,be)
    if sf.D in [1,2]:Epos[sf.ID]=(Epos[sf.ID][0],Epos[sf.ID][1]+de[sf.D])
    elif sf.D in [0,3]:Epos[sf.ID]=(Epos[sf.ID][0]+de[sf.D],Epos[sf.ID][1])
    fill_rect(int(Epos[sf.ID][0]),int(Epos[sf.ID][1]),6,6,ce[sf.n]);sf.Tr+=v
enemy=[];alive=0
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*int(wave//20)
    lVl=int(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=[int(wav//4+lVl//3),int(wav//10+1*wave//50),int(wav//2+lVl/3),int(wav//2-1+lVl/3)]
  j1,j=0,-1
  for i in Wave:
    j+=1
    for f in range(i):
      alive+=1;j1+=1
      Epos.append((0-10*j1,44))
      enemy.append(Enemy(j,lVl))
def Info2(x,y):
  if (x,y) in Tpos:
    ID=Tpos.index((x,y));stats=None
    for t in tower:
      if t.ID==ID:stats=t.Stats;break
    if stats==None:return bc
    d1=stats[1];d2=T[t.n][t.Lvl+1][1]
    if d1>10000:
      d1,d2="",""
    ra=stats[3]
    draw_string("Damage: "+str(d1)+"-->"+str(d2),0,140)
    draw_string(str(name[t.n])+"/Level: "+str(t.Lvl),0,100);draw_string("Upgrade: "+str(stats[0]),0,120);draw_string("Reload delay: "+str(stats[2])+"-->"+str(T[t.n][t.Lvl+1][2]),0,160);draw_string("Range: "+str(ra)+"-->"+str(T[t.n][t.Lvl+1][3]),0,180);return ro
  else:return bc
def cercle(x0,y0,r,c1,e):
  for i in range(e):
    xd=x0-int((r-i)/sqrt(2))
    xf=x0+int((r-i)/sqrt(2))
    for x in range(xd,xf+1):
      x1=x
      y1=y0+int(sqrt((r-i)**2-(x-x0)**2))
      set_pixel(x,y1,c1)
      for j in range(3):
        x2=x0+y1-y0
        y2=y0+x0-x1
        set_pixel(x2,y2,c1)
        x1,y1=x2,y2
def Help():
  tp=1
  col=[0,255,255]
  fill_rect(0,0,320,222,gr)
  while 1-keydown(4):
    if col[2]>150 and tp==1:col[2]-=1
    else:
      col[2]+=1
      if col[2]<255:tp=0
      else:tp=1
    draw_string("Tower Defense",95,91,bl,gr)
    draw_string("Par FIXEM",2,2,bl,gr)
    draw_string("Version: 2.0",200,2,bl,gr)
    draw_string("[OK] pour continuer",65,202,col,gr)
  while keydown(4):pass
  fill_rect(0,0,320,222,gr)
  while 1-keydown(4):
    if col[2]>150 and tp==1:col[2]-=1
    else:
      col[2]+=1
      if col[2]<255:tp=0
      else:tp=1
    draw_string("[shift] -> Voir les FPS\n[alpha] -> Voir les stats sur\n\t\t   une tour\n[cut] -> Voir les PV\n[OK] -> Ameliorer les tours\nFleches -> Deplacer le curseur\n[EXE] -> Lancer une vague\n1-5 -> Placer des tours",0,2,bl,gr)
    draw_string("[OK] pour continuer",65,202,col,gr)
  while keydown(4):pass
  fill_rect(0,0,320,222,gr)
  while 1-keydown(4):
    if col[2]>150 and tp==1:col[2]-=1
    else:
      col[2]+=1
      if col[2]<255:tp=0
      else:tp=1
    draw_string("Tour 1 -> Soldat (25)\nTour 2 -> Sniper (75)\nTour 3 -> Lance-Flamme (125)\nTour 4 -> Minigunner (450)\nTour 5 -> Anihilateur(2500)",0,2,bl,gr)
    draw_string("[OK] pour continuer",65,202,col,gr)
  while keydown(4):pass
def Train():
  global tower
  fill_rect(0,0,320,222,gr)
  Wave=Choose()
  Play(1,Wave)
# Cost,Damage,Delay,Range
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]]
def Choose():
  global lVl,Perso
  Wave=[0,0,0,0]
  Perso=1
  pos=0
  ne=["Lent: ","Boss: ","Normal: ","Rapide: ","Niveau: "]
  while 1-keydown(4):
    for i in range(5):
      draw_string(ne[i],25,2+30*i,gr1,gr)
      try:
        tx=str(Wave[i])
      except IndexError:
        tx=str(lVl)
      draw_string(tx,25+10*len(ne[i]),2+30*i,gr1,gr)
    if keydown(1) and pos!=0:
      draw_string("  ",2,2+30*pos,gr1,gr);pos-=1
      while keydown(1):pass
    elif keydown(2) and pos!=3:
      draw_string("  ",2,2+30*pos,gr1,gr);pos+=1
      while keydown(2):pass
    if keydown(0) and Wave[pos]!=0:
      Wave[pos]-=1
      while keydown(0):pass
    if keydown(3) and sum(Wave)!=40:
      Wave[pos]+=1
      while keydown(3):pass
    if keydown(46) and lVl!=0:
      lVl-=1
      while keydown(46):pass
    elif keydown(45):
      lVl+=1
      while 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():
  global tower
  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
  for i in range(5):
    tower.append(Tower(i))
  while 1:
    draw_string(name[pos],2,2,gr1,gr)
    if keydown(0):
      pos=pos-1 if pos!=0 else 4
      while keydown(0):pass
      fill_rect(0,0,320,222,gr)
    elif keydown(3):
      pos=pos+1 if pos!=4 else 0
      while keydown(3):pass
      fill_rect(0,0,320,222,gr)
    if keydown(1) and t.Lvl!=7:
      t.Lvl+=1
      while keydown(1):pass
    elif keydown(2) and t.Lvl!=0:
      t.Lvl-=1
      while keydown(2):pass
    t=tower[pos]
    t.Stats=T[t.n][t.Lvl]
    stats=t.Stats
    if stats[1]>100000:stats=(stats[0],"",stats[2],stats[3])
    draw_string("Niveau: "+str(t.Lvl)+" "*9,12+10*len(name[pos]),2,gr2,gr)
    draw_string("Prix vers niveau "+str(t.Lvl+1)+":",2,42,gr2,gr);draw_string(str(stats[0])+" "*9,190+10*len(str(t.Lvl)),42,gr1,gr)
    draw_string("Prix de base: ",2,62,gr2,gr);draw_string(str(pdb[pos])+" "*9,142,62,gr1,gr)
    draw_string("Attaque: ",2,82,gr2,gr);draw_string(str(stats[1])+" "*9,92,82,gr1,gr)
    draw_string("Delai: ",2,102,gr2,gr);draw_string(str(stats[2])+" "*9,72,102,gr1,gr)
    draw_string("Portee: ",2,122,gr2,gr);draw_string(str(stats[3])+" "*9,82,122,gr1,gr)
    draw_string("Symbole:",2,152,gr2,gr);fill_rect(92,147,30,30,ct[pos])
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.0",278,22,gr2,gr)
    draw_string("Par FIXEM",2,200,gr2,gr)
  info()
  while 1:
    if keydown(1):
      pos=pos-1 if pos!=0 else len(xy)-1
      while keydown(1):pass
    elif keydown(2):
      pos=pos+1 if pos!=len(xy)-1 else 0
      while keydown(2):pass
    for i in range(len(txt)):
      c1=gr1 if pos==i else gr2
      draw_string(txt[i],xy[i][0],xy[i][1],c1,gr) 
    if keydown(4):
      try:
        while keydown(4):pass
        wave=0
        action[pos]()
        info()
      except KeyboardInterrupt or NameError:sleep(0.4);info();tower.clear();Tpos.clear();Epos.clear(),enemy.clear();Perso=0;Wave=[0,0,0,0]
try:
  Menu()
except KeyboardInterrupt:pass

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.