From 282e7de4b474abd2c667597a09afd0e5e9a680b0 Mon Sep 17 00:00:00 2001 From: skrabanek Date: Mon, 15 Jun 2026 15:32:34 +0200 Subject: [PATCH] fix --- pygame/main.py | 182 ++++++++++++++++++++++++++++++++++++++++++++++++ pygame/main.zip | Bin 0 -> 4248 bytes 2 files changed, 182 insertions(+) create mode 100644 pygame/main.py create mode 100644 pygame/main.zip diff --git a/pygame/main.py b/pygame/main.py new file mode 100644 index 0000000..09ec674 --- /dev/null +++ b/pygame/main.py @@ -0,0 +1,182 @@ +import pygame +import asyncio # PŘIDÁNO PRO WEB: importujeme asyncio pro neblokující smyčku +import random +import sys + +# Povinná příprava knihovny Pygame +async def main(): # PŘIDÁNO PRO WEB: Zabalíme celou hru do asynchronní funkce + pygame.init() + + # --- NASTAVENÍ OKNA A MŘÍŽKY --- + # Hra SNAKE (Had) většinou nefunguje na pixely jako ostatní hry, ale funguje na jakési neviditelné "Mřížce". + SIRKA_OKNA = 800 + VYSKA_OKNA = 600 + VELIKOST_DILKU = 20 # Velikost jednoho čtverečku na mřížce (dílku hada i jídla) + FPS = 15 # Rychlost hada. Zde je nižší 15, protože pohyb po skocích na mřížce nevyžaduje 60 FPS. + + # Definice Palety Barev (Red, Green, Blue) + CERNA = (0, 0, 0) + BILA = (255, 255, 255) + ZELENA = (0, 255, 0) + CERVENA = (255, 0, 0) + + okno = pygame.display.set_mode((SIRKA_OKNA, VYSKA_OKNA)) + pygame.display.set_caption("Klasický Had (Snake)") + + hodiny = pygame.time.Clock() + font = pygame.font.SysFont("arial", 36) + + # Pomocná funkce pro rychlé vykreslení textu na daných x, y. + # Zkracuje to kód, abychom pořád neopakovali metody render() a blit(). + def zobraz_text(text, barva, x, y): + text_plocha = font.render(text, True, barva) + okno.blit(text_plocha, (x, y)) + + # Veškerou logiku hry teď poprvé schováme do tzv. Hlavní Funkce. + # Proč? Jakmile funkce skončí (kvůli výhře/prohře), velmi jednoduše se tímto trikem dá celá hra resetovat, + # jelikož stačí funkci zavolat odznova. + async def hlavni_smycka(): + + # --- POČÁTEČNÍ STAV HRY --- + # Nejdůležitější princip této hry! Tělo hada není jeden objekt, je to SEZNAM SOUŘADNIC (pole v poli). + # Každý článek jeho těla má své [x, y]. Ten ÚPLNĚ PRVNÍ prvek na pozici 0 je HLAVA HADA. + had_telo = [ + [SIRKA_OKNA // 2, VYSKA_OKNA // 2], # Hlava + [SIRKA_OKNA // 2 - VELIKOST_DILKU, VYSKA_OKNA // 2], # Druhý článek břicha + [SIRKA_OKNA // 2 - 2 * VELIKOST_DILKU, VYSKA_OKNA // 2] # Ocas + ] + + # Směr pohybu! Tohle číslo přidáme při každém snímku k souřadnicím HLAVY. + # Tím ji virtuálně posuneme vpřed. + smer_x = VELIKOST_DILKU # Z počátku letí had doprava, protože z osy X roste pozitivně + smer_y = 0 # Do vertikály Y mu zpočátku nepřidáváme nic, letí rovně + + # --- POZICE JÍDLA (ČERVENÝ ČTVEREČEK) --- + # Jídlo musíme nasměrovat přesně do nějaké buňky mřížky! + # Trik: random.randrange(od, do, krok) ... Jídlo padne například na X=20, 40, 60... ale NIKDY na 17, 33 atd. + # Kdyby nebylo zarovnané na mřížku, tak ho had miné! + jidlo_x = random.randrange(0, SIRKA_OKNA, VELIKOST_DILKU) + jidlo_y = random.randrange(0, VYSKA_OKNA, VELIKOST_DILKU) + + skore = 0 + konec_hry = False # Boolean kontrolka pro Game Over + + # Nekonečná smyčka tohoto jednoho konkrétního zápasu + while True: + + # 1. ZPRACOVÁNÍ UDÁLOSTÍ + for udalost in pygame.event.get(): + if udalost.type == pygame.QUIT: + pygame.quit() + sys.exit() + + # Detekce šipek pro změnu SMĚRU pohybu HADA + if udalost.type == pygame.KEYDOWN: + + # OCHRANA: Had nemůže provést fyzicky nemožný obrat o 180 stupňů a zajet si rovnou do těla! + # Tzn. pokud zmáčknul šipku DOLEVA, a had letí rovně/doprava (smer_x == 0), + # teprve pak si smí dovolit nastavit změnu směru. + if udalost.key == pygame.K_LEFT and smer_x == 0: + smer_x = -VELIKOST_DILKU # Záporná hodnota pro směr vlevo + smer_y = 0 # Vertikální se ruší + elif udalost.key == pygame.K_RIGHT and smer_x == 0: + smer_x = VELIKOST_DILKU # Kladná hodnota pro směr vpravo + smer_y = 0 + elif udalost.key == pygame.K_UP and smer_y == 0: + smer_x = 0 + smer_y = -VELIKOST_DILKU # Záporná hodnota směrem vzhůru k Y=0 + elif udalost.key == pygame.K_DOWN and smer_y == 0: + smer_x = 0 + smer_y = VELIKOST_DILKU + + # Pokud zemřel a bliká varování, čekáme na Mezerník + if udalost.key == pygame.K_SPACE and konec_hry: + # Pokud nastane RETURN, znamená to, že se celá tato 'hlavni_smycka()' okamžitě ukončí, + # její paměť (proměnné had_telo atd) se nenávratně vymaže. + # Následně ji však náš spouštěč úplně dole v souboru spustí naprosto na čisto znova. (RESTART) + return + + # LOGIKA HRY: Provede se jenom pokud žijeme + if not konec_hry: + + # --- ZÁKLADNÍ PRINCIP POHYBU HADA --- + # Jak hada posunout? + # 1. Spočítáme, kde se bude nacházet hadova hlava v PŘÍŠTÍM Snímku + # Vezmeme si pozici staré hlavy, neboli had_telo na nultém indexu + nova_hlava_x = had_telo[0][0] + smer_x + nova_hlava_y = had_telo[0][1] + smer_y + + # 2. Tuto ZCELA NOVOU POZICI vsuneme pomocí "insert" na ÚPLNÝ ZAČÁTEK (index 0) našeho Seznamu + # Náš had je najednou o kousek delší! (Natáhl hlavu tam, kam letí) + had_telo.insert(0, [nova_hlava_x, nova_hlava_y]) + + # --- SEŽRÁNÍ JÍDLA (Růst hada) --- + # Zjišťujeme, zda se souřadnice nové hlavy náhodou rovnou nerovnají pozici Jídla na mřížce. + # Nepoužíváme obdélníkové kolize, protože pracujeme s přesnou mřížkou! + if nova_hlava_x == jidlo_x and nova_hlava_y == jidlo_y: + skore += 1 # Bod do tabulky! + + # Zrušíme staré jídlo a najdeme mu na hracím plánu nové náhodné místo (zarovnané na mřížku) + jidlo_x = random.randrange(0, SIRKA_OKNA, VELIKOST_DILKU) + jidlo_y = random.randrange(0, VYSKA_OKNA, VELIKOST_DILKU) + + # TOHLE JE DŮLEŽITÉ: Náš hadí Seznam byl momentálně obohacen o přední novou "hlavu", tzn vyrostl, a + # a my mu ten starý OCAS NEZKRÁTÍME. Takže je opravdu objektivně o jedno políčko natrvalo větší! + else: + # Pokud jídlo na této pozici NEBYLO, my musíme zachovat hada stále stejně dlouhého. + # Nahoře jsme mu před chvílí přidali hlavičku. Tady dole mu z konce seznamu (ocásku) + # jeden prvek odebereme (pomocí .pop()), takže vlastně provedl POHYB A JE STÁLE STEJNĚ DLOUHÝ. + had_telo.pop() + + # --- SMRTELNÉ NÁRAZY (Stěna a Sebevražda) --- + + # Pokud vylétla nová hlava mimo rozměry Okna... + if (nova_hlava_x < 0 or nova_hlava_x >= SIRKA_OKNA or + nova_hlava_y < 0 or nova_hlava_y >= VYSKA_OKNA): + konec_hry = True # GAME OVER + + # Nebo pokud had sežral vlastního ocas! + # for-cyklus "for dilek in had_telo[1:]" prohlédne VŠE kromě samotné hlavy (začíná od indexu 1, čili tělo) + # A pokud se na jedné jediné z těchto pozic těla nachází nově nakreslená hlava, tak had do sebe kousl. + for dilek in had_telo[1:]: + if nova_hlava_x == dilek[0] and nova_hlava_y == dilek[1]: + konec_hry = True + + # --- VYKRESLOVÁNÍ (Obarvování monitoru) --- + okno.fill(CERNA) # Umytí tabule na černo + + # 1. Jídlo (Čtverec o rozměrech jedné buňky na mřížce) + pygame.draw.rect(okno, CERVENA, (jidlo_x, jidlo_y, VELIKOST_DILKU, VELIKOST_DILKU)) + + # 2. Celý samotný dlouhý had + # Projdeme seznam všech buněk a pro každičkou z nich na daném [X, Y] nakreslíme jeden zelený kvádr + for dilek in had_telo: + pygame.draw.rect(okno, ZELENA, (dilek[0], dilek[1], VELIKOST_DILKU, VELIKOST_DILKU)) + + zobraz_text(f"Skóre: {skore}", BILA, 10, 10) + + if konec_hry: + # Zásadní hláška uprostřed pole o tom, ať to zkusí hráč znovu. + zobraz_text("Konec hry! Stiskni MEZERNÍK pro novou hru.", CERVENA, 100, VYSKA_OKNA // 2) + + # Hotový frame se prohazuje s tím na monitoru + pygame.display.flip() + + # Omezení rychlosti + hodiny.tick(FPS) + # PRIDANO PRO WEB + await asyncio.sleep(0) + +# Úplný spodek skriptu Pythonu + # Tento 'if' ověřuje, jestli Python zapnul tento soubor napřímo jako první. + if __name__ == "__main__": + + # NEKONEČNÁ SLUČKA ŽIVOTA. + # Jakmile uvnitř `hlavni_smycka` zavoláme 'return' kvůli Game Over + stisku Mezerníku, + # funkce se zničí, a tento while True ji opět vzkřísí z prachu k novému životu s čistým listem skóre. + while True: + await hlavni_smycka() + + +# PŘIDÁNO PRO WEB: Spuštění asynchronní hry +asyncio.run(main()) \ No newline at end of file diff --git a/pygame/main.zip b/pygame/main.zip new file mode 100644 index 0000000000000000000000000000000000000000..6bb4386141d9537328d4f3b7ef4867429c41e930 GIT binary patch literal 4248 zcmZ{oS2P?9w}uC!CD93n38DniTZmr5=tFeTheU}Qz1IX0L^nYYJvw8U=)H{IyQsq; zdJX^gor`n+o3r1w_TKM$_x)b$fvV#HsR2a)NL+8|4dB0u5Woz0Z)NYy=j!X}^ALao z{5Sibrmsf=Aav?_?yz;v?_li)cBnT|cVU=IS$;8kzh-2P6wjUeD!fD-aRjV;Wh!K= z%fep3-U;P1Hngjb@sv1ope3yR!-vBITX1HTL-ut%?2g3}B#3oiTbyM1$MQ$($=XF# zy(%d^SpU^>lI1Z-|45&FOdybz;CPTfM)p-93EMJwdoa1lqISf9e z=w?B>f$g{Y-j@c}Zgi7HVeQhWNyqym8Ai4qMYxo;V@Cu?T5o?3@>hkZF|LgChz!ZX z(mLhX!rrW4O1iW$-)Gazqnv!T@YXI3?ETTxTCY@m=GeuiQ?g@9XuDv~YX{B0R}Hgg z^|mZ@e~XAuME$Pd#3=m2@e?ebII-G_#W4_GOV4E*FxIM!56e8{z7 zISPdNRJ~qLF;{cX=6(7H`YTcH`PK%`hxNNt!p*h4rweFJkF(1k(yiBMti$`@%4H{} z?0xM1OuXy%7>CPWBfl@P%}|T^mR+vQH%ifu*x+&ALg^K%saa-z$XO}`^G8do1uAyo ztJ-ieyT$9w$FdhCDPI0hw1;iDKRBpcUwylM$)tE(UO9*rP8_IYC(-BMUwsx?5w`ci zf3QrE%07tK$zb#a{FkMzb1B%DbZ@N$Z%0rK6HNqDFi@Yj^?L%rq+z0I2d!(h9eK+^ zj#?*b^de>N`63tNkXJ|UvvD=f z{Myi(0$cRHp?Q@_N!>%JKUj(!Gy^yzqrvcwd|3Vnm9ZnVX!tAc^q5R0NdZp*#Ws>Ce&#D|=C;5Vj7F zcg(D|Mbwa$)KLAW^5FRVxkmDHCb#(-U<$UppEJDg;e=P6FGiw9<+bHp zdEEpn>AmQ>YUti%##>VvoaQ}TAB17%XeT{*PO6{dDg7#17H8y;k70in9Qvk{IrOUn zBm-vCM%l&*VyBruQ|jRMFBCP&uzv|nid`9dxJJr|_wc7nM5JtE+e9jSBPSQmhT7d^ z+AtIV2B!@qLtIwV^fBaC=kmYOG{Ko(7!*jH~ER;Y38TW~jfB2crKTcr7e>_Ek9<}UljLDbmwC zUq7LI#$FFsxw@Fj>REnW6ZPPMrX}S_#&v>m1K+VD!%lfp+M?wd8sR>3PAgRVWMTig9PpqNb|HVkB?R=xEK+ zmB-stxZi@$XrxWLfPrhC8PkCWj&CWwwIO6Kuuw?@Krw-viw9fa1=03Nv$Ve$x&eMbahv2Vp;ixy&Ow`RmiFbm!8|5 z{A}L?WFD`Z5I&3WUlxl)*3XQi=}y?Iq8 z9T~06U`)e1Auv<>$F&Ko%8)CrKy@6-yvZO+31WlhYJ&XpEzR`l zEv)vTNzW}JoLG9u5Mhsu!$ZUZ?5`EF#P5^fS{_LFvZ<~tz#g?4PIK3B|6*JhLWJN> zV&H60N>Q_I+9gM9h>FU8kbXzke!jo1(${bwbHCzrTsxEp@;}R>YH2)UfK^!}eZp=+ z8YZ*`L`1uPvbKXLhbp$5I^zbZiD^~!Ox;&k&pVcHNYC@l)}{}t6AO}CHn!zyIkgA_b~fRNCeeN*t_^0o;YeQV6sEaGk&2 z=Q#G48oEyoCMWWq9K6I_er* z%DiS&@*o#xF_EVEwBRRi>ObNgocQAf(DoL1UXhqoev<_Ji%-c29%{(B+t_!xi&(m) zwsF8|&q>nZzh@L^75BYW|FQb%?*6Nd@#nKDH%nYvpCfs{!o09posJT64Sp0)xSi?@ zlvtjB6QV$yb};g#;#{7FF}xsavp^D-<*d;wrW;u1y>`=j#>hutL{;5K#?7Mx@>;rI!??JYd#Q2?HNI=>({cxz>|wAZ!Y}cp*Sa9aU&# zBzjfNNP;Al`_1*>rMPVyU#Rc6(1Z$GUSoKh5G0f$jrohqV8e3`+t@73`<+kOq=EHU zp!*%eS3g%I_?iWs9mV*}-iNCc>)Rj)F%zJ7LHWLmQbLo#@n7@C>D^5UwGeBUEH!9? z*gQv5YP=%-*EKW!s~Tj<49f!0YmP}T=2KrR%bhh-*i;Mz2ZQ{nu1=R=W zoQX53@=3ZisSt|pHrFT`K53d}Ys7%w)l{Crpn8*^naN?=zDdxO5cLNW-1_5@S2;Cx z!~EJeS~A1;75>X@?Bbk@@6F$;nFsAYW!!{3NkB2{w@ju)MS<3JnyM(&&4vfmJk_FN z_ORo6-lgGcX~dyrh8}AlSsQ0nME{Cn zeN{UJJ-A%db_tYzE6cg#tbNhSbC5daF}t{=Qg5E0b<1?~XQ{apJF;*h9M-Fw7}hxfu>DRUeR}z z-H$!b>UB#N)N9n^72!7mi%7f8mjO{7+|{p><{KS5eUng)1Ty`&mtPc-TPDr$;X({Q zx2YGbZOu~C4JD+fSf)1)emEWQJ5&~9o~nh(Rz>RB9?Iwbb8LnL2qy%Yg-CcQ z&)euZnK{#Z<<&H2X#aUd>|w_06NTEA)(4f{g zPF=42KwX*2mY+H&$Z3=E2m-oS?M>nyQ9`Yx5r*ln8%*>JBQ6X`qz&6Uop=4*APkEV z)nKxg-tH#Z};Urykf;E3WCr?*+J7btt~wbB+hcw(CFhdAn9V} z4Q^?j1J#uENv=d|GARD28!hZ3P2lA}(Z+MVi?1sDDI)9A+Al^gz4cuu#+jSr0HVqA zi-xqy0J~qWKZs5)`Y23ensPFPE}!w9uzj2;L zG!%@FH`WW?{<3X+eOl9X0w&SrBm3Z$QYbE0P-uWyis362^{v$QMu|LpKDV!l))#T2 zrSB&()sAPwJ2Jy(WsSYi&wdh?+RyE7@0*D~*btAKnq-bS_i8uE$!kMpHf`yL4jMYm z!O8O71%d6%+%rZzI?o6Qnqc!(*FGU*MuLFw(zC+tq}9F37T$^ey^<3QqZP9^+Z;`0 zU!*5?)hqlswYA*!i|DmbZ$ETq5;Gu7c60T>R0<%y@(wj8i`S@mUlKhV%+h+&=#_yG zySguLCyGGDcq~06jw~brko_Ssg#H}V$+|rC1rcTAdeRnWH;Q;lOoWxV*+6Ma%RnBn z@a5tY(xG;9Nq2=A?;YEH>Y!}1Nwhk9X7ynZ@+}?z zo?h1Sydxbvet(qZYFD|g2S{*#N3XuDQX+ObtJ=we41IVG7VqRN3>VquYE9UZVKQyikT`&@TLNHkLP<9mSC5znWw1QaqcXtIvEu$Q;5{W^svfxOSih$`E|tEV}mR#>?& zu2wkc`8L*Ry=TrP-@rxewB%6I;gCsld8Q0V;J+yKlaHxSa|E>xEbNmVWlDP~87!hQ z+645o%mk4YixcO7?OY{>NU29q25!Fgi5RPwpS~aNOp^LRt zqpW7eXUL19LDGbV+j&*$I&daJ!z*&0X2l&K=}K)d%^15Vb`Zz$*b&