Sviluppare un gioco in Python : Sprites e ancora suoni. Terza Parte.

Introduzione

In questa terza parte analizzeremo la prima classe che gestice le sprites delle esplosioni. Nella prossima vedremo quella del personaggio ed infine quella del loop principale di gioco. Spero che, nonostante questa divisione, sia chiaro alla fine il funzionamento e che il vostro bagaglio sia arricchito per quanto riguarda l’uso delle sprites, fondamentali in qualsiasi gioco 2d. Senza perdere tempo, vediamo subito il codice:

class oggetto_esplosione(pygame.sprite.Sprite):
	def __init__(self,nome,altezza,larghezza,xy,screen, num):
		pygame.sprite.Sprite.__init__(self)
		self.immagini = carica_imm_sprite(nome,altezza,larghezza,num)
		self.immagine = self.immagini[0]

		self.coordinate = (int(xy[0]),int(xy[1]))
		self.rect = pygame.Rect((int(xy[0]+65),int(xy[1]+43)),(50,50))

		self.screen = screen
		self.esplosione = False

		self.audio = pygame.mixer.Sound("104447__dkmedic__EXPLODE.wav")
		self.canale_ex = pygame.mixer.Channel(4)

		self.maxframe = len(self.immagini)
		self.frame_corrente = 0

		self.tempo_anim = 0.0

		self.fine = False

	def update(self,tps, stringa):
		if self.esplosione == False and stringa is None:
			if ambiente.get_volume() != 1.0 and self.tempo_anim >= 1:
				ambiente.set_volume(ambiente.get_volume()+0.01)
				a_vento.set_volume(a_vento.get_volume()+0.01)
			else:
				self.tempo_anim += tps
			return
		else:
			self.esplosione = True

		if self.esplosione == True:
			if self.tempo_anim > 0.025 and self.frame_corrente != self.maxframe:
				if self.frame_corrente == 0:
					ambiente.pause()
					a_vento.pause()
					self.canale_ex = self.audio.play()
				self.immagine = self.immagini[self.frame_corrente]
				self.screen.blit(self.immagine,self.coordinate)
				self.frame_corrente += 1
				self.tempo_anim = 0

			elif self.frame_corrente == self.maxframe:
				self.frame_corrente = 0
				self.esplosione = False
				self.tempo_anim = 0
				if self.fine == True:
					x = self.screen.get_width()/2
					x -= fine_gioco.get_width()/2
					y = self.screen.get_height()/2
					y -= fine_gioco.get_height()/2
					notrun(self.screen, x,y)
				ambiente.set_volume(0.10)
				a_vento.set_volume(0.10)
				ambiente.unpause()
				a_vento.unpause()
				return

			else:
				self.screen.blit(self.immagine,self.coordinate)
				self.tempo_anim += tps
				return

Analisi

Come potete vedere alla linea 1, la classe creata estende pygame.sprite.Sprite, così da ereditare alcuni metodi e proprietà: per esempio possiamo utilizzare gruppi di sprite, per controllare meglio la renderizzazione (prossimamente vedremo anche questo) oppure per gestire meglio le collisioni. Dividerò l’analisi per ogni “funzione” che troveremo nella classe, per rendere più semplice la lettura.

Classe oggetto_esplosione : def __init__

  • Quando inizializziamo un nuovo oggetto abbiamo bisogno del nome, l’altezza e la larghezza della sprite che utilizzeremo, le coordinate della posizione iniziale (xy), l’oggetto screen (che rappresenza lo schermo dove si renderizza il tutto) e il numero di immagini che compongono la sprite (num).
  • Successivamente possiamo vedere che si richiama anche il metodo per inizializzare la sprite della libreria pygame (linea 3).
  • Procediamo caricando le immagini per la sprite, utilizzando la funzione vista in precedenza e settiamo l’immagine iniziale, che sarà il primo frame della lista di immagini ritornata.
  • Memorizziamo poi le coordinate dell’immagine, dividendo la tupla xy ed associamo un oggetto rect alla sprite, per gestire le collisioni. Per l’esempio in questione, ho spostato le cooridnate dell’oggetto rect per farle centrate rispetto l’immagine da me utilizzata, altrimenti la collisione inizierebbe appena si entra nel campo dell’immagine (anche se si utilizzano canali alpha), mentre qui ci interessa che la collisione con la bomba avvenga proprio nelle sue vicinanze.  Inoltre in questo caso non necessitavo di spostare le varie bombe piazzate sullo schermo, ma se vi capita di fare un aggiustamento del genere dovete contarlo anche per eventuali spostamenti della sprite, perché l’oggetto rect deve rimanere incollato ad essa come un’ombra, altrimenti si perderà tutto il realismo che si è cercato di creare poco prima.
  • Non perdiamo traccia dello schermo (screen) e inizializziamo un variabile per l’esplosione (self.esplosione = False).
  • Memorizziamo poi il suono della nostra esplosione e il canale dove sarà riprodotto. Visto che tutte le esplosioni hanno assegnato lo stesso canale (il numero 4), sappiamo quindi che sarà solo utilizzato per la riproduzione delle bombe e non intaccherà gli altri effetti, come il sottofondo di pioggia e vento che metteremo.
  • Infine memorizziamo delle variabili che ci servono per le animazioni: maxframe per vedere se siamo arrivati alla fine, frame_corrente, temp_anim per il tempo di animazione e la variabile fine (necessaria per la fine del gioco, vedremo poi come).

Classe oggetto_esplosione : def update

  • Questa funzione necessita del tempo passato in secondi e di una stringa, che indicherà se l’esplosione deve avvenire o meno.
  • (Linea 24) Se l’esplosione è avvenuta (oppure non è mai iniziata) e la stringa passata è uguale a “None”, non dobbiamo far esplodere nulla; controlliamo però il volume dell’ambiente, perché in caso di esplosione conclusa, dobbiamo ripristinare i valori iniziali del volume, creando quindi un effetto di vuoto tra il tempo dell’esplosione e la sua conclusione (perchè più avanti abbasseremo il volume dell’ambiente se l’esplosione è avvenuta). Se il volume non è tornato ancora alla normalità si incrementa solamente il tempo di animazione. Il tutto ci serve per regolare la durata dell’effetto e se il volume di ambiente (che va di pari passo con quello del vento, per questo non controlliamo entrambi) è nella norma si esce subito, quindi non avviene nessuna esplosione e non si vedrà nulla (a meno che la stringa non indichi diversamente).
  • Dalla linea 31 vediamo invece che cosa accade se l’esplosione deve sussistere. Esplosione diventa vera grazie al primo controllo, controlliamo comunque che sia vera, perché significa che stiamo in animazione. Subito dopo, se siamo nel tempo di animazione giusto (per il mio esempio ho scelto che ogni frame deve essere visualizzato ogni 0.025 secondi) e che non siamo arrivati alla fine, mettiamo in pausa l’ambiente e il vento e riproduciamo l’audio dell’esplosione (se il frame corrente è il primo). Aggiorniamo l’immagine corrente e la renderizziamo sullo schermo; prepariamo poi il prossimo frame e rimettiamo il tempo di animazione a zero, perché devono passare altri 0.025 secondi per far renderizzare la prossima immagine.
  • Facciamo poi un altro controllo alla linea 45 per vedere se siamo giunti a fine animazione ed in questo caso, rimettiamo il frame corrente a zero, l’esplosione a False e il tempo di animazione a zero. Infine se il gioco deve finire, prepariamo le coordinate per renderizzare “Game Over” utilizzando pygame.font. Una volta centrato il testo richiamiamo la funzione notrun, che si occuperà della conclusione del gioco (vedremo il tutto a tempo debito). Ora basti notare che dalle coordinate del centro dello schermo (dividiamo il tutto per due infatti), sottraiamo metà della lunghezza e dell’altezza del testo che vogliamo stampare a video, così che sia perfettamente centrato una volta renderizzato. Se invece il gioco deve proseguire, impostiamo un nuovo volume all’ambiente e al vento (più basso del normale) e togliamo la pausa.
  • Se l’animazione non è conclusa renderizziamo a video il frame corrente e aggiorniamo il tempo di animazione per poi ritornare.

Conclusioni

Per ora non potete mettere mano al prodotto completo, ma dovete assolutamente impadronirvi di questi basilari concetti per creare i vostri oggetti, le vostre sprites.

Le scelte che si intraprendono durante la creazione di un gioco, per quanto semplice sia, possono essere diverse e mai uguali. Non è detto che una soluzione sia sempre sbagliata; magari non è la più veloce o la più semplice da comprendere, ma se avete chiaro il vostro obbiettivo, riuscirete sicuramente ad utilizzare queste librerie tirando fuori quello che voi volete. Poi le scelte tecniche vengono fatte in base alle necessità, per esempio: se renderizziamo delle stelle in movimento sullo sfondo, queste non necessiteranno mai di un oggetto rect per gestire le collisioni se il nostro personaggio non deve interagire con esse.

Per quanto riguarda i suoni, dovete pensare sempre di sincronizzare l’animazione con essi e gestendo dei canali separati con un pizzico di fantasia potete creare i vostri effetti. Naturalmente l’aiuto di un buon editor audio non guasta, perché dovete creare dei suoni di buona qualità e di un certo effetto se volete attirare i sensi del giocatore (letteralmente parlando). Quindi fate molta attenzione alla scelta della musica e nell’utilizzo dei suoni.

Concludo qui, sperando di non essere stato troppo noioso e ripetitivo!

Press ESC to close