di  -  martedì 12 ottobre 2010

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!

6 Commenti »

I commenti inseriti dai lettori di AppuntiDigitali non sono oggetto di moderazione preventiva, ma solo di eventuale filtro antispam. Qualora si ravvisi un contenuto non consono (offensivo o diffamatorio) si prega di contattare l'amministrazione di Appunti Digitali all'indirizzo info@appuntidigitali.it, specificando quale sia il commento in oggetto.

  • # 1
    Francesco
     scrive: 

    Ciao Mirco,

    volevo dirti che le tue guide mi stanno tornando davvero utili..era proprio quello che cercavo.

    A tal proposito mi chiedevo se in futuro scriverai anche una parte dedicata alle finestre di gioco: se uno ha un gioco dove magari è presente una schermata iniziale (gioca, carica, opzioni, esci) come la crea? e come da lì si lancia il gioco vero e proprio?

    ti sarei molto grato..

    Cmq davvero un bel lavoro..aspetto la tua prossima guida ;)

  • # 2
    Mirco Tracolli
     scrive: 

    Ciao Francesco,

    questa piccola guida sta volgendo al termine, ma non è di certo la fine!!! :D Gli argomenti che hai sollevato saranno trattati molto presto e, tempo permettendo, farò degli esempi un pò meno banali per creare un qualcosa di più sostanzioso. Ma non posso dirti di più per ora, rovinerei la sorpresa. :P

  • # 3
    Francesco
     scrive: 

    @ Mirco:

    va bene..aspetterò..

    intanto do un’occhiata alla nuova guida ;)

  • # 4
    craig
     scrive: 

    Ciao, veramente molto utile la guida, tuttavia ti consiglerei di seguire meglio la PEP8 per esempio per quanto riguarda i nomi delle classi: OggettoEsplosione al posto di oggetto_esplosione . QUesto potrebbe aiutare ancora di piu i niubbi come me che magari potrebbero trovare qualche difficoltà.
    Queste non vogliono essere critiche per “rompere” o per fare i pignoli, spero tu comprenda che sono solo dei consigli :)

  • # 5
    Mirco Tracolli
     scrive: 

    @ craig

    Tranquillo che non rompi :D . A volte mi capita di scrivere in quel modo, anche se non si dovrebbe fare. Purtroppo, essendo gli svariati esempi staccati tra di loro, mi capita di scrivere in uno stile molto spartano i codici.

    Comunque sai benissimo che questo può anche variare da programmatore a programmatore e che è bene mettersi daccordo su questi dettagli se si segue un progetto più grande.

    Credo di aver migliorato un pò questo aspetto nei nuovi esempi, infatti spero di eliminare del tutto questo “vizio” in futuro.

  • # 6
    Cesare Di Mauro
     scrive: 

    La comunità Python è LEGGERMENTE fanatica anche col codice scritto da altri con questo linguaggio. :D

Scrivi un commento!

Aggiungi il commento, oppure trackback dal tuo sito.

I commenti inseriti dai lettori di AppuntiDigitali non sono oggetto di moderazione preventiva, ma solo di eventuale filtro antispam. Qualora si ravvisi un contenuto non consono (offensivo o diffamatorio) si prega di contattare l'amministrazione di Appunti Digitali all'indirizzo info@appuntidigitali.it, specificando quale sia il commento in oggetto.