Python gyerekeknek - űrhajós játék - utolsó simítások
Kategória: Python gyerekeknek.
Áttekintés
A feladat majdnem kész, de csak majdnem. Sok apróság van még hátra. Létezik egy úgynevezett Pareto-elv (ez egy általános elv), ami jelen esetben azt jelenti, hogy egy szoftver 80%-os készültségére megy az idő 20%-a, és fordítva. Most tartunk a 80% készültségnél és 20% időnél. Tehát akár még négyszer ennyi időt is el lehetne tölteni a csiszolásával, amelynél az eredmény alig látható, és sok időbe telik a megvalósítása. Most pár ilyet nézünk meg!
from tkinter import *
import random
lives = 3
score = 0
counter = 0
rocketship_state = 'stand'
ghosts = []
bullets = []
def key_pressed(event):
global rocketship_state
if event.keysym == 'Left':
rocketship_state = 'left'
if event.keysym == 'Right':
rocketship_state = 'right'
if event.char == ' ':
rocketship_coords = canvas.coords(rocketship)
position_x = rocketship_coords[0] - 10
position_y = rocketship_coords[1] - 50
bullet = canvas.create_oval(
position_x,
position_y,
position_x + 20,
position_y + 20,
width=3,
outline='black',
fill='yellow'
)
bullets.append(bullet)
def key_released(event):
global rocketship_state
if event.keysym in ['Left', 'Right']:
rocketship_state = 'stand'
def play():
global counter
global lives
global score
counter = counter + 1
rocketship_coords = canvas.coords(rocketship)
if rocketship_state == 'left' and rocketship_coords[0] > 0:
canvas.move(rocketship, -1, 0)
if rocketship_state == 'right' and rocketship_coords[0] < 480:
canvas.move(rocketship, 1, 0)
deleted_bullets = []
for bullet in bullets:
if canvas.coords(bullet)[1] > 0:
canvas.move(bullet, 0, -1)
else:
canvas.delete(bullet)
deleted_bullets.append(bullet)
for deleted_bullet in deleted_bullets:
bullets.remove(deleted_bullet)
ghosts_to_delete = []
bullets_to_delete = []
for ghost_struct in ghosts:
ghost = ghost_struct['ghost']
ghost_coords = canvas.coords(ghost)
for bullet in bullets:
bullet_coords = canvas.coords(bullet)
coord_diff_x = abs(bullet_coords[0] - ghost_coords[0])
coord_diff_y = abs(bullet_coords[1] - ghost_coords[1])
if coord_diff_x < 20 and coord_diff_y < 20:
ghosts_to_delete.append(ghost_struct)
bullets_to_delete.append(bullet)
score = score + 1
score_nr_label['text'] = str(score)
for ghost_to_delete in ghosts_to_delete:
canvas.delete(ghost_to_delete['ghost'])
ghosts.remove(ghost_to_delete)
for bullet_to_delete in bullets_to_delete:
canvas.delete(bullet_to_delete)
bullets.remove(bullet_to_delete)
if counter % 100 == 0:
ghost = canvas.create_image(random.randint(0, 480), 0, image=ghost_image)
direction = random.randint(-2, 2)
ghost_struct = {
'ghost': ghost,
'direction': direction,
}
ghosts.append(ghost_struct)
deleted_ghosts = []
hit = False
for ghost_struct in ghosts:
ghost = ghost_struct['ghost']
direction = ghost_struct['direction']
ghost_coords = canvas.coords(ghost)
if ghost_coords[1] < 360:
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)
else:
canvas.delete(ghost)
deleted_ghosts.append(ghost_struct)
coord_diff_x = abs(ghost_coords[0] - rocketship_coords[0])
coord_diff_y = abs(ghost_coords[1] - rocketship_coords[1])
if coord_diff_x <= 40 and coord_diff_y <= 40:
hit = True
lives = lives - 1
lives_nr_label['text'] = str(lives)
for deleted_ghost in deleted_ghosts:
ghosts.remove(deleted_ghost)
if hit:
for ghost_struct in ghosts:
canvas.delete(ghost_struct['ghost'])
ghosts.clear()
for bullet in bullets:
canvas.delete(bullet)
bullets.clear()
if lives <= 0:
canvas.create_text(240, 180, text='VÉGE', fill='yellow', font=('Helvetica', 50))
else:
root.after(2, play)
root = Tk()
root.title('Űrhajós játék')
root.bind('<KeyPress>', key_pressed)
root.bind('<KeyRelease>', key_released)
root.after(2, play)
info_frame = Frame(root)
lives_str_label = Label(master=info_frame, text='Életek száma:')
lives_str_label.grid(column=0, row=0)
lives_nr_label = Label(master=info_frame, text=str(lives))
lives_nr_label.grid(column=1, row=0)
score_str_label = Label(master=info_frame, text='Pontszám:')
score_str_label.grid(column=0, row=1)
score_nr_label = Label(master=info_frame, text=str(score))
score_nr_label.grid(column=1, row=1)
info_frame.pack()
canvas = Canvas(root, width=480, height=360, bg='black')
canvas.pack()
rocketship_image = PhotoImage(file='rocketship.png')
rocketship = canvas.create_image(240, 310, image=rocketship_image)
ghost_image = PhotoImage(file='ghost.png')
root.mainloop()
Kisebb hibák javítása
Golyó a végén
Ha befejeződött a játszma, és lövünk egyet, akkor megjelenik egy golyó. Megoldás: a key_pressed() függvény elejére (a global után) szúrjuk be az alábbi két sort:
Beragadt űrhajó
Ha véletlenül egyszerre megnyomjuk a jobb és a bal nyilat, akkor nem halad tovább az űrhajó mindaddig, amíg el nem engedjük, és újra le nem nyomjuk. Ennek auz oka a következő:
- Lenyomjuk és nyomva tartjuk a bal nyilat. Az űrhajó left állapotba kerül.
- Lenyomjuk és nyomva tartjuk a jobb nyilat. Az űrhajó right állapotba kerül.
- Elengedjük a bal nyilat. Az űrhajó stand állapotba kerül.
- Nyomva tartjuk a jobb nyilat. Mivel nincs változás, az űrhajó stand állapotban marad. Újra el kell engedni és meg kell nyomni ahhoz, hogy haladjon.
A megoldás egy kicsit bonyolultabb. Ki kell törölni a rocketship_state változót. Ehelyett a következőket szúrjuk be. Hozzunk létre két globális változót, ami azt jelzi, hogy a bal ill. a jobb nyíl le van-e nyomva:
left_pressed = False
right_pressed = False
A lenyomás vizsgálatakor (key_pressed) egyrészt jelezzük, hogy ezeket a változókat meg szeretnénk változtatni, másrészt a megfelelő gomb lenyomásakor állítsuk is be (a felesleges sorokat töröljük ki):
def key_pressed(event):
global left_pressed, right_pressed
[…]
if event.keysym == 'Left':
left_pressed = True
if event.keysym == 'Right':
right_pressed = True
Az elengedéskor (key_released) is állítsuk be megfelelően:
def key_released(event):
global left_pressed, right_pressed
if event.keysym == 'Left':
left_pressed = False
if event.keysym == 'Right':
right_pressed = False
A fő függvényben pedig (play) ne a rocketship_state-et vizsgáljuk, hanem a lenyomás állapotát:
if left_pressed and rocketship_coords[0] > 0:
canvas.move(rocketship, -1, 0)
if right_pressed and rocketship_coords[0] < 480:
canvas.move(rocketship, 1, 0)
Egész sok mindent meg kellett változtatnunk egyetlen apró hiba kijavítása érdekében.
from tkinter import *
import random
lives = 3
score = 0
counter = 0
left_pressed = False
right_pressed = False
ghosts = []
bullets = []
def key_pressed(event):
global left_pressed, right_pressed
if lives <= 0:
return
if event.keysym == 'Left':
left_pressed = True
if event.keysym == 'Right':
right_pressed = True
if event.char == ' ':
rocketship_coords = canvas.coords(rocketship)
position_x = rocketship_coords[0] - 10
position_y = rocketship_coords[1] - 50
bullet = canvas.create_oval(
position_x,
position_y,
position_x + 20,
position_y + 20,
width=3,
outline='black',
fill='yellow'
)
bullets.append(bullet)
def key_released(event):
global left_pressed, right_pressed
if event.keysym == 'Left':
left_pressed = False
if event.keysym == 'Right':
right_pressed = False
def play():
global counter
global lives
global score
counter = counter + 1
rocketship_coords = canvas.coords(rocketship)
if left_pressed and rocketship_coords[0] > 0:
canvas.move(rocketship, -1, 0)
if right_pressed and rocketship_coords[0] < 480:
canvas.move(rocketship, 1, 0)
deleted_bullets = []
for bullet in bullets:
if canvas.coords(bullet)[1] > 0:
canvas.move(bullet, 0, -1)
else:
canvas.delete(bullet)
deleted_bullets.append(bullet)
for deleted_bullet in deleted_bullets:
bullets.remove(deleted_bullet)
ghosts_to_delete = []
bullets_to_delete = []
for ghost_struct in ghosts:
ghost = ghost_struct['ghost']
ghost_coords = canvas.coords(ghost)
for bullet in bullets:
bullet_coords = canvas.coords(bullet)
coord_diff_x = abs(bullet_coords[0] - ghost_coords[0])
coord_diff_y = abs(bullet_coords[1] - ghost_coords[1])
if coord_diff_x < 20 and coord_diff_y < 20:
ghosts_to_delete.append(ghost_struct)
bullets_to_delete.append(bullet)
score = score + 1
score_nr_label['text'] = str(score)
for ghost_to_delete in ghosts_to_delete:
canvas.delete(ghost_to_delete['ghost'])
ghosts.remove(ghost_to_delete)
for bullet_to_delete in bullets_to_delete:
canvas.delete(bullet_to_delete)
bullets.remove(bullet_to_delete)
if counter % 100 == 0:
ghost = canvas.create_image(random.randint(0, 480), 0, image=ghost_image)
direction = random.randint(-2, 2)
ghost_struct = {
'ghost': ghost,
'direction': direction,
}
ghosts.append(ghost_struct)
deleted_ghosts = []
hit = False
for ghost_struct in ghosts:
ghost = ghost_struct['ghost']
direction = ghost_struct['direction']
ghost_coords = canvas.coords(ghost)
if ghost_coords[1] < 360:
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)
else:
canvas.delete(ghost)
deleted_ghosts.append(ghost_struct)
coord_diff_x = abs(ghost_coords[0] - rocketship_coords[0])
coord_diff_y = abs(ghost_coords[1] - rocketship_coords[1])
if coord_diff_x <= 40 and coord_diff_y <= 40:
hit = True
lives = lives - 1
lives_nr_label['text'] = str(lives)
for deleted_ghost in deleted_ghosts:
ghosts.remove(deleted_ghost)
if hit:
for ghost_struct in ghosts:
canvas.delete(ghost_struct['ghost'])
ghosts.clear()
for bullet in bullets:
canvas.delete(bullet)
bullets.clear()
if lives <= 0:
canvas.create_text(240, 180, text='VÉGE', fill='yellow', font=('Helvetica', 50))
else:
root.after(2, play)
root = Tk()
root.title('Űrhajós játék')
root.bind('<KeyPress>', key_pressed)
root.bind('<KeyRelease>', key_released)
root.after(2, play)
info_frame = Frame(root)
lives_str_label = Label(master=info_frame, text='Életek száma:')
lives_str_label.grid(column=0, row=0)
lives_nr_label = Label(master=info_frame, text=str(lives))
lives_nr_label.grid(column=1, row=0)
score_str_label = Label(master=info_frame, text='Pontszám:')
score_str_label.grid(column=0, row=1)
score_nr_label = Label(master=info_frame, text=str(score))
score_nr_label.grid(column=1, row=1)
info_frame.pack()
canvas = Canvas(root, width=480, height=360, bg='black')
canvas.pack()
rocketship_image = PhotoImage(file='rocketship.png')
rocketship = canvas.create_image(240, 310, image=rocketship_image)
ghost_image = PhotoImage(file='ghost.png')
root.mainloop()
Újraindítás
Látszólag egyszerű, ám nagyon sok helyen bele kell nyúlni a kódba, és sok a buktató.
Először is hozzuk létre a nyomógombot, közvetlenül az információs rész alatt:
restart_button = Button(master=root, text='Újraindít', command=init, state='disabled')
restart_button.pack()
Fontos, hogy alapból inaktív legyen (state='disabled'), különben a fő ciklust is le kellene állítani.
Tehát az init függvény fog meghívódni, ha rákattintunk. Ekkor alapértelmezésre kell állítani a változókat. Ezt érdemes úgy megírni, hogy eleve az induláskor is meghvíjuk, ám vannak részek, amelyek csak a második indítástól érdekesek:
- a szellemek törlése,
- a golyók törlése,
- az űrhajó alaphelyzetbe állítása.
Ennek tehát lesz egy paramétere, amellyel megmondjuk, hogy ez az első futtatás-e, vagy nem. Alapértelmezett értéket is fogunk neki adni.
Töröljük ki az elejéről az alábbi sorokat:
lives = 3
score = 0
counter = 0
left_pressed = False
right_pressed = False
ghosts = []
bullets = []
Az init() függvény a következő:
def init(first_run=False):
global lives, score, counter, left_pressed, right_pressed, ghosts, bullets
if not first_run:
for ghost_struct in ghosts:
canvas.delete(ghost_struct['ghost'])
for bullet in bullets:
canvas.delete(bullet)
rocketship_coords = canvas.coords(rocketship)
canvas.move(rocketship, 240 - rocketship_coords[0], 310 - rocketship_coords[1])
lives = 3
score = 0
counter = 0
left_pressed = False
right_pressed = False
ghosts = []
bullets = []
lives_nr_label['text'] = str(lives)
score_nr_label['text'] = str(score)
restart_button['state'] = 'disabled'
canvas.itemconfigure(end_text, state='hidden')
root.after(2, play)
Magyarázat:
- Először megadjuk a globális változókat, amelyeket itt hozunk létre.
- Ha nem az első futásról van szó, akkor töröljük a szellemeket és a golyókat, valamint alaphelyzetbe állítjuk az űrhajót.
- Beállítjuk a korábbi lépésben törölt adatokat: az életek számát, a pontszámot, a számlálót, a gomb lenyomások állapotát, a szellemek és a golyók listáját.
- Át kell kicsit rendezni a főprogramot (ld. lejjebb); emiatt csak itt tudjuk megjeleníteni az életek számát és a pontszámot.
- Ugyancsak az átszervezés miatt nem a végén hozzuk létre a VÉGE feliratot, hanem már itt, láthatatlanná tesszük (state='hidden'), és szükség esetén ismét láthatóvá.
- Innen indítjuk a fő ciklust.
A fő ciklusban ha az életek száma elfogyott, akkor aktiváljuk az új játék nyomógombot, és nem létrehozzuk a VÉGE feliratot, hanem megjelenítjük (itt csak a második és harmadik sor új ill. módosult):
if lives <= 0:
restart_button['state'] = 'active'
canvas.itemconfigure(end_text, state='normal')
else:
root.after(2, play)
A végén a root.after(2, play) sort ki kell törölni, az átkerült a fenti függvénybe.
Mivel még nem áll rendelkezésre, nem írjuk ki az életek számát és a pontszámot sem. A módosított kódrészlet:
lives_str_label = Label(master=info_frame, text='Életek száma:')
lives_str_label.grid(column=0, row=0)
lives_nr_label = Label(master=info_frame)
lives_nr_label.grid(column=1, row=0)
score_str_label = Label(master=info_frame, text='Pontszám:')
score_str_label.grid(column=0, row=1)
score_nr_label = Label(master=info_frame)
score_nr_label.grid(column=1, row=1)
Miután létrehoztuk a vásznat, adjun hozzá a láthatatlan (state='hidden') VÉGE feliratot:
end_text = canvas.create_text(240, 180, text='VÉGE', fill='yellow', font=('Helvetica', 50), state='hidden')
Közvetlenül a root.mainloop() előtt hívjuk meg az inicializálást:
Mivel az életek száma és a pontszám csak ekkor jön létre, korábban nem tudtuk beállítani. Ám az inicializálás meghívását viszont csak a vászon létrehozása utánra tehetjük.Szóval nem egyszerű! És ezzel nem kezeltük azt a problémát, hogy ha futás közben kattintana a játékos az újraindításra, akkor helytelenül működne (emiatt állítottuk inaktívra). Egyetlen aprónak tűnő módosítás igen sok aprólékos változtatást tett szükségessé.
from tkinter import *
import random
def key_pressed(event):
global left_pressed, right_pressed
if lives <= 0:
return
if event.keysym == 'Left':
left_pressed = True
if event.keysym == 'Right':
right_pressed = True
if event.char == ' ':
rocketship_coords = canvas.coords(rocketship)
position_x = rocketship_coords[0] - 10
position_y = rocketship_coords[1] - 50
bullet = canvas.create_oval(
position_x,
position_y,
position_x + 20,
position_y + 20,
width=3,
outline='black',
fill='yellow'
)
bullets.append(bullet)
def key_released(event):
global left_pressed, right_pressed
if event.keysym == 'Left':
left_pressed = False
if event.keysym == 'Right':
right_pressed = False
def play():
global counter
global lives
global score
counter = counter + 1
rocketship_coords = canvas.coords(rocketship)
if left_pressed and rocketship_coords[0] > 0:
canvas.move(rocketship, -1, 0)
if right_pressed and rocketship_coords[0] < 480:
canvas.move(rocketship, 1, 0)
deleted_bullets = []
for bullet in bullets:
if canvas.coords(bullet)[1] > 0:
canvas.move(bullet, 0, -1)
else:
canvas.delete(bullet)
deleted_bullets.append(bullet)
for deleted_bullet in deleted_bullets:
bullets.remove(deleted_bullet)
ghosts_to_delete = []
bullets_to_delete = []
for ghost_struct in ghosts:
ghost = ghost_struct['ghost']
ghost_coords = canvas.coords(ghost)
for bullet in bullets:
bullet_coords = canvas.coords(bullet)
coord_diff_x = abs(bullet_coords[0] - ghost_coords[0])
coord_diff_y = abs(bullet_coords[1] - ghost_coords[1])
if coord_diff_x < 20 and coord_diff_y < 20:
ghosts_to_delete.append(ghost_struct)
bullets_to_delete.append(bullet)
score = score + 1
score_nr_label['text'] = str(score)
for ghost_to_delete in ghosts_to_delete:
canvas.delete(ghost_to_delete['ghost'])
ghosts.remove(ghost_to_delete)
for bullet_to_delete in bullets_to_delete:
canvas.delete(bullet_to_delete)
bullets.remove(bullet_to_delete)
if counter % 100 == 0:
ghost = canvas.create_image(random.randint(0, 480), 0, image=ghost_image)
direction = random.randint(-2, 2)
ghost_struct = {
'ghost': ghost,
'direction': direction,
}
ghosts.append(ghost_struct)
deleted_ghosts = []
hit = False
for ghost_struct in ghosts:
ghost = ghost_struct['ghost']
direction = ghost_struct['direction']
ghost_coords = canvas.coords(ghost)
if ghost_coords[1] < 360:
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)
else:
canvas.delete(ghost)
deleted_ghosts.append(ghost_struct)
coord_diff_x = abs(ghost_coords[0] - rocketship_coords[0])
coord_diff_y = abs(ghost_coords[1] - rocketship_coords[1])
if coord_diff_x <= 40 and coord_diff_y <= 40:
hit = True
lives = lives - 1
lives_nr_label['text'] = str(lives)
for deleted_ghost in deleted_ghosts:
ghosts.remove(deleted_ghost)
if hit:
for ghost_struct in ghosts:
canvas.delete(ghost_struct['ghost'])
ghosts.clear()
for bullet in bullets:
canvas.delete(bullet)
bullets.clear()
if lives <= 0:
restart_button['state'] = 'active'
canvas.itemconfigure(end_text, state='normal')
else:
root.after(2, play)
def init(first_run=False):
global lives, score, counter, left_pressed, right_pressed, ghosts, bullets
if not first_run:
for ghost_struct in ghosts:
canvas.delete(ghost_struct['ghost'])
for bullet in bullets:
canvas.delete(bullet)
rocketship_coords = canvas.coords(rocketship)
canvas.move(rocketship, 240 - rocketship_coords[0], 310 - rocketship_coords[1])
lives = 3
score = 0
counter = 0
left_pressed = False
right_pressed = False
ghosts = []
bullets = []
lives_nr_label['text'] = str(lives)
score_nr_label['text'] = str(score)
restart_button['state'] = 'disabled'
canvas.itemconfigure(end_text, state='hidden')
root.after(2, play)
root = Tk()
root.title('Űrhajós játék')
root.bind('<KeyPress>', key_pressed)
root.bind('<KeyRelease>', key_released)
info_frame = Frame(root)
lives_str_label = Label(master=info_frame, text='Életek száma:')
lives_str_label.grid(column=0, row=0)
lives_nr_label = Label(master=info_frame)
lives_nr_label.grid(column=1, row=0)
score_str_label = Label(master=info_frame, text='Pontszám:')
score_str_label.grid(column=0, row=1)
score_nr_label = Label(master=info_frame)
score_nr_label.grid(column=1, row=1)
info_frame.pack()
restart_button = Button(master=root, text='Újraindít', command=init, state='disabled')
restart_button.pack()
canvas = Canvas(root, width=480, height=360, bg='black')
canvas.pack()
rocketship_image = PhotoImage(file='rocketship.png')
rocketship = canvas.create_image(240, 310, image=rocketship_image)
ghost_image = PhotoImage(file='ghost.png')
end_text = canvas.create_text(240, 180, text='VÉGE', fill='yellow', font=('Helvetica', 50), state='hidden')
init(True)
root.mainloop()
Refaktorálás
A kód lényegében készen van. Ám eléggé nehézkessé vált a karbantartása: pl. egyetlen nyomógomb létrehozásához is nagyon sok helyen bele kellett nyúlni. A fő ciklus különösen hosszú lett, nehezen áttekinthető. Eljött az idő a kód olyan szintű átalakítására, ami új funkciót nem visz bele, az olvashatóságit viszont javítja. A következőket tesszük bele:
- A fő programot (ami most "csak úgy" oda van írva) külön függvénybe tesszük. Az igazi főprogram tehát csak annak a függvénynek a meghívása lesz. Viszont itt globálissá kell tennünk azokat a változókat, amelyeket a többi függvényből is használni szeretnénk (akár csak olvasni).
- A play() függvényt logikai egységekre bontjuk: üres sortokat és megjegyzéseket írunk a logikai egységek közé.
A végeredmény:
from tkinter import *
import random
def key_pressed(event):
global left_pressed, right_pressed
if lives <= 0:
return
if event.keysym == 'Left':
left_pressed = True
if event.keysym == 'Right':
right_pressed = True
if event.char == ' ':
rocketship_coords = canvas.coords(rocketship)
position_x = rocketship_coords[0] - 10
position_y = rocketship_coords[1] - 50
bullet = canvas.create_oval(
position_x,
position_y,
position_x + 20,
position_y + 20,
width=3,
outline='black',
fill='yellow'
)
bullets.append(bullet)
def key_released(event):
global left_pressed, right_pressed
if event.keysym == 'Left':
left_pressed = False
if event.keysym == 'Right':
right_pressed = False
def play():
global counter, lives, score
rocketship_coords = canvas.coords(rocketship)
if left_pressed and rocketship_coords[0] > 0:
canvas.move(rocketship, -1, 0)
if right_pressed and rocketship_coords[0] < 480:
canvas.move(rocketship, 1, 0)
deleted_bullets = []
for bullet in bullets:
if canvas.coords(bullet)[1] > 0:
canvas.move(bullet, 0, -1)
else:
canvas.delete(bullet)
deleted_bullets.append(bullet)
for deleted_bullet in deleted_bullets:
bullets.remove(deleted_bullet)
ghosts_to_delete = []
bullets_to_delete = []
for ghost_struct in ghosts:
ghost = ghost_struct['ghost']
ghost_coords = canvas.coords(ghost)
for bullet in bullets:
bullet_coords = canvas.coords(bullet)
coord_diff_x = abs(bullet_coords[0] - ghost_coords[0])
coord_diff_y = abs(bullet_coords[1] - ghost_coords[1])
if coord_diff_x < 20 and coord_diff_y < 20:
ghosts_to_delete.append(ghost_struct)
bullets_to_delete.append(bullet)
score = score + 1
score_nr_label['text'] = str(score)
for ghost_to_delete in ghosts_to_delete:
canvas.delete(ghost_to_delete['ghost'])
ghosts.remove(ghost_to_delete)
for bullet_to_delete in bullets_to_delete:
canvas.delete(bullet_to_delete)
bullets.remove(bullet_to_delete)
counter = counter + 1
if counter % 100 == 0:
ghost = canvas.create_image(random.randint(0, 480), 0, image=ghost_image)
direction = random.randint(-2, 2)
ghost_struct = {
'ghost': ghost,
'direction': direction,
}
ghosts.append(ghost_struct)
deleted_ghosts = []
hit = False
for ghost_struct in ghosts:
ghost = ghost_struct['ghost']
direction = ghost_struct['direction']
ghost_coords = canvas.coords(ghost)
if ghost_coords[1] < 360:
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)
else:
canvas.delete(ghost)
deleted_ghosts.append(ghost_struct)
coord_diff_x = abs(ghost_coords[0] - rocketship_coords[0])
coord_diff_y = abs(ghost_coords[1] - rocketship_coords[1])
if coord_diff_x <= 40 and coord_diff_y <= 40:
hit = True
lives = lives - 1
lives_nr_label['text'] = str(lives)
for deleted_ghost in deleted_ghosts:
ghosts.remove(deleted_ghost)
if hit:
for ghost_struct in ghosts:
canvas.delete(ghost_struct['ghost'])
ghosts.clear()
for bullet in bullets:
canvas.delete(bullet)
bullets.clear()
if lives <= 0:
restart_button['state'] = 'active'
canvas.itemconfigure(end_text, state='normal')
else:
root.after(2, play)
def init(first_run=False):
global lives, score, counter, left_pressed, right_pressed, ghosts, bullets
if not first_run:
for ghost_struct in ghosts:
canvas.delete(ghost_struct['ghost'])
for bullet in bullets:
canvas.delete(bullet)
rocketship_coords = canvas.coords(rocketship)
canvas.move(rocketship, 240 - rocketship_coords[0], 310 - rocketship_coords[1])
lives = 3
score = 0
counter = 0
left_pressed = False
right_pressed = False
ghosts = []
bullets = []
lives_nr_label['text'] = str(lives)
score_nr_label['text'] = str(score)
restart_button['state'] = 'disabled'
canvas.itemconfigure(end_text, state='hidden')
root.after(2, play)
def start():
global root, canvas, lives_nr_label, score_nr_label, rocketship, ghost_image, end_text, restart_button
root = Tk()
root.title('Űrhajós játék')
root.bind('<KeyPress>', key_pressed)
root.bind('<KeyRelease>', key_released)
info_frame = Frame(root)
lives_str_label = Label(master=info_frame, text='Életek száma:')
lives_str_label.grid(column=0, row=0)
lives_nr_label = Label(master=info_frame)
lives_nr_label.grid(column=1, row=0)
score_str_label = Label(master=info_frame, text='Pontszám:')
score_str_label.grid(column=0, row=1)
score_nr_label = Label(master=info_frame)
score_nr_label.grid(column=1, row=1)
info_frame.pack()
restart_button = Button(master=root, text='Újraindít', command=init, state='disabled')
restart_button.pack()
canvas = Canvas(root, width=480, height=360, bg='black')
canvas.pack()
rocketship_image = PhotoImage(file='rocketship.png')
rocketship = canvas.create_image(240, 310, image=rocketship_image)
ghost_image = PhotoImage(file='ghost.png')
end_text = canvas.create_text(240, 180, text='VÉGE', fill='yellow', font=('Helvetica', 50), state='hidden')
init(True)
root.mainloop()
start()
Utolsó gondolatok
A Scratch után kifejezetten nehéz volt Pythonban is elkészíteni ugyanazt a játékot. Sokkal hosszabb és bonyolultabb lett a kód. Ám míg a Scratch-ben ezzel megközelítettük a lehetőségek határát, addig Pythonban épp, hogy csak bekukkantottunk a lehetőségek óriási tárházába.