EntertainmentFunGamingGoodiesopen sourceProgrammare col martelloPythonTech notes

Creare un gioco con python

programmare un gioco con python

Programmare giochi

Ho sempre considerato lo sviluppo di videogame il punto più ‘alto’ della programmazione.
Da un lato perchè a livello tecnico richiede una serie di conoscenze matematiche (soprattutto quando si parla di 3D) e tecniche specifiche che sono generalmente molto distanti da quelle richieste per esempio da un’applicazione gestionale.
Dall’altro perchè è la prima cosa che ho provato a fare agli albori del mio interesse nella programmazione.
A questo si aggiunge il fascino di creare un mondo immaginario che funziona secondo le nostre regole.
Così, per svago e per fare una sorpresa a mia figlia, che si è appassionata di anime ricercati, mi sono documentato sulla libreria pygame (www.pygame.org).

Mi sono stati estremamente utili questi due link:
http://programarcadegames.com/python_examples/en/sprite_sheets/
e:
Tasdik Rahman
https://github.com/tasdikrahman/spaceShooter

Danganrompa

Nel caso specifico ho voluto prendere i personaggi da un anime tratto a sua volta da un gioco: Danganrompa.
Dalla trama molto complessa ed aspetti tra il comico e l’horror in un mondo distopico dove si combatte una battaglia tra la speranza e la disperazione.

Molti personaggi muoiono in spettacolari ‘punizioni’ dovute alle dinamiche del gioco, dove è necessario trovare il ‘traditore’ per sopravvivere, un pò come nel ben più noto e popolare ‘among us’.
In questo caso mi sono immaginato di dare una seconda possibilità al suo personaggio preferito: Gundham Tanaka.

Un tipo eccentrico che ha il potere di controllare gli animali e gira sempre con un gruppo di criceti dentro la sciarpa!
Il terribile orso-robot Monokuma tenta ancora di sconfiggerlo ma il nostro eroe si difenderà a colpi di…criceto.

creare un gioco in python

 

Pygame

Naturalmente il lavoro necessario per fare un gioco completo è molto di più di quello che posso allocare in questo momento e la prima versione è molto ottimizzabile e da completare, però nel codice che trovate su github ho già impostato alcuni meccanismi e metodi di base che possono essere usati per moltissimi giochi, in particolare:

  • La gestione degli sprite, le collisioni, gli spari, le esplosioni, la creazione del livello, la gestione dei salti e la gravità
  • Altri attribut dei personaggi, come l’animazione in funzione della direzione e la logica di movimento dei nemici
  • La gestione delle vite, dei punti e di un’eventuale barra d’energia
  • Gli effetti sonori e la colonna sonora principale
  • I comandi di base via tastiera
  • Il menù principale e la logica di game over

La programmazione di video game, come dicevamo, è molto diversa da quella classica, in linea di massima possiamo dire che dobbiamo definire:

  • gli oggetti del gioco(sprite), che possono essere personaggi, spari, esplosioni, piattaforme, etc..
  • il ciclo principale del programma che ne gestisce il comportamento e l’aggiornamento

Ogni oggetto sarà una classe che avrà, oltre al metodo init(), che imposterà, ad esempio, la posizione inizale del personaggio,
un metodo Update() che definirà di fatto tutta la logica di comportamento dell’oggetto in funzione degli eventi che andremo a definire nel ciclo principale.

class Player(pygame.sprite.Sprite):
    def __init__(self):
       # Call the parent's constructor
        pygame.sprite.Sprite.__init__(self)

        sprite_sheet = SpriteSheet("img/p1_tannaka.png")
        # Load all the right facing images into a list
        image = sprite_sheet.get_image(0, 0, 66, 90)
        self.walking_frames_r.append(image)
        # image = sprite_sheet.get_image(66, 0, 66, 90)
        # self.walking_frames_r.append(image)
        image = sprite_sheet.get_image(132, 0, 67, 90)
        self.walking_frames_r.append(image)
        image = sprite_sheet.get_image(0, 93, 66, 90)
        self.walking_frames_r.append(image)
        image = sprite_sheet.get_image(66, 93, 66, 90)
        self.walking_frames_r.append(image)
        image = sprite_sheet.get_image(132, 93, 72, 90)
        self.walking_frames_r.append(image)
        # image = sprite_sheet.get_image(0, 186, 70, 90)
        # self.walking_frames_r.append(image)

        # Load all the right facing images, then flip them
        # to face left.
        image = sprite_sheet.get_image(0, 0, 66, 90)
        image = pygame.transform.flip(image, True, False)
        self.walking_frames_l.append(image)
        # image = sprite_sheet.get_image(66, 0, 66, 90)
        # image = pygame.transform.flip(image, True, False)
        # self.walking_frames_l.append(image)
        image = sprite_sheet.get_image(132, 0, 67, 90)
        image = pygame.transform.flip(image, True, False)
        self.walking_frames_l.append(image)
        image = sprite_sheet.get_image(0, 93, 66, 90)
        image = pygame.transform.flip(image, True, False)
        self.walking_frames_l.append(image)
        image = sprite_sheet.get_image(66, 93, 66, 90)
        image = pygame.transform.flip(image, True, False)
        self.walking_frames_l.append(image)
        image = sprite_sheet.get_image(132, 93, 72, 90)
        image = pygame.transform.flip(image, True, False)
        self.walking_frames_l.append(image)
        # image = sprite_sheet.get_image(0, 186, 70, 90)
        # image = pygame.transform.flip(image, True, False)
        # self.walking_frames_l.append(image)
        self.hidden = False
        self.hide_timer = pygame.time.get_ticks()
        # Set the image the player starts with
        self.image = self.walking_frames_r[0]

        # Set a referance to the image rect.
        self.rect = self.image.get_rect()
        self.rect.bottom = HEIGHT - 10

    def update(self):
        # Move left/right
        self.rect.x += self.change_x
        pos = self.rect.x + self.level.world_shift
        if self.direction == "R":
            frame = (pos // 30) % len(self.walking_frames_r)
            self.image = self.walking_frames_r[frame]
        else:
            frame = (pos // 30) % len(self.walking_frames_l)
            self.image = self.walking_frames_l[frame]

        # See if we hit anything
        block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:
            # If we are moving right,
            # set our right side to the left side of the item we hit
            if self.change_x > 0:
                self.rect.right = block.rect.left
            elif self.change_x < 0:
                # Otherwise if we are moving left, do the opposite.
                self.rect.left = block.rect.right

Naturalmente ogni oggetto potra avere anche un suo metodo specifico, ad esempio, il giocatore potrà avere jump() per saltare e anche questo metodo potrà essere attivato dal ciclo principale, che si occupa anche di ‘reagire’ agli input dell’utente.

def jump(self):
    """ Called when user hits 'jump' button. """

    # move down a bit and see if there is a platform below us.
    # Move down 2 pixels because it doesn't work well if we only move down 1
    # when working with a platform moving down.
    self.rect.y += 2
    platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
    self.rect.y -= 2

    # If it is ok to jump, set our speed upwards
    if len(platform_hit_list) > 0 or self.rect.bottom >= constants.SCREEN_HEIGHT:
        self.change_y = -10

Qui invece definiamo lo sparo come oggetto sprite a sè stante e anche qui avremo un metodo init() e update():

class Shot(pygame.sprite.Sprite):
    def __init__(self, pos, direction):
        pygame.sprite.Sprite.__init__(self)
        
        self.images = []
        self.images.append(pygame.image.load('img/littlehamster.png'))

        # Set the for the enemy
        self.image = self.images[0]

        self.rect = self.image.get_rect()
        self.rect = self.rect.move(pos)

        self.direction = direction

    def update(self):
        if self.direction=='R': self.rect = self.rect.move(5,0)
        else:self.rect = self.rect.move(-5,0)

        if self.rect.x<0 or self.rect.x>constants.SCREEN_WIDTH:
            #print("KILL")
            self.kill()

La libreria Pygame in particolare permette di raggruppare gli sprite in gruppi in modo da poterli aggiornare tutti in una volta.

while running:
        pygame.time.wait(3000)

        #Stop menu music
        pygame.mixer.music.stop()
        #Play the gameplay music
        pygame.mixer.music.load(path.join(sound_folder, 'tgfcoder-FrozenJam-SeamlessLoop.ogg'))
        pygame.mixer.music.play(-1)     ## makes the gameplay sound in an endless loop
        
        menu_display = False
        
        ## group all the sprites together for ease of update
        all_sprites = pygame.sprite.Group()
        player = Player()
        all_sprites.add(player)
        
        ### SPRITE UPDATES
        # Update the player.
        active_sprite_list.update()

 

Questo di fatto chiama il metodo update di ogni oggetto facente parte del gruppo.

Per approfondire potete trovare qui il codice completo:
https://github.com/Rohzen/dangagame

Comment here