Skip to content

Commit a6f2cc1

Browse files
committed
Snake: Add Pyglet fast-track, some more rewriting
1 parent 679c736 commit a6f2cc1

File tree

6 files changed

+373
-73
lines changed

6 files changed

+373
-73
lines changed

courses/snake/info.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,17 @@ plan:
6060
- lesson: fast-track/for
6161
- title: "Doplnění: list slicing, del, n-tice, zip()"
6262
url: null
63-
- lesson: intro/pyglet
64-
title: Úvod do Pygletu (*)
63+
- title: Had
64+
slug: workshop
65+
materials:
66+
- title: Instalalce Pygletu
67+
url: null
68+
- lesson: fast-track/pyglet
6569
- lesson: snake/drawing
6670
- lesson: snake/logic
6771
- title: Zabalení spustitelného souboru (bonus)
6872
url: null
6973
- title: Rozšíření
7074
slug: extensions
71-
date: 2018-09-01
72-
time:
73-
start: '18:00'
74-
end: '18:30'
7575
materials:
7676
- lesson: snake/toroid

lessons/fast-track/pyglet/index.md

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
# Grafika
2+
3+
Teď si ukážeme, jak napsat grafickou aplikaci.
4+
5+
Python obsahuje nástroje na kreslení obrázků,
6+
ale pro tvorbu her nejsou příliš vhodné.
7+
Použijeme proto *knihovnu* (nadstavbu) jménem Pyglet, která je přímo stavěná
8+
na interaktivní grafiku.
9+
10+
Musíme si ji ale nejdřív zvlášť nainstalovat.
11+
Nejjistější je do příkazové řádky se zapnutým virtuálním prostředím
12+
zadat následující dva příkazy.
13+
(Existují i jednodušší způsoby, které ovšem vyžadují „správně“
14+
nastavený systém.)
15+
16+
* Aktualizace nástroje `pip`, který umí instalovat knihovny pro Python:
17+
``` console
18+
(venv)$ python -m pip install --upgrade pip
19+
```
20+
(V překladu: **Python**e, spusť **m**odul **pip** a řekni mu,
21+
ať na**instal**uje a kdyžtak aktualizuje (*upgrade*) knihovnu **pip**.)
22+
* Samotné nainstalování Pygletu:
23+
``` console
24+
(venv)$ python -m pip install pyglet
25+
```
26+
(V překladu: **Python**e, spusť **m**odul **pip** a řekni mu,
27+
ať na**instal**uje knihovnu **pyglet**.)
28+
29+
U mě vypadá instalace nějak takto:
30+
31+
```console
32+
(venv)$ python -m pip install --upgrade pip
33+
Requirement already satisfied: pip in ./venv/lib/python3.6/site-packages (18.0)
34+
(venv)$ python -m pip install pyglet
35+
Collecting pyglet
36+
Downloading pyglet-1.2.4-py3-none-any.whl (964kB)
37+
Installing collected packages: pyglet
38+
Successfully installed pyglet-1.2.4
39+
```
40+
41+
Důležité je `Successfully installed`, resp. `Requirement already satisfied`
42+
na konci.
43+
To znamená že je knihovna připravená k použití!
44+
45+
46+
## Kostra programu
47+
48+
Teď zkus v editoru vytvořit nový soubor, uložit ho jako `grafika.py`
49+
a napsat do něj následující program:
50+
51+
```python
52+
import pyglet
53+
window = pyglet.window.Window()
54+
pyglet.app.run()
55+
print('Hotovo!')
56+
```
57+
58+
Spusť ho. Mělo by se objevit černé okýnko.
59+
60+
> [note] Okýnko není černé?
61+
> Na některých počítačích (často s macOS a některými druhy Linuxu) se stává,
62+
> že okýnko není černé, ale je v něm nějaký „nepořádek“.
63+
> To nevadí.
64+
> Než do okýnka začneme kreslit, nepořádek uklidíme.
65+
66+
> [note] AttributeError?
67+
> Jestli dostaneš chybu
68+
> `AttributeError: module 'pyglet' has no attribute 'window'`, zkontroluj si,
69+
> zě jsi soubor pojmenoval{{a}} `grafika.py` a ne `pyglet.py`.
70+
> Soubor v editoru„ulož jako `grafika.py`, případný soubor `pyglet.py` smaž,
71+
> a zkus to znovu.
72+
73+
Hotovo? Pojďme si vysvětlit, co se v tomhle programu děje.
74+
75+
Příkaz `import pyglet` ti zpřístupní grafickou knihovnu, tak jako třeba
76+
`import random` ti zpřístupní funkce okolo náhodných čísel.
77+
78+
Zavolání `pyglet.window.Window()` vytvoří nové *okýnko* na obrazovce.
79+
Vrátí objekt, kterým pak tohle okýnko můžeš ovládat; ten si uložíme
80+
do proměnné `window`.
81+
82+
Zavolání `pyglet.app.run()` pak spustí aplikaci.
83+
Co to znamená?
84+
85+
Jednoduché programy, které jsi zatím psal{{a}}, jsou popisy procesu – podobně
86+
jako třeba recepty k vaření.
87+
Sled kroků, které Python postupně vykoná od prvního po poslední.
88+
Občas se něco opakuje a některé kroky se dají „zabalit“ do funkce,
89+
ale vždycky jsme zatím popisovali jeden postup od začátku po konec.
90+
91+
Programy pro složitější aplikace spíš než jako recept vypadají jako příručka
92+
automechanika.
93+
Popisují, co se má stát v jaké situaci.
94+
Třeba program pro textový editor by mohl vypadat takhle:
95+
96+
* Když uživatel zmáčkne písmenko na klávesnici, přidej ho do dokumentu.
97+
* <p>Když uživatel zmáčkne <kbd>⌫ Backspace</kbd>, poslední písmenko umaž.</p>
98+
* Když uživatel zmáčkne tlačítko Uložit, zapiš soubor na disk.
99+
100+
I takový program se dá napsat i jako „recept“ – ale ten recept je pro všechny
101+
aplikace stejný:
102+
103+
* Pořád dokola:
104+
* Počkej, než se něco zajímavého stane
105+
* Zareaguj na nastalou situaci
106+
107+
A to je přesně to, co dělá `pyglet.app.run()`.
108+
Zpracovává *události*, situace na které je potřeba zareagovat.
109+
V tvém programu reaguje zavírací tlačítko okýnka a na klávesu <kbd>Esc</kbd>
110+
tím, že okno zavře a ukončí se.
111+
112+
Tvůj úkol teď bude popsat, jaké další události jsou zajímavé
113+
a jak na ně reagovat.
114+
115+
116+
## Obsluha událostí
117+
118+
Nejjednodušší událost, kterou můžeme obsloužit, je psaní textu na klávesnici.
119+
120+
Zkus do programu těsně nad řádek `pyglet.app.run()` dát následující kód:
121+
122+
``` python
123+
@window.event
124+
def on_text(text):
125+
print(text)
126+
```
127+
128+
Co to je?
129+
Je to definice funkce, ale na začátku má *dekorátor* – tu řádku začínající
130+
zavináčem.
131+
132+
Dekorátor `window.event` je způsob, jak Pygletu říct, že má tuto funkci
133+
spustit, když se něco zajímavého stane.
134+
135+
Co zajímavého?
136+
To Pyglet zjistí podle jména funkce: `on_text` reaguje na text.
137+
Vždycky, když uživatel zmáčkne klávesu, Pyglet zavolá tvoji funkci!
138+
139+
A co udělá tvoje funkce? Zavolá `print`. To už znáš.
140+
Zadaný text se vypíše na konzoli, ze které program spouštíš.
141+
To, že je otevřené okýnko, neznamená že `print` začne automaticky psát do něj!
142+
143+
144+
## Kreslení
145+
146+
Jak psát do okýnka?
147+
To je trochu složitější než do konzole.
148+
Text tu může mít různé barvy, velikosti, druhy písma,
149+
může být všelijak posunutý nebo natočený…
150+
151+
Všechny tyhle *atributy* písma můžeme (i se samotným textem) uložit do objektu
152+
`Label` („popisek“).
153+
Zkus to – dej následující kód pod řádek s `window = `:
154+
155+
```python
156+
label = pyglet.text.Label("Ahoj!", x=10, y=20)
157+
```
158+
159+
V proměnné `label` teď budeš mít máš popisek s textem `"Ahoj"`, který patří
160+
na pozici (10, 20) – 10 bodů od pravého okraje okna, 20 od spodního.
161+
162+
To je ale jen informace.
163+
Podobně jako pro vypsání textu do konzole je potřeba zavolat `print`,
164+
pro nakreslení textu je potřeba reagovat na událost
165+
*vykreslení okna*`on_draw`.
166+
167+
Dej pod funkci `on_text` tento kód:
168+
169+
```python
170+
@window.event
171+
def on_draw():
172+
window.clear()
173+
label.draw()
174+
```
175+
176+
Tuhle funkci Pyglet zavolá vždycky, když je potřeba nakreslit obsah okýnka.
177+
U animací (filmů nebo her) to často bývá třeba 60× za sekundu
178+
(„[60 FPS](https://cs.wikipedia.org/wiki/Sn%C3%ADmkov%C3%A1_frekvence)“).
179+
180+
Funkce dělá dvě věci:
181+
* Smaže celé okýnko (nabarví ho na černo)
182+
* Vykreslí text
183+
184+
V okně teď bude vidět pozdrav!
185+
186+
187+
Zkus ještě změnit `on_text` tak, aby se zadaný text místo na konzoli
188+
ukázal v okýnku.
189+
To se dělá přiřazením do *atributu* `label.text`:
190+
191+
```python
192+
@window.event
193+
def on_text(text):
194+
print('Starý text:', label.text)
195+
label.text = text
196+
print('Nový text:', label.text)
197+
```
198+
199+
Zvládneš v této funkci nový text přidat ke starému,
200+
aby program fungoval jako jednoduchý textový editor?
201+
202+
{% filter solution %}
203+
```python
204+
@window.event
205+
def on_text(text):
206+
label.text = label.text + text
207+
```
208+
{% endfilter %}
209+
210+
211+
## Další událostí
212+
213+
Na jaké další události se dá reagovat?
214+
Všechny jsou popsané v [dokumentaci Pygletu](https://pyglet.readthedocs.io/en/latest/modules/window.html#pyglet.window.Window.on_activate).
215+
Tady uvádím pár zajímavých.
216+
217+
### Stisk klávesy
218+
219+
Klávesy, které nezadávají text (šipky, <kbd>Backspace</kbd> nebo
220+
<kbd>Enter</kbd>, atp.) se dají rozpoznat v události `on_key_press`.
221+
222+
Funkce `on_key_press` má dva argumenty: první je kód klávesy,
223+
který můžeš porovnat s konstantou z [pyglet.window.key](https://pyglet.readthedocs.io/en/latest/modules/window_key.html#key-constants).
224+
Druhý určuje stisknuté modifikátory jako <kbd>Shift</kbd> nebo <kbd>Ctrl</kbd>.
225+
226+
``` python
227+
@window.event
228+
def on_key_press(key_code, modifier):
229+
if key_code == pyglet.window.key.BACKSPACE:
230+
label.text = label.text[:-1]
231+
232+
if key_code == pyglet.window.key.ENTER:
233+
print('Zadaná zpráva:', label.text)
234+
window.close()
235+
```
236+
237+
Na macOS budeš možná muset zaměňit `BACKSPACE` za `DELETE`. {# XXX: je to tak? #}
238+
(Nebo si doma nastuduj [způsob](https://pyglet.readthedocs.io/en/latest/programming_guide/keyboard.html#motion-events), jak to dělat automaticky a správně.)
239+
240+
241+
### Kliknutí myši
242+
243+
Při obsluze události `on_mouse_press` dostaneš informace o pozici
244+
kliknutí (<var>x</var>-ovou a <var>x</var>-ovou souřadnici)
245+
a navíc informaci o stisknutém tlačítku myši a modifikátoru.
246+
247+
Takhle se třeba popisek přesune na místo kliknutí:
248+
249+
```python
250+
@window.event
251+
def on_mouse_press(x, y, button, modifier):
252+
label.x = x
253+
label.y = y
254+
```
255+
256+
257+
## Celý program
258+
259+
Pro případ, že by ses ztratil{{a}} nebo nevěděla,
260+
kam který kousek kódu patří, uvádím výsledný ukázkový program.
261+
262+
```python
263+
import pyglet
264+
window = pyglet.window.Window()
265+
label = pyglet.text.Label("Ahoj!", x=10, y=20)
266+
267+
268+
@window.event
269+
def on_draw():
270+
window.clear()
271+
label.draw()
272+
273+
274+
@window.event
275+
def on_text(text):
276+
label.text = label.text + text
277+
278+
279+
@window.event
280+
def on_key_press(key_code, modifier):
281+
if key_code == pyglet.window.key.BACKSPACE:
282+
label.text = label.text[:-1]
283+
284+
if key_code == pyglet.window.key.ENTER:
285+
print('Zadaná zpráva:', label.text)
286+
window.close()
287+
288+
289+
@window.event
290+
def on_mouse_press(x, y, button, modifier):
291+
label.x = x
292+
label.y = y
293+
294+
295+
pyglet.app.run()
296+
```
297+

lessons/fast-track/pyglet/info.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
title: Úvod do Pygletu
2+
style: md
3+
attribution:
4+
- Pro PyLadies Brno napsal Petr Viktorin, 2015-2018.
5+
license: cc-by-sa-40

0 commit comments

Comments
 (0)