Skip to content

Commit 4c974be

Browse files
authored
Asteroids improvements (#294)
- based on IRL conversation with @encukou - no window attribute (plenty of globals anyway, be consistent) - sometimes, be more specific - explain how the controls should work - center the anchor of images - add a bit info about CONSTANTS - flip sin and cos (just deal with Pyglet's rotation direction) - make sure .x, .y. and .rotation are propagated to .sprite - remove unnecessary asterisk - use <var> where appropriate - add some missing commas - adding objects to objects can be done in __init__ - so don't explicitly require people to do it manually - remove draw_circle once not needed anymore - change sprite description Merges #294
1 parent db98a54 commit 4c974be

1 file changed

Lines changed: 75 additions & 50 deletions

File tree

lessons/projects/asteroids/index.md

Lines changed: 75 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ První krok bude naprogramovat vesmírnou loď, která půjde ovládat klávesni
3535

3636
* Vesmírnou loď bude reprezentovat objekt třídy `Spaceship`.
3737
* Každá loď má vlastní atributy `x` a `y` (pozice),
38-
`x_speed` a `y_speed` (rychlost), `rotation` (úhel natočení),
39-
`sprite` (obrázek pro Pyglet) a `window` (okno, ve kterém se hraje).
38+
`x_speed` a `y_speed` (rychlost), `rotation` (úhel natočení) a
39+
`sprite` (2D objekt v Pygletu s polohou, rotací a obrázkem).
4040
* Loď má metodu `tick`, která obstarává
4141
mechaniku týkající se lodi – posouvání, natáčení a ovládání.
42-
* Všechny objekty ve hře si budeme dávat do seznamu `objects`.
42+
* Všechny objekty ve hře si budeme dávat do globálního seznamu `objects`.
4343
Zatím tam bude jenom vesmírná loď.
4444
* Co se ovládání týče, stisknuté klávesy si uchovávej v *množině* (angl. `set`),
4545
což je datový typ podobný seznamu, jen nemá dané pořadí
@@ -62,49 +62,70 @@ První krok bude naprogramovat vesmírnou loď, která půjde ovládat klávesni
6262
Do „batche” jde přidávat pomocí argumentu při vytváření `Sprite()`
6363
a odebírat pomocí `sprite.delete()`. Například:
6464

65-
```python
66-
batch = pyglet.graphics.Batch()
67-
sprite1 = pyglet.sprite.Sprite(obrazek, batch=batch)
68-
sprite2 = pyglet.sprite.Sprite(obrazek, batch=batch)
69-
70-
# a potom můžeš vykreslit všechny najednou:
71-
batch.draw()
72-
```
73-
74-
* Základní pohyb raketky je jednoduchý: k x-ové
75-
souřadnici se přičte x-ová rychlost krát uplynulý čas
76-
a to samé v y-ové souřadnici i pro úhel otočení:
77-
78-
```python
79-
self.x = self.x + dt * self.x_speed
80-
self.y = self.y + dt * self.y_speed
81-
self.rotation = self.rotation + dt * rotation_speed
82-
```
83-
84-
Rychlost otáčení závisí na stisknutých šipkách (doleva nebo doprava).
85-
86-
* Zrychlení je trochu složitější: k x-ové rychlosti
87-
se přičte kosinus úhlu otočení krát uplynulý čas.
88-
U y-ové osy se použije sinus.
89-
Je ale potřeba převést úhel na radiány, protože
90-
Pyglet (a naše hra) používá stupně:
91-
92-
```python
93-
rotation_radians = math.radians(self.rotation)
94-
self.x_speed += dt * ACCELERATION * math.cos(rotation_radians)
95-
self.y_speed += dt * ACCELERATION * math.sin(rotation_radians)
96-
```
97-
* Když raketka vyletí z okýnka ven, vrať
98-
ji zpátky do hry na druhé straně okýnka.
99-
(Zkontroluj si, že to funguje na všech čtyřech stranách.)
65+
```python
66+
batch = pyglet.graphics.Batch()
67+
sprite1 = pyglet.sprite.Sprite(obrazek, batch=batch)
68+
sprite2 = pyglet.sprite.Sprite(obrazek, batch=batch)
69+
70+
# a potom můžeš vykreslit všechny najednou:
71+
batch.draw()
72+
```
73+
74+
Kolekci `batch` si stejně jako `objects` uchovávej globálně.
75+
* Aby se objekty hýbaly a otáčely podle svých středů, je dobré nastavit „kotvu“
76+
obrázku na jeho střed (jinak je kotva v levém dolním rohu):
77+
78+
```python
79+
image = pyglet.image.load(...)
80+
image.anchor_x = image.width // 2
81+
image.anchor_y = image.height // 2
82+
self.sprite = pyglet.sprite.Sprite(image, batch=batch)
83+
```
84+
* Pro pohyb raketky půjde použít klávesy s šipkami doleva, doprava a rovně.
85+
Šipky do stran raketu točí, šipka dopředu zrychluje pohyb tím směrem, kam je
86+
raketka otočená.
87+
* Základní pohyb raketky je jednoduchý: k <var>x</var>-ové
88+
souřadnici se přičte <var>x</var>-ová rychlost krát uplynulý čas
89+
a to samé v <var>y</var>-ové souřadnici i pro úhel otočení:
90+
91+
```python
92+
self.x = self.x + dt * self.x_speed
93+
self.y = self.y + dt * self.y_speed
94+
self.rotation = self.rotation + dt * rotation_speed
95+
```
96+
97+
Rychlost otáčení závisí na stisknutých šipkách (doleva nebo doprava).
98+
V jednom případě je záporná, v druhém kladná. Vhodnou hodnotu zvol
99+
experimentováním. Všechny podobné „magické hodnoty“ je vhodné definovat
100+
jako konstanty – tedy proměnné, které na začátku nastavíš a nikdy
101+
je neměníš. Bývá zvykem je označovat velkými písmeny a dávat je na
102+
začátek souboru, hned za importy.
103+
* Zrychlení je trochu složitější: k <var>x</var>-ové rychlosti
104+
se přičte sinus úhlu otočení krát uplynulý čas.
105+
U <var>y</var>-ové osy se použije kosinus.
106+
Je ale potřeba převést úhel na radiány, protože
107+
Pyglet (a naše hra) používá stupně:
108+
109+
```python
110+
rotation_radians = math.radians(self.rotation)
111+
self.x_speed += dt * ACCELERATION * math.sin(rotation_radians)
112+
self.y_speed += dt * ACCELERATION * math.cos(rotation_radians)
113+
```
114+
115+
Všimni si v příkladu konstanty `ACCELERATION`. Tu opět zvol podle uvážení.
116+
* Když máš hodnoty `self.x`, `self.y` a `self.rotation` spočítané, nezapomeň
117+
je promítnout do `self.sprite`, jinak se nic zajímavého nestane.
118+
* Když raketka vyletí z okýnka ven, vrať
119+
ji zpátky do hry na druhé straně okýnka.
120+
(Zkontroluj si, že to funguje na všech čtyřech stranách.)
100121
* **Bonus 1**: Zkus si přidat několik raketek,
101122
každou trochu jinak natočenou.
102123

103124
Každý jednotlivý objekt třídy `Spaceship`
104125
si udržuje vlastní stav, takže by nemělo být složité
105126
jich vytvořit víc (a všechny ovládat najednou).
106127
* **Bonus 2**:
107-
Možná sis všiml{{a}} „skoku” když
128+
Možná sis všiml{{a}} „skoku”, když
108129
raketa vyletí z okýnka a vrátí se na druhé straně.
109130
Tomu se dá zabránit tak, že
110131
vlevo, vpravo, nahoře i dole vedle naší „scény”
@@ -152,7 +173,7 @@ Přidej druhý typ vesmírného objektu: `Asteroid`.
152173

153174
* Asteroidy a vesmírné lodě mají mnoho společného:
154175
každý takový vesmírný objekt bude mít polohu,
155-
rychlost, natočení a pravidla jak se pohybuje.
176+
rychlost, natočení a pravidla, jak se pohybuje.
156177
Vytvoř proto třídu `SpaceObject`,
157178
ve které bude všechno to společné, a z ní poděď
158179
třídu `Spaceship`, ve které zůstane
@@ -167,15 +188,14 @@ Přidej druhý typ vesmírného objektu: `Asteroid`.
167188
* Napiš ještě třídu `Asteroid`,
168189
která taky dědí ze `SpaceObject`,
169190
ale má svoje vlastní chování:
170-
může mít jednu ze čtyř velikostí,
171-
začíná buď na levé nebo spodní straně obrazovky*
191+
začíná buď na levé nebo spodní straně obrazovky
172192
s náhodnou rychlostí
173193
a ke každému asteroidu se přiřadí
174194
náhodně vybraný obrázek.
175195
(V Asteroidech je levý a pravý okraj v podstatě
176196
to samé; a stejně tak horní a spodní.)
177197
* A pak pár asterojdíků různých velikostí přidej
178-
na začátku hry do `objects`.
198+
na začátku do hry.
179199

180200
Povedlo se? Máš dva typy objektů?
181201
Čas to všechno dát do Gitu!
@@ -192,14 +212,15 @@ Naše asteroidy jsou zatím docela neškodné. Pojďme to změnit.
192212
* V této sekci bude tvým úkolem zjistit, kdy
193213
loď narazila do asteroidu.
194214
Pro zjednodušení si každý objekt nahradíme
195-
kolečkem a budeme počítat kdy se srazí kolečka.
215+
kolečkem a budeme počítat, kdy se srazí kolečka.
196216
Každý objekt bude potřebovat mít poloměr – atribut `radius`.
197217
* Aby bylo vidět co si hra o objektech „myslí”,
198218
nakresli si nad každým objektem příslušné kolečko.
199219
Nejlepší je to udělat pomocí
200220
[pyglet.gl](http://pyglet.readthedocs.org/en/latest/programming_guide/gl.html)
201221
a trochy matematiky; pro teď si jen opiš funkci
202222
`draw_circle` a pro každý objekt ji zavolej.
223+
Až to bude všechno fungovat, můžeš funkci dát pryč.
203224

204225
```python
205226
def draw_circle(x, y, radius):
@@ -226,7 +247,7 @@ Naše asteroidy jsou zatím docela neškodné. Pojďme to změnit.
226247
V rámci `Spaceship.tick` projdi
227248
každý objekt, zjisti jestli vzdálenost mezi lodí
228249
a objektem je menší než součet poloměrů
229-
(t.j. narazily do sebe) a pokud jo,
250+
(t.j. narazily do sebe) a pokud ano,
230251
zavolej na objektu metodu `hit_by_spaceship`.
231252

232253
Zjišťování vzdálenosti ve hře, kde se
@@ -257,6 +278,10 @@ Naše asteroidy jsou zatím docela neškodné. Pojďme to změnit.
257278
`Asteroid.hit_by_spaceship`, aby
258279
zavolala `delete` lodi.
259280

281+
Protože lodí může být v naší hře obecně více, musí asteroid
282+
vědět, se kterou lodí se srazil, aby ji mohl rozbít.
283+
Metoda `hit_by_spaceship` by tedy na to měla mít argument.
284+
260285
Povedlo se? Konečně se dá prohrát?
261286
Čas to všechno zkontrolovat, dát do Gitu a můžeme pokračovat!
262287

@@ -289,7 +314,7 @@ Teď zkusíme asteroidy rozbíjet.
289314
rozdělí na dva menší (nebo, je-li už příliš malý, zmizí úplně).
290315

291316
Rychlosti nových asteroidů si můžeš nastavit
292-
podle sebe – důležité je jen aby každý menší
317+
podle sebe – důležité je jen, aby každý menší
293318
asteroid letěl jinam.
294319
Většinou bývají nové asteroidy rychlejší než ten původní.
295320
* A to je vše! Máš funkční hru!
@@ -320,7 +345,7 @@ vlastní rozšíření!
320345

321346
**Bonus:** Několik vteřin po
322347
„restartu” může být raketka nezničitelná,
323-
aby měla čas odletět když je zrovna uprostřed
348+
aby měla čas odletět, když je zrovna uprostřed
324349
okýnka asteroid.
325350
* Je hra příliš lehká?
326351

@@ -353,13 +378,13 @@ vlastní rozšíření!
353378
Doporučuji si na efekty udělat nový `Batch`
354379
a vykreslit ho před tím hlavním, aby efekty
355380
nepřekrývaly herní objekty.
356-
* Nepoznáš kdy jsi prohrál{{a}}?
381+
* Nepoznáš, kdy jsi prohrál{{a}} nebo vyhrál{{a}}?
357382

358-
Na konci můžeš ukázat veliký nápis GAME OVER.
383+
Na konci můžeš ukázat veliký nápis GAME OVER nebo WINNER.
359384
* Nudíš se?
360385

361386
V původní hře se občas objeví UFO, které občas
362-
vystřelí na místo kde je právě hráčova raketka,
387+
vystřelí na místo, kde je právě hráčova raketka,
363388
takže pokud hráč stojí pořád na jednom místě a
364389
jenom se točí dokola, UFO ho sestřelí.
365390
Můžeš zkusit dodělat třídu `Ufo`

0 commit comments

Comments
 (0)