Kategória: Python gyerekeknek.
Valósítsuk meg azt, hogy jönnek a szellemek! Ezt három lépésre osztjuk.
Függőlegesen jönnek a szellemek
Töltsük be szellem képét! Ezt az űrhajó képének betöltéséhez hasonlóan tudjuk megtenni, és az alá tehetjük: ghost_image = PhotoImage(file='ghost.png'). Képet vagy keressünk a neten, és méretezzük át, vagy használhatjuk az alábbit is.

Ahhoz, hogy a szellem egy véletlen helyről induljon, szükség lesz egy véletlen szám generátorra. Írjuk be a program elejére a következőt: import random
Egyszerre több szellemet fogunk látni. Ezt egy kell menteni egy listába. Ezt hozzuk létre globális változóként, az elején: ghosts = [].
Ha minden lépésben létre hoznánk egy újabb szellemet, akkor másodpercenként 500 jönne létre. Igazából elég csak minden századik lépésben végrehajtani. Emiatt létrehozunk egy számlálót, amit az elején kinullázunk (counter = 0), majd mindegyik lépésben növelünk (a play() függvény elején global counter, majd counter = counter + 1).
Ha épp a századik lépésnél tartunk, létrehozunk egy szellemet egy véletlen helyen felül, és beletesszük a szellemek listájába:
if counter % 100 == 0: ghost = canvas.create_image(random.randint(0, 480), 0, image=ghost_image) ghosts.append(ghost)
Mindegyik lépésben (tehát nemcsak minden századikban) végiglépkedünk a szellemeken ha még nem érte el az alját, akkor lefelé mozgatjuk, azaz növeljük az y koordinátát. Egyébként letöröljük a vászonról. A ghosts listából is ki kell törölni azokat a szellemeket, amelyeket a képernyőről töröltünk. Ehhez a "szellemes" ciklus előtt létrehozunk egy üres tömböt, majd miután az else ágban töröltök a szellemet a képernyőről, hozzáadjuk a listához. A ciklus után pedig egyesével kitöröljük. Ezek megvalósítása:
if counter % 100 == 0: ghost = canvas.create_image(random.randint(0, 480), 0, image=ghost_image) ghosts.append(ghost) deleted_ghosts = [] for ghost in ghosts: ghost_coords = canvas.coords(ghost) if ghost_coords[1] < 360: canvas.move(ghost, 0, 1) else: canvas.delete(ghost) deleted_ghosts.append(ghost) for deleted_ghost in deleted_ghosts: ghosts.remove(deleted_ghost)
A program most úgy működik, hogy jönnek függőlegesen a szellemek:

Átlósan is jönnek a szellemek
Módosítsuk a kódot úgy, hogy ne csak függőlegesen jöjjenek a szellemek! Az ötlet a következő: ahelyett, hogy csak a szellemet tároljuk, hozzunk létre egy olyan struktúrát, ami a szellem mellett tárolja annak irányát is. Az irány legyen véletlenszerű. Ehhez az apróságnak tűnő lépéshez egész sok mindent kell módosítani:
- Miután létrehoztuk a szellemet (ghost = canvas.create_image(…)), határozzunk meg egy véletlen irányt: direction = random.randint(-2, 2).
- Utána szótár formájában hozzunk létre egy szellem struktúrát (ghost_struct = {), melyhez hozzáadjuk a szellemet ('ghost': ghost,) és az irányt ('direction': direction,), majd lezárjuk a szótárat (}).
- A következő sort, melyben elmentjük a szellemet, úgy módosítjuk, hogy a szellem struktúrát mentse el: ghosts.append(ghost) → ghosts.append(ghost_struct).
- Mivel most már a szellem struktúrákon lépkedünk végig, és nem a szellemeken, ennek megfelelően módosítjuk a ciklust for ghost in ghosts: → for ghost_struct in ghosts:.
- Utána a ciklusmagban lekérdezzük a struktúrából a szellemet: ghost = ghost_struct['ghost'].
- Kiolvassuk a struktúrából az irányt is: direction = ghost_struct['direction'].
- Most jön a lényeg: abban a sorban, amelyben mozgatjuk a szellemet, nem lefelé mozgatjuk, hanem az iránynak megfelelően: canvas.move(ghost, direction, 1) → canvas.move(ghost, direction, 1).
- A törölt szellemekhez nem magát a szellemet kell beletenni, hanem a szellem struktúrát: deleted_ghosts.append(ghost) → deleted_ghosts.append(ghost_struct).
Minden irányban egyforma sebességgel jönnek a szellemek
A probléma a fentivel az, hogy aránytalan a szellemek sebessége különböző irányokba. Gondoljunk bele: ha függőlegesen halad, akkor egy lépésben 0 képpontnyit halad oldalra, és 1 képpontnyit lefelé, azaz összesen 1 képpontnyit. Ha viszont kettőt lép oldalra, akkor a Pitagorasz-tételt használva $\sqrt{1^2+2^2} = \sqrt{5} \approx 2,24$ lépést tesz meg, azaz több mint kétszeres sebességgel halad.
A szellemek mozgatását (canvas.move(ghost, direction, 1)) cseréljük le az alábbira:
if direction == 0: canvas.move(ghost, 0, 1) elif abs(direction) == 1: canvas.move(ghost, direction/3, 0.95) else: canvas.move(ghost, direction/3, 0.75)
Ha az irány:
- függőleges, akkor egyet lépünk lefelé, ahogy idáig is tettük.
- nem függőleges, akkor - csökkentve az oldalirányú sebességet - elosztjuk hárommal. (Kikísérletezve így jött ki játszhatónak.)
- 1 vagy -1: nagyon picit csökkentjük a lefelé irányt, hogy - a Pitagorasz tételt használva - körülbelül ugyanakkor legyen a szellem abszolút sebessége, mint amekkora a függőleges szellemé.
- 2 vagy -2: kicsit jobban csökkentjük, hasonló okokból, mint fent.
Azt kaptuk tehát, hogy a szellemek látszólag össze-vissza röpködnek, egyenes pályán, kb. egyenletes sebességgel. Egyelőre még nem lesz "bajunk" attól, ha nekünk jön a szellem; itt folytatjuk a következő lépésben.