Costruire giochi con Python 3 e Pygame parte 1

Panoramica

Molti sviluppatori entrano nello sviluppo del software perché vogliono creare giochi. Non tutti possono essere sviluppatori di giochi professionali, ma ognuno può costruire i propri giochi per divertimento e forse profitto. In questa serie in cinque parti, ti mostrerò come creare giochi 2D per giocatore singolo usando Python 3 e l'eccellente framework Pygame. 

Costruiremo una versione del classico gioco Breakout. Quando tutto è stato detto e fatto, avrai una chiara comprensione di ciò che serve per creare il tuo gioco, avrai familiarità con le capacità di Pygame e avrai un gioco di esempio. 

Ecco le funzionalità e le funzionalità che implementeremo:

  • semplice GameObject generico e TextObject
  • semplice oggetto di gioco generico
  • semplice pulsante generico
  • file di configurazione
  • gestione degli eventi di tastiera e mouse
  • mattoni, pagaia e palla
  • gestione del movimento del paddle
  • gestendo le collisioni della palla con tutto
  • immagine di sfondo
  • effetti sonori
  • sistema di effetti speciali estensibile

Cosa tu non dovrebbe aspettarsi è un gioco visivamente piacevole. Sono un programmatore e non un artista. Mi preoccupo di più dell'estetica del codice. Il risultato del mio design visivo può essere abbastanza scioccante. Tra l'altro, se vuoi migliorare l'aspetto di questa versione di Breakout, lo hai tonnellate di spazio per il miglioramento. Con questo terribile avvertimento, ecco uno screenshot:

Il codice sorgente completo è disponibile qui.

Introduzione rapida alla programmazione del gioco

I giochi riguardano lo spostamento dei pixel sullo schermo e il rumore. Praticamente tutti i video / giochi per computer hanno la maggior parte dei seguenti elementi. Al di fuori di questo articolo ci sono giochi client-server e giochi multi-player, che coinvolgono anche molta programmazione di rete.

Ciclo principale

Il ciclo principale di un gioco esegue e aggiorna lo schermo a intervalli fissi. Questa è la tua frequenza dei fotogrammi e impone quanto siano fluide le cose. In genere, i giochi aggiornano lo schermo da 30 a 60 volte al secondo. Se si va più lentamente, gli oggetti sullo schermo sembreranno a scatti. 

All'interno del ciclo principale, ci sono tre attività principali: gestione degli eventi, aggiornamento dello stato del gioco e disegno dello stato corrente dello schermo.

Gestione degli eventi

Gli eventi in un gioco consistono in tutto ciò che accade al di fuori del controllo del codice del gioco, ma è rilevante per il funzionamento del gioco. Ad esempio, se in Breakout il giocatore preme il tasto freccia sinistra, il gioco deve spostare la paddle a sinistra. Gli eventi tipici sono la pressione di tasti (e rilasci), il movimento del mouse, i clic del pulsante del mouse (specialmente nei menu) e gli eventi del timer (ad esempio, un effetto speciale scade dopo 10 secondi).

Stato di aggiornamento

Il nucleo di ogni gioco è il suo stato: le cose che tiene traccia e disegna sullo schermo. In Breakout, lo stato include la posizione di tutti i mattoni, la posizione e la velocità della palla e la posizione della pagaia, nonché le vite e il punteggio. 

C'è anche lo stato ausiliario che aiuta a gestire il gioco: 

  • Stiamo mostrando un menu ora? 
  • Il gioco è finito? 
  • Il giocatore ha vinto?

Disegno

Il gioco deve mostrare il suo stato sullo schermo. Ciò include il disegno di forme geometriche, immagini e testo.

Fisica del gioco

La maggior parte dei giochi simula un ambiente fisico. In Breakout, la palla rimbalza sugli oggetti e ha un molto sistema di fisica rigida corpo rigido sul posto (se si può chiamare così). 

I giochi più avanzati possono avere sistemi di fisica più sofisticati e realistici (in particolare i giochi 3D). Nota che alcuni giochi come i giochi di carte non hanno molta fisica, e questo è assolutamente soddisfacente. 

AI (intelligenza artificiale)

Ci sono molti giochi in cui si gioca contro un avversario di computer artificiale o avversari, o ci sono nemici che cercano di ucciderti o peggio. Queste fiabe dell'immaginazione del gioco si comportano spesso in modo apparentemente intelligente nel mondo del gioco. 

Ad esempio, i nemici ti inseguiranno e si renderanno conto della tua posizione. Breakout non presenta un'IA. Giochi contro i mattoni freddi e duri. Tuttavia, l'intelligenza artificiale nei giochi è spesso molto semplice e segue semplicemente regole semplici (o complesse) per ottenere risultati pseudo-intelligenti.

Riproduzione audio

La riproduzione dell'audio è un altro aspetto importante dei giochi. Ci sono in generale due tipi di audio: musica di sottofondo ed effetti sonori. In Breakout, mi concentro sugli effetti sonori che suonano brevemente quando accadono vari eventi. 

La musica di sottofondo è solo musica che viene riprodotta costantemente in background. Alcuni giochi non usano la musica di sottofondo, e alcuni lo cambiano ad ogni livello.

Vive, Punteggio e livelli

La maggior parte dei giochi ti dà una certa quantità di vite e quando finisci le vite, il gioco è finito. Spesso hai anche una colonna sonora che ti dà un'idea di quanto stai facendo bene e una motivazione per migliorare la prossima volta che giochi o semplicemente vantati ai tuoi amici delle tue abilità folli di Breakout. Molti giochi hanno livelli completamente diversi o aumentano il livello di difficoltà.

Incontra Pygame

Prima di immergerci e iniziare a implementare, impariamo un po 'su Pygame, che farà molto per noi.

Cos'è Pygame?

Pygame è un framework Python per la programmazione di giochi. È costruito su SDL e ha tutte le cose buone:

  • maturo
  • grande comunità
  • open source
  • piattaforme
  • buoni documenti
  • un sacco di giochi di esempio
  • facile da imparare

Installare Pygame

genere pip installa pygame per installarlo. Se hai bisogno di qualcos'altro, segui le istruzioni nella sezione Per iniziare del Wiki. Se esegui macOS Sierra come faccio io, potresti incontrare dei problemi. Sono stato in grado di installare Pygame senza problemi, e il codice sembrava funzionare bene, ma la finestra di gioco non si presentava mai. 

È una specie di seccatura quando si esegue una partita. Alla fine ho dovuto ricorrere a correre su Windows in una VM VirtualBox. Spero che, nel momento in cui leggerai questo articolo, il problema sarà risolto.

Architettura di gioco

I giochi devono gestire molte informazioni ed eseguire operazioni simili su molti oggetti. Breakout è un mini-gioco, ma provare a gestire tutto in un file sarebbe schiacciante. Invece, ho optato per creare una struttura di file e un'architettura adatta a giochi molto più grandi.

Directory e struttura dei file

├── Pipfile ├── Pipfile.lock ├── README.md ├── ball.py ├── breakout.py ├── brick.py ├── button.py ├── colors.py ├── config .py ├── game.py ├── game_object.py ├── immagini │ └── background.jpg ├── paddle.py ├── sound_effects │ ├── brick_hit.wav │ ├── effect_done.wav │ ├── level_complete.wav │ └── paddle_hit.wav └── text_object.py 

Pipfile e Pipfile.lock sono il modo moderno di gestire le dipendenze in Python. La directory images contiene immagini utilizzate dal gioco (solo l'immagine di sfondo in questa incarnazione), e la directory sound_effects contiene brevi clip audio usati come (hai indovinato) effetti sonori. 

I file ball.py, paddle.py e brick.py contengono codice specifico per ciascuno di questi oggetti di Breakout. Li coprirò in profondità più avanti nella serie. Il file text_object.py contiene il codice per visualizzare il testo sullo schermo e il file background.py contiene la logica di gioco specifica di Breakout. 

Tuttavia, ci sono diversi moduli che formano uno scheletro sciolto e generico. Le classi definite qui possono essere riutilizzate per altri giochi basati su Pygame.

La classe GameObject

Il GameObject rappresenta un oggetto visivo che sa come renderizzare se stesso, mantenere i suoi confini e muoversi. Pygame ha in effetti una classe Sprite che ha un ruolo simile, ma in questa serie voglio mostrare come le cose funzionano a un livello basso e non fare affidamento su troppa magia preconfezionata. Ecco la classe GameObject:

da pygame.rect import Rect class GameObject: def __init __ (self, x, y, w, h, speed = (0,0)): self.bounds = Rect (x, y, w, h) self.speed = speed @property def left (self): return self.bounds.left @property def right (self): return self.bounds.right @property def top (self): return self.bounds.top @property def bottom (self): return self.bounds.bottom @property def width (self): restituisce self.bounds.width @property def height (self): restituisce self.bounds.height @property def center (self): restituisce self.bounds.center @property def centerx (self): return self.bounds.centerx @property def centery (self): return self.bounds.centery def draw (self, surface): passa def move (self, dx, dy): self.bounds = self .bounds.move (dx, dy) def update (self): se self.speed == [0, 0]: return self.move (* self.speed) 

GameObject è progettato per fungere da classe base per altri oggetti. Espone direttamente molte delle proprietà del suo rettangolo self.bound e nel suo aggiornare() metodo sposta l'oggetto in base alla sua velocità corrente. Non fa nulla al suo interno disegnare() metodo, che dovrebbe essere sovrascritto dalle sottoclassi.

La classe di gioco

La classe di gioco è il cuore del gioco. Esegue il ciclo principale. Ha un sacco di funzionalità utili. Prendiamolo metodo per metodo.

Il __dentro__() il metodo inizializza Pygame stesso, il sistema di font e il mixer audio. Il motivo per cui devi fare tre chiamate diverse è perché non tutti i giochi Pygame usano tutti i componenti, quindi controlli quali sottosistemi usi e inizializzi solo quelli con i loro parametri specifici. Crea l'immagine di sfondo, la superficie principale (dove viene disegnato tutto) e l'orologio di gioco con la frequenza fotogrammi corretta. 

Il membro self.objects manterrà tutti gli oggetti di gioco che devono essere renderizzati e aggiornati. I vari gestori gestiscono gli elenchi della funzione del gestore che deve essere chiamata quando si verificano determinati eventi.

import pygame import sys dalle collezioni import defaultdict class Gioco: def __init __ (self, caption, width, height, back_image_filename, frame_rate): self.background_image = \ pygame.image.load (back_image_filename) self.frame_rate = frame_rate self.game_over = False self.objects = [] pygame.mixer.pre_init (44100, 16, 2, 4096) pygame.init () pygame.font.init () self.surface = pygame.display.set_mode ((width, height)) pygame. display.set_caption (caption) self.clock = pygame.time.Clock () self.keydown_handlers = defaultdict (list) self.keyup_handlers = defaultdict (list) self.mouse_handlers = [] 

Il aggiornare() e disegnare() i metodi sono molto semplici Semplicemente iterano su tutti gli oggetti di gioco gestiti e chiamano i loro metodi corrispondenti. Se due oggetti di gioco si sovrappongono, l'ordine nella lista degli oggetti determina quale oggetto sarà reso per primo, e l'altro lo coprirà parzialmente o completamente. 

 def update (self): per o in self.objects: o.update () def draw (self): per o in self.objects: o.draw (self.surface) 

Il handle_events () il metodo ascolta gli eventi generati da Pygame, come gli eventi di tasti e mouse. Per ogni evento, richiama tutte le funzioni del gestore che sono registrate per gestire questo tipo di evento.

 def handle_events (self): per evento in pygame.event.get (): if event.type == pygame.QUIT: pygame.quit () sys.exit () elif event.type == pygame.KEYDOWN: per gestore in self.keydown_handlers [event.key]: gestore (event.key) elif event.type == pygame.KEYUP: per gestore in self.keydown_handlers [event.key]: gestore (event.key) elif event.type in (pygame .MOUSEBUTTONDOWN, pygame.MOUSEBUTTONUP, pygame.MOUSEMOTION): per il gestore in self.mouse_handlers: handler (event.type, event.pos) 

Finalmente, il correre() il metodo esegue il ciclo principale. Funziona fino al gioco finito il membro diventa vero. In ogni iterazione, rende l'immagine di sfondo e invoca in ordine il handle_events (), aggiornare(), e disegnare() metodi. 

Quindi aggiorna il display, che effettivamente aggiorna il display fisico con tutto il contenuto che è stato reso durante questa iterazione. Ultimo, ma non meno importante, chiama il clock.tick () metodo per controllare quando verrà chiamata la successiva iterazione.

 def run (self): while not self.game_over: self.surface.blit (self.background_image, (0, 0)) self.handle_events () self.update () self.draw () pygame.display.update () self.clock.tick (self.frame_rate)

Conclusione

In questa parte, hai imparato le basi della programmazione del gioco e tutti i componenti coinvolti nella creazione di giochi. Quindi, abbiamo esaminato Pygame stesso e come installarlo. Infine, abbiamo approfondito l'architettura del gioco ed esaminato la struttura delle directory, il GameObject classe, e la classe di gioco. 

Nella seconda parte, esamineremo il TextObject classe utilizzata per il rendering del testo sullo schermo. Creeremo la finestra principale, inclusa un'immagine di sfondo, e poi impareremo come disegnare oggetti come la palla e la pagaia.

Inoltre, guarda cosa abbiamo a disposizione per la vendita e per studiare nel mercato Envato, e non esitare a fare domande e fornire il tuo prezioso feedback usando il feed qui sotto.