Aceasta este o parte din cinci serii de tutoriale despre realizarea de jocuri cu Python 3 și PyGame. În partea a patra am detectat coliziuni, am răspuns la minge care lovesc diferite obiecte de joc și am creat un meniu de joc cu butoane personalizate.
În această ultimă parte, vom aborda diverse subiecte, cum ar fi jocul final, gestionarea vieții și scorului, efecte sonore, muzică și chiar un sistem de efecte speciale flexibile. Pentru desert, vom discuta potențialele îmbunătățiri și direcțiile viitoare.
În cele din urmă, jocul trebuie să se încheie. În această versiune de Breakout, jocul se termină în unul din două moduri: fie jucătorul își pierde toată viața, fie lovesc toate cărămizile. Nu există un nivel următor (deși ar fi ușor să adăugați).
Campul game_over al clasei de joc este setat la Fals în __ metodei __init ()
metodă a clasei de joc. Bucla principală merge rotundă și rotundă până la joc încheiat
variabila este setată la True:
Clasa jocului: def __init __ (sine, legendă, lățime, înălțime, nume de back_image_file, frame_rate): ... self.game_over = False ... def run (self): în timp ce nu self.game_over: self.surface.blit (self.background_image, , 0)) self.handle_events () self.update () self.draw () pygame.display.update () self.clock.tick (self.frame_rate)
Totul se întâmplă în clasa Breakout în următoarele cazuri:
def on_quit (buton): self.game_over = Adevărat self.is_game_running = False def handle_ball_collisions (self): ... # Hit floor dacă self.ball.top> c.screen_height: self.lives - = 1 dacă self.lives == 0 : self.game_over = Adevărat dacă nu self.bricks: self.show_message ('YOU WIN !!!', centralized = True) self.is_game_running = False self.game_over = Ajustare adevărată return def (self): ... dacă nu este auto. cărămizi: self.show_message ('YOU WIN !!!', centralizat = adevărat) self.is_game_running = False self.game_over = True return
De obicei, atunci când jocul se termină, nu vrem ca fereastra jocului să dispară în aer subțire. Excepția este dacă ați făcut clic pe butonul QUIT din meniu. Cand jucatorul isi pierde ultima viata, Breakout afiseaza jocul traditional "GAME OVER!" mesaj, iar când jucătorul câștigă, afișează "YOU WIN!"
show_message ()
funcția este utilizată în ambele cazuri. Afișează textul deasupra ecranului curent (jocul va fi întrerupt) și așteaptă câteva secunde înainte de a se întoarce. În următoarea iterație a jocului, verificarea pentru joc încheiat
câmpul va determina că este adevărat, iar programul va ieși.
Aici este show_message ()
funcţie:
def_message (auto, text, culoare = culori.WHITE, font_name = "Arial", font_size = 20, centralizat = False): message = TextObject (c.screen_width // 2, font_size) auto.draw () message.draw (self.surface, centralizat) pygame.display.update () time.sleep (c.message_duration)
În această versiune, nu păstrez scorul mare deoarece există doar un nivel, iar scorul tuturor va fi același dacă va șterge toate cărămizile. În general, se poate face la nivel local prin stocarea scorului ridicat într-un fișier și apoi afișarea unui alt mesaj dacă jucătorul a spart scorul mare.
Jocurile sunt o experiență audio-vizuală. Cele mai multe jocuri au efecte sonore care sunt biti de sunet scurt care se joacă atunci când jucătorul ucide un monstru, găsește o anumită comoară sau explodează oribil. Unele jocuri au și muzică de fundal, care contribuie la atmosferă. Breakout are numai efecte sonore, dar vă voi arăta cum să jucați muzică de fundal în jocurile dvs..
Aveți nevoie de fișiere audio (similare fișierelor imagine) pentru a reda efecte sonore. Aceste fișiere pot fi în formate .wav, .mp3 sau .ogg. Breakout își păstrează efectele sonore în efecte sonore
pliant:
~ / git / pygame-breakout> arbore sound_effects / sound_effects / ├── brick_hit.wav ├── effect_done.wav ├─────────────────────────────────────────────────────────────────────────────────────────────
Să vedem cum sunt încărcate și redate aceste efecte sonore la momentul potrivit. Mai întâi, pentru a reda efecte sonore (sau muzică de fundal), trebuie să inițializați sistemul de sunet al lui Pygame. Acest lucru se întâmplă în clasa de joc: pygame.mixer.pre_init (44100, 16, 2, 4096)
Apoi, în clasa Breakout, toate efectele sonore sunt încărcate din configurație în pygame.mixer.Sound
obiect și sunt stocate într-un dicționar:
# În config.py sounds_effects = dict (brick_hit = "sound_effects / brick_hit.wav", effect_done = "sound_effects / effect_done.wav", paddle_hit = "sound_effects / paddle_hit.wav", level_complete = "sound_effects / level_complete.wav" # În breakout.py clasa Breakout (joc): def __init __ (self): ... self.sound_effects = nume: pygame.mixer.Sound (sunet) pentru nume, sunet în c.sounds_effects.items () ...
Acum, putem juca efectele sonore când se întâmplă ceva interesant. De exemplu, atunci când mingea lovește o cărămidă:
# Caramida pentru cărămidă în caramida: marginea = intersect (caramida, auto.bal) dacă nu marginea: continuați self.sound_effects ['brick_hit'] play ()
Efectul sonor joacă asincron, ceea ce înseamnă că jocul nu se îngheață în timp ce sunetul este redat. Efectele sonore multiple pot fi redate simultan.
Înregistrarea efectelor dvs. sonore este atât de simplă și de plină de satisfacții. Spre deosebire de designul activelor vizuale, acesta nu necesită mult talent. Oricine poate spune "Kaboom!" sau "Boing" sau strigă "Ești mort, mai mult noroc data viitoare!"
Adesea îi întreb pe copiii mei să înregistreze efecte sonore, precum și mesaje vocale care însoțesc mesaje text cum ar fi "YOU WIN!" sau "GAME OVER!" Imaginația ta este singura limitare.
Muzica de background ar trebui să joace în mod constant. Teoretic, poți avea un efect de sunet foarte rău, dar o abordare mai comună este pur și simplu să joci muzica de fundal într-o buclă. Fișierele muzicale pot fi formate .wav, .mp3 sau .midi. Iată cum se face:
muzică = pygame.mixer.music.load ('background_music.mp3') pygame.mixer.music.play (-1, 0.0)
Aveți posibilitatea să aveți doar o piesă de muzică de fundal care se joacă la un moment dat. Dar mai multe efecte sonore pot juca peste muzica de fundal. Este vorba despre amestecare.
Să fim fantezie. Ruperea cărămizilor cu o minge este rece, dar se îmbătrânește destul de repede. Ce zici de un sistem generic de efecte speciale? Vom dezvolta un sistem extensibil de efecte speciale care sunt asociate cu anumite cărămizi și se vor activa atunci când mingea lovește cărămida.
Iată planul. Efectele au o durată de viață. Efectul incepe atunci cand caramida se rupe si se termina cand durata efectului scade. Ce se întâmplă dacă mingea lovește o altă cărămidă cu efect special? Teoretic, ai putea avea efecte complexe, dar pentru a simplifica lucrurile pentru implementarea inițială, efectul activ se va opri și noul efect îi va lua locul.
Un efect special poate fi definit cel mai generic ca două funcții. Prima funcție activează efectul, iar a doua funcție o resetează. Vrem să atașăm efectele cărămizilor și să le clarificăm jucătorului cărămizile speciale, astfel încât să încerce să le lovească sau să le evite în anumite puncte.
Următorul dict din modulul breakout.py definește efectele noastre speciale. Fiecare efect are un nume (de exemplu, long_paddle) și o valoare, care constă în culoarea cărămizii pe care o va avea caramida, precum și cele două funcții. Funcțiile sunt definite ca funcții lambda care iau o instanță de joc, care include tot ce are un efect special în Breakout care ar putea să se schimbe.
special_effects = dict (long_paddle = (culori.ORANGE, lambda g: g.paddle.bounds.inflate_ip (c.paddle_width // 2, 0), lambda g: g.paddle.bounds.inflate_ip (-c.paddle_width // 2 ), Slow_ball = (colors.AQUAMARINE2, lambda g: g.change_ball_speed (-1), lambda g: g.change_ball_speed (1)), tripple_points = (colors.DARKSEAGREEN4, lambda g: g.set_points_per_brick , lambda g: g.set_points_per_brick (1)), extra_life = (culori.GOLD1, lambda g: g.add_life (), lambda g: Niciuna))
Atunci când cărămizile sunt create, ele au o schimbare pentru a fi atribuite unul dintre efectele speciale. Iată codul:
Definiți cre_bricks (auto): w = c.brick_width h = c.brick_height brick_count = c.screen_width // (w + 1) offset_x = (c.screen_width - brick_count * (w + 1)) // 2 bricks = pentru randul în intervalul (c.row_count): pentru col în intervalul (brick_count): effect = Niciunul brick_color = c.brick_color index = random.randint (0, 10) dacă indexul < len(special_effects): x = list(special_effects.values())[index] brick_color = x[0] effect = x[1:] brick = Brick(offset_x + col * (w + 1), c.offset_y + row * (h + 1), w, h, brick_color, effect) bricks.append(brick) self.objects.append(brick) self.bricks = bricks
Clasa Brick are un câmp de efect care este de obicei Niciuna, dar poate obține (30% șansă) unul dintre efectele speciale definite mai sus. Rețineți că acest cod nu cunoaște efectele disponibile. Pur și simplu obține efectul și culoarea cărămizii și le atribuie dacă este necesar.
În această versiune de Breakout, am declanșarea efectelor numai atunci când o cărămidă este lovită, dar vă puteți imagina alte scenarii care ar putea declanșa evenimente. Efectul anterior este resetat (dacă există unul), iar apoi se lansează noul efect. Funcția de resetare și timpul de pornire a efectului sunt stocate pentru ulterior.
dacă brick.special_effect nu este Niciunul: # Resetați efectul anterior dacă este cazul dacă self.reset_effect nu este Nici unul: self.reset_effect (self) # Trigger efect special self.effect_start_time = datetime.now () brick.special_effect [0] (self) # Setați funcția efectului actual de resetare self.reset_effect = brick.special_effect [1]
Dacă nu s-a declanșat niciun efect nou, este necesar să resetăm evenimentul curent când expiră. Acest lucru se întâmplă în Actualizați()
metodă. În fiecare cadru, funcția de resetare a efectului curent a fost atribuită funcției reset_effect
camp. Dacă timpul de la începutul efectului curent a depășit durata efectului, atunci reset_effect ()
este apelată funcția și reset_effect
câmpul este setat la Nici unul (adică nu există niciun efect activ acum).
# Resetarea efectului special dacă este necesar dacă self.reset_effect: elapsed = datetime.now () - self.effect_start_time dacă a trecut> = timedelta (secunde = c.effect_duration): self.reset_effect (self) self.reset_effect =
Efectul cu paletă lungă funcționează prin umflarea cuțitului cu 50%. Funcția de resetare o restituie doar la normal. Culoarea cărămizii este Orange:
long_paddle = (culori.ORANGE, lambda g: g.paddle.bounds.inflate_ip (c.paddle_width // 2, 0), lambda g: g.paddle.bounds.inflate_ip (-c.paddle_width // 2, 0)),
Un alt efect care ajută la urmărirea mingii este efectul cu bilă lentă, care încetinește pur și simplu viteza mingii cu o singură unitate. Culoarea cărămizii este Aquamarine.
slow_ball = (culori.AQUAMARINE2, lambda g: g.change_ball_speed (-1), lambda g: g.change_ball_speed (1)),
Dacă doriți numere mari, vă va plăcea efectul triplu de puncte care vă oferă trei puncte pentru fiecare cărămidă pe care ați lovit-o în loc de un punct standard. Culoarea cărămizii este verde închis.
tripple_points = (culori.DARKSEAGREEN4, lambda g: g.set_points_per_brick (3), lambda g: g.set_points_per_brick (1)),
În cele din urmă, un efect foarte util este efectul vieții suplimentare. Aceasta vă oferă o viață suplimentară. Nu este nevoie de resetare. Culoarea cărămizii este de aur.
extra_life = (culori.GOLD1, lambda g: g.add_life (), lambda g: niciuna))
Există mai multe direcții naturale pentru a extinde Breakout. Dacă sunteți interesat să vă încercați să adăugați mai multe capabilități și caracteristici, iată câteva idei.
Pentru a face Breakout un joc serios, este nevoie de nivele. Redarea unui singur ecran nu este suficientă. La începutul fiecărui nivel, veți restabili ecranul, dar păstrați scorul și trăiți așa cum este. Pentru a face jocul mai greu, puteți crește ușor viteza mingii la fiecare nivel sau adăugați un alt strat de cărămizi.
Adăugarea unei a doua mingi ca efect temporar este obligată să creeze o mulțime de haos. Partea dificilă aici este aceea de a trata ambele mingi ca fiind egale, indiferent de cine a fost originalul. Când o minge dispare, jocul continuă cu singura minge care a mai rămas. Nu se pierde viața.
Când aveți niveluri cu dificultăți în creștere, scorul mare devine un premiu râvnit. Puteți păstra scorul mare într-un fișier pentru a persista între jocuri. Când un jucător sparge scorul mare, puteți adăuga un mic pizazz sau lăsați-i să-și scrie numele (în mod tradițional, doar trei caractere).
În implementarea actuală, toate efectele speciale sunt legate de cărămizi, dar puteți adăuga efecte (bune și rele) care coboară din cer și jucătorul trebuie să le colecteze sau să le evite.
Dezvoltarea Breakout folosind Python 3 și Pygame a fost o experiență super-plină de satisfacții. Este o combinație foarte puternică pentru jocuri 2D (și jocuri 3D, de asemenea). Dacă vă place Python și doriți să vă faceți propriile jocuri, nu puteți merge în neregulă cu Pygame.
Cu siguranta planuiesc sa fac mai multe jocuri cu Python si Pygame.
În cele din urmă, rețineți că avem o mulțime de conținut Python disponibil pentru vânzare și pentru studiu pe piața Envato.