Ukázka, jak se pomocí Tkinteru dá poměrně rychle naprogramovat primitivní had.
Vytvoření plochy
Jak jsem již předeslal, využijeme udělátko Canvas, které si rozdělíme na čtverce o velikost 30 × 30. O velikosti hrací plochy budou rozhodovat dvě proměnné:
# -*- coding: cp1250 -*-
from Tkinter import*
import random
class Had:
def __init__(self):
self.sirka=15
self.vyska=10
self.okno=Tk()
if __name__ == "__main__":
Had()
mainloop()
Takže plátno vykreslíme takto:
self.platno=Canvas(width=self.sirka*30,height=self.vyska*30)
self.platno.pack()
Okraje budou černé a pozadí bílé. Takže nyní musíme naprogramovat funkci, která vykreslí jednotlivé čtverce na plochu:
def vytvor_objekt(self,x,y,barva):
x=x*30
y=y*30
self.platno.create_rectangle(x,y,x+30,y+30,fill=barva)
Důvod, proč se x a y násobí 30, je, doufám, jasný z následujícího nákresu:
Schází proměnit slova ve skutek a plochu vykreslit. K tomu použijeme dva cykly for:
for y in range(self.vyska):
for x in range(self.sirka):
if y in [0,self.vyska-1] or x in [0,self.sirka-1]:#Jestliže se jedná o krajní bod, ať je černý.
self.vytvor_objekt(x,y,"black")
else:
self.vytvor_objekt(x,y,"white")
Nyní, když máme hotovou plochu, můžeme se vrhnout na vykreslení hada.
Vykreslení hada
Směr
Had se bude ovládat směrovými šipkami. Při každém zmáčknutí šipky se musí proměnná smer změnit. Následující kód zavolá funkci stisk, kdykoliv uživatel zmáčkne jakoukoliv klávesu:
self.okno.bind('<Key>',self.stisk)
Funkce stisk bude kromě povinného parametru self přijímat ještě jeden, pojmenujme si ho třeba akce. Pomocí tohoto parametru se pak dá zjistit, jaká klávesa byla stisknuta.
def stisk(self, akce):
if akce.keysym in ["Left","Right","Down","Up"]:
self.smer=akce.keysym
Toto ale není úplně správně, protože pokud had směřuje doleva a uživatel zmáčkne klávesu doprava, tak se had „otočí“ na místě, což není povoleno. Proto se musí kód upravit:
def stisk(self, akce):
if akce.keysym == "Right" and self.smer != "Left":self.smer="Right"
elif akce.keysym == "Left" and self.smer != "Right":self.smer="Left"
elif akce.keysym == "Up" and self.smer != "Down":self.smer="Up"
elif akce.keysym == "Down" and self.smer != "Up":self.smer="Down"
Posun
Na začátku každé hry bude mít had velikost 5 políček, bude situován v levém dolním rohu a počáteční směr bude doprava:
self.smer = "Right"
self.had=[[1,self.vyska-2],[2,self.vyska-2],[3,self.vyska-2],[4,self.vyska-2],[5,self.vyska-2]]
V seznamu self.had jsou vždy všechny souřadnice, na kterých se hadovo tělo nachází. Had se za určitý časový interval musí posunout v náležitém směru. Proto si na začátku musíme definovat proměnnou rychlost. Jako hodnoty bych dosazoval čísla mezi 100-1 000.
def __init__(self):
self.rychlost=500
#Vykreslení plochy
for prvek in self.had:#Vykresluju hada
self.vytvor_objekt(prvek[0],prvek[1],"green")
self.okno.after(self.rychlost,self.posun)#Za určitou dobu zavolej funkci self.posun.
def posun(self):
#Posun hada
self.okno.after(self.rychlost,self.posun)
Takže kostru funkce posun již máme. V té funkci by se měl had na konci o jedno políčko zkrátit a vepředu o jedno nové prodloužit. Zkrátit hada je lehké:
self.vytvor_objekt(self.had[0][0],self.had[0][1],"white")#Poslední políčko musí být bílé.
self.had=self.had[1:]#Zkrať seznam políček s hadem.
Zvětšit hada je sice trochu složitější, nicméně to není nepřekonatelná překážka. Nejprve si musíte definovat funkci zvetsi_hada. Tam se do seznamu self.had přidá patřičné políčko dle směru.
def zvetsi_hada(self):
if self.smer == "Right":
#Hlava hada se nachází například na souřadnicích [3,3]. Pokud má had zahnout doprava, hlava se přesune na souřadnice [4,3].
self.had.append([self.had[-1][0]+1,self.had[-1][1]])
elif self.smer == "Left":
self.had.append([self.had[-1][0]-1,self.had[-1][1]])
elif self.smer == "Up":
self.had.append([self.had[-1][0],self.had[-1][1]-1])
elif self.smer == "Down":
self.had.append([self.had[-1][0],self.had[-1][1]+1])
Tím pádem můžeme skoro dokončit funkci posun:
def posun(self):
self.vytvor_objekt(self.had[0][0],self.had[0][1],"white")
self.had=self.had[1:]
self.zvetsi_hada()
self.vytvor_objekt(self.had[-1][0],self.had[-1][1],"green")#Vykresli políčko, které bylo vygenerováno ve funkci zvetsi_hada.
self.okno.after(self.rychlost,self.posun)
Nyní by se had již měl pohybovat. Schází dodělat jídlo a srážky se zdí.
Jídlo
Aby náš had rostl, musí sníst nějaké jídlo. Na začátku bude jídlo na pozici [5,5]. Následující kód přidejte do funkce __init__.
self.jidlo=[5,5]
self.vytvor_objekt(self.jidlo[0],self.jidlo[1],"red")
Had přes jídlo přejede, ale nic se nestane. Proto ho musíme naučit rozpoznat, kdy něco snědl. Nejprve si připravíme funkci pridej_jidlo. Ta vygeneruje na náhodné místo na ploše jídlo.
def pridej_jidlo(self):
while 1:
x=random.randint(1,self.sirka-2)
y=random.randint(1,self.vyska-2)
if [x,y] not in self.had:break
self.jidlo=[x,y]
self.vytvor_objekt(self.jidlo[0],self.jidlo[1],"red")
A následující kód přidejte do funkce posun před opětovné volání funkce posun.
if self.had[-1] == self.jidlo:
self.pridej_jidlo()
self.zvetsi_hada()
self.vytvor_objekt(self.had[-1][0],self.had[-1][1],"green")
Ve funkci posun kontrolujeme, zda se hlava hada náhodou nenachází na stejných souřadnicích jako jídlo. Pokud tomu tak je, velikost hada se musí opět prodloužit nám už známou funkcí zvetsi_hada. Výborně, teď už had umí sníst jídlo, ale na ploše už žádné není. Proto jsme si definovali funkci pridej_jidlo. Ta na plochu vykreslí pomocí modulu random nové políčko s jídlem. Schází dodělat ukončení hry, pokud had narazí do zdi, nebo do sebe sama.
Náraz do zdi
Zbýva dokončit poslední čast programu. Pokud had narazil, měla by se zavolat funkce konec. Následující kód přidejte do funkce zvetsi_hada:
hlava=self.had[-1]
#Když je x nebo y rovno nule, když x je rovno šířce-1, nebo když y je rovno výšce-1, had narazil.
if hlava[0] == 0 or hlava[0] == self.sirka-1 or hlava[1] == 0 or hlava[1] == self.vyska-1:
self.konec()
#A nyní přijde kontrola, zda had nenarazil do sebe:
novy_seznam=[]
for prvek in self.had:
if prvek not in novy_seznam:
novy_seznam.append(prvek)
if len(self.had) != len(novy_seznam):
self.konec()
Ve funkci konec se program ukončí.
def konec(self):
self.okno.destroy()
Doporučuji dodělat nějaký způsob zaznamenávání skóre. Tím je dnešní lekce u konce.