Sito web di notizie tecnologiche e videogames.

Pygame Shooter Parte 11: Esplosioni

3

Questo articolo è l’undicesima parte del progetto PyShooter, oggi vedremo come aggiungere l’auto-fire e le eplosioni quando si verificano le collisioni.

Auto-fire

In questo momento l’utente deve premere la barra spaziatrice ogni volta che vuole sparare, per questo vedremo come far sparare automaticamente finchè la barra spaziatrice è premuta.

Per fare ciò aggiungiamo due attributi alla classe Player:

self.shoot_delay = 250
self.last_shot = pygame.time.get_ticks()

La variabile shoot_delay misura quanti millisecondi devono passare tra uno sparo e l’altro, in modo da evitare che vengano sparati troppi proiettili nell’unità di tempo.

La variabile last_shot tiene traccia dell’ultima volta che è stato sparato un colpo in modo da sapere se è passato abbastanza tempo per poterne sparare un altro.

A questo punto dobbiamo richiamare il metodo shoot() nel metodo update della classe Player quando la barra spaziatrice è premuta:

def update(self):
    self.speedx = 0
    keystate = pygame.key.get_pressed()
    if keystate[pygame.K_LEFT]:
        self.speedx = -8
    if keystate[pygame.K_RIGHT]:
        self.speedx = 8
    if keystate[pygame.K_SPACE]:
        self.shoot()

Ora aggiungiamo la logica del sistema di auto-fire in un nuovo metodo:

def shoot(self):
now = pygame.time.get_ticks()
if now - self.last_shot > self.shoot_delay:
    self.last_shot = now
    bullet = Bullet(self.rect.centerx, self.rect.top)
    all_sprites.add(bullet)
    bullets.add(bullet)

In questo modo quando la barra spaziatrice è premuta il gioco controlla quanto tempo è passato dall’ultima volta che è stato creato un proiettile. Se il tempo passato è maggiore di shoot_delay verrà istanziato un nuovo proiettile e la variabile last_shot verrà aggiornata.

A questo punto eliminiamo le seguenti righe del programma:

elif event.type == pygame.KEYDOWN:
    if event.key == pygame.K_SPACE:
        player.shoot()

Pygame Shooter Parte 11: Esplosioni

Esplosioni animate

Per rendere le collisioni più animate abbiamo bisogno di un set di immagini per le esplosioni. Avremo quindi bisogno di creare uno sprite nella posizione della meteora che viene distrutta e assegnargli ciclicamente le immagini dell’esplosione.

Per prima cosa dobbiamo caricare il set di immagini dell’esplosione e caricare ogni immagine in un arraylist.

Abbiamo anche bisogno di ridimensionare le immagini, perché le immagini per la collisione tra una meteora e un proiettile saranno più grandi rispetto a quelle tra una meteora ed il player.

Per fare ciò useremo quindi un dizionario contenente due liste, lg e sm. Dato che le immagini delle esplosioni si chiamano allo stesso modo con un numero che va da 00 a 08, possiamo usare un ciclo per caricarle tutte ed aggiungerle alle liste.

explosion_anim = {}
        # liste per le immagini
explosion_anim['lg'] = []
explosion_anim['sm'] = []
for i in range(9):
    filename = 'regularExplosion0{}.png'.format(i)
    img = pygame.image.load(path.join(img_dir, filename)).convert()
    img.set_colorkey(BLACK)
    img_lg = pygame.transform.scale(img, (75, 75))
    explosion_anim['lg'].append(img_lg)
    img_sm = pygame.transform.scale(img, (32, 32))
    explosion_anim['sm'].append(img_sm)

Esplosione degli sprite

Successivamente definiamo un nuovo sprite che rappresenterà la vera e propria esplosione. L’immagine dello sprite cambierà rapidamente scorrendo tutte le immagini della lista delle immagini delle esplosioni.

Quando lo sprite raggiunge l’ultima immagine della lista verrà eliminato.

Lo sprite verrà istanziato nella posizione della collisione tra i due sprite.

Come per l’auto-fire abbiamo un attributo che controlla ogni quanti millisecondi verranno creati i proiettili, anche per le esplosioni avremo un attributo (frame_rate) che controlla ogni quanti millisecondi verrà cambiata l’immagine dello sprite.

La classe Explosion è la seguente:

class Explosion(pygame.sprite.Sprite):
    def __init__(self, center, size):
        pygame.sprite.Sprite.__init__(self)
        self.size = size
        self.image = explosion_anim[self.size][0]
        self.rect = self.image.get_rect()
        self.rect.center = center
        self.frame = 0
        self.last_update = pygame.time.get_ticks()
        self.frame_rate = 50
    def update(self):
        now = pygame.time.get_ticks()
        if now - self.last_update > self.frame_rate:
            self.last_update = now
            self.frame += 1
            if self.frame == len(explosion_anim[self.size]):
                self.kill()
            else:
                center = self.rect.center
                self.image = explosion_anim[self.size][self.frame]
                self.rect = self.image.get_rect()
                self.rect.center = center

A questo punto dobbiamo istanziare un oggetto della classe Explosion ogni qual volta una meteora viene distrutta:

hits = pygame.sprite.groupcollide(mobs, bullets, True, True)
for hit in hits:
    score += 50 - hit.radius
    random.choice(expl_sounds).play()
    expl = Explosion(hit.rect.center, 'lg')
    all_sprites.add(expl)
    newmob()

Abbiamo bisogno inoltre di istanziare un’esplosione quando una meteora collide con il player:

hits = pygame.sprite.spritecollide(player, mobs, True, pygame.sprite.collide_circle)
for hit in hits:
    player.shield -= hit.radius * 2
    expl = Explosion(hit.rect.center, 'sm')
    all_sprites.add(expl)
    newmob()
    if player.shield <= 0:
        running = False

NB: Da notare che quando istanziamo un’esplosione specifichiamo la lista dalla quale prendere le immagini per essa. La lista passata come parametro sarà quindi diversa se la collisione è tra un proiettile ed una meteora oppure tra una meteora ed il player.

Pygame Shooter Parte 11: Esplosioni

Link al codice, immagini: code , images

Link al precedente articolo: Pygame Shooter Parte 10: Lo scudo per il player

 

Commenti