Skapa ett spel med Pygame – Logik

Vi kan även införa logik i spelet. Beroende på vad som händer i spelet, ska något nytt hända!

I föregående avsnitt visade vi hur man kan skapa en game-loop för att skapa basen för ett spel i pygame. Vi har även visat hur man kan använda piltangenterna för att styra spelaren. Nu behövs lite logik i spelet. Vi ska programmera en fallande vägg med ett hål i. Målet är att styra spelaren igenom hålet. Om man nuddar väggen, får man game-over. Vi ska även lägga till en räknare, som håller reda på hur många hål vi passerat. Vi utgår från koden som vi skapat i tidigare avsnitt:

Visa kod

# 1 - Import library
import pygame
from pygame.locals import *

# 2 - Initialize the game
pygame.init()
pygame.font.init() # you have to call this at the start, 
                   # if you want to use this module.

width, height = 64*10, 64*8
screen=pygame.display.set_mode((width, height))
player_x = 200
player_y = 200
keys = [False, False, False, False]

# 3 - Load images
player = pygame.image.load("hero.png")

# 4 - keep looping through
while 1:

    # 5 - clear the screen before drawing it again
    screen.fill((255,255,255))
    # 6 - draw the screen elements
    screen.blit(player, (player_x, player_y))

    # 7 - update the screen
    pygame.display.flip()
    # 8 - loop through the events
    for event in pygame.event.get():
        # check if the event is the X button 
        if event.type == pygame.QUIT:
            # if it is quit the game
            pygame.quit() 
            exit(0) 
        if event.type == pygame.KEYDOWN:
            if event.key==K_UP:
                keys[0]=True
            elif event.key==K_LEFT:
                keys[1]=True
            elif event.key==K_DOWN:
                keys[2]=True
            elif event.key==K_RIGHT:
                keys[3]=True

        if event.type == pygame.KEYUP:
            if event.key==pygame.K_UP:
                keys[0]=False
            elif event.key==pygame.K_LEFT:
                keys[1]=False
            elif event.key==pygame.K_DOWN:
                keys[2]=False
            elif event.key==pygame.K_RIGHT:
                keys[3]=False

    # Updatera y-positionen
    if keys[0]:                        # Om uppåtknappen är intryckt
        if player_y > 0:               # Om koordinaten är större än 0 (ej utanför spelplanen)
            player_y -= 15             # Ändra y-positionen med 15 pixlar. Spelaren åker uppåt
    elif keys[2]:                      # Om nedåttangenten är intryckt
        if player_y < height-64:       # Om koodinaten är mindre än höjden på spelplanen (ej utanför spelplanen) 
            player_y += 15             # Ändra y-positionen med 15 pixlar. Spelaren åker nedåt 
    if keys[1]:                        # Om vänster tangent är nedtryckt 
        if player_x > 0:               # Om spelaren är innanför spelplanen
            player_x -= 15             # Minska positionen i x-led. Spelaren åker vänster
    elif keys[3]:                      # Om höger tangent är nedtryckt
        if player_x < width-64:        # Om spelaren är innanför spelplanen
            player_x += 15             # Öka positionen i x-led. Spelaren åker höger


Skapa en fallande vägg

Vi laddar in en bild som är 64 x 64 pixlar stor. Detta är en ruta i spelet.

Eftersom spelet är 10 x 64 pixlar bred, vet vi att det får plats 10 väggblock på spelplanen. Därför skapar vi 8 objekt av wall, vilket innebär att hålet blir två rutor bred.

def wall_render(rand, wall_y):                 # Rand är ett random heltal mellan 0-9 
    for i in range(0, 10):                     # Loopa 10 gånger
        if not (i == rand or i == rand + 1):   # Rita inte på två efterföljande random rutor
            screen.blit(wall, (i*64, wall_y))  # Rita ut blocket på rätt position

Koden ovan kommer rita ut ett block på åtta platser på samma höjd, med 64 pixlar mellan varje ruta. Det kommer bli ett hål som är två rutor stort.

Programmera flera lika dana objekt i python

Gör så att väggen faller

Gör så att väggen faller genom att öka wall_y som hanterar y-positionen på väggen. När väggen har fallit hela vägen till botten av spelplanen, börjar den om från toppen igen.

def wall_handler(wall_y, rand, nmbr_of_walls, wall_speed):
    wall_y += wall_speed          # Öka y-positionen för väggen. Väggen "faller"
    if wall_y > height:           # Om väggen har åkt hela vägen ner i botten, börja om från toppen
        wall_y = -64              # Hela väggen är i toppen av spelet
        rand = randint(0,8)       # Slumpa ett heltal mellan 0 och 8. Hålet kommer på en ny plats
        nmbr_of_walls += 1        # Håll räkningen hur många väggar man passerat
        wall_speed +=1            # Öka hastigheten på väggen

    # Returnera alla uppdateringar
    return wall_y, rand, nmbr_of_walls, wall_speed

Väggen faller nu neråt hela tiden och hålet kommer bytas varje gång väggen har kommit till marken.


Sätt game-over om spelaren krockar med väggen

Om spelaren åker in i väggen får vi game-over. Vi kollar om spelarens position krockar med väggen med följande kod:

def collide(player_x, player_y, wall_y, rand_wall):
    if (player_y >= wall_y and player_y <= wall_y + 64) and\
        ((player_x > 0 and player_x <= rand_wall*64) or (player_x > (rand_wall+1)*64 and player_x < width+64)): 
        return True
    else:
        return False

Om spelarens x- och y-koordinat är innanför väggens koordinater så returneras True, annars False.


Byt till meny-läge vid game-over

Vi kan blanda mellan meny-läge och spel-läge med variabeln is_game. Om man trycker på Enter i meny-läget, startas ett nytt spel.

while 1:
    if not is_game:
        screen.fill((255,255,255))                                              # Rita ut en vit spelplan
        textsurface = myfont.render("Press enter to start", False, (0, 0, 0))   # Skapa en textrad
        screen.blit(textsurface,(180, 200))                                     # Rita ut textraden på en viss position
        pygame.display.flip()                                                   # Uppdatera spelplanen

        for event in pygame.event.get():                     # Undersök alla event - Exempelvis knapptryckningar
            if event.type == pygame.QUIT:                    # Om man kryssar ner spelplanen 
                pygame.quit()                                # Avsluta spelet
                exit(0)                                      # Stäng av programmet

            if event.type == pygame.KEYDOWN:                 # Kolla om en tangent trycks ner
                if event.key==K_RETURN:                      # Om Enter trycks ner, uppdatera alla variablet
                    player_x = 256                           # Startposition i x-led för spelaren
                    player_y = 440                           # Startposition i y-led för spelaren
                    wall_y = -64                             # Sätt väggen i toppen av spelplanen
                    rand_wall = randint(0,8)                 # Slumpa ett nytt hål
                    nmbr_of_walls = 0                        # Sätt antal klarade väggar till 0
                    keys = [False, False, False, False]      # Nollställ alla knapptryck
                    wall_speed = 2                           # Sätt en starthastighet
                    is_game = True                           # Starta spelet

Skapa en räknare

Slutligen skapar vi en räknare som håller koll på hur många väggar vi har passerat:

textsurface = myfont.render(str(nmbr_of_walls), False, (0, 0, 0))
screen.blit(textsurface,(10, 0))

Där nmbr_of_walls är antal passerade väggar som uppdateras i funktionen wall_handler.

Spelet är nu klart! All kod hittar du nedan! Testa själv!

# 1 - Import library
import pygame
from pygame.locals import *
from random import randint

# 2 - Initialize the game
pygame.init()
pygame.font.init() # you have to call this at the start, 
                   # if you want to use this module.
myfont = pygame.font.SysFont('Comic Sans MS', 30)

width, height = 64*10, 64*8
screen=pygame.display.set_mode((width, height))
player_x = 256
player_y = 440
keys = [False, False, False, False]
wall_y = -64
rand_wall = randint(0,8)
nmbr_of_walls = 0
wall_speed = 2
is_game = False

# 3 - Load images
player = pygame.image.load("hero.png")
wall = pygame.image.load("wall.png")

def wall_render(rand, wall_y):                 # Rand är ett random heltal mellan 0-9 
    for i in range(0, 10):                     # Loopa 10 gånger
        if not (i == rand or i == rand + 1):   # Rita inte på två efterföljande random rutor
            screen.blit(wall, (i*64, wall_y))  # Rita ut blocket på rätt position

def wall_handler(wall_y, rand, nmbr_of_walls, wall_speed):
    wall_y += wall_speed          # Öka y-positionen för väggen. Väggen "faller"
    if wall_y &gt; height:           # Om väggen har åkt hela vägen ner i botten, börja om från toppen
        wall_y = -64              # Hela väggen är i toppen av spelet
        rand = randint(0,8)       # Slumpa ett heltal mellan 0 och 8. Hålet kommer på en ny plats
        nmbr_of_walls += 1        # Håll räkningen hur många väggar man passerat
        wall_speed +=1            # Öka hastigheten på väggen

    # Returnera alla uppdateringar
    return wall_y, rand, nmbr_of_walls, wall_speed  

def collide(player_x, player_y, wall_y, rand_wall):
    if (player_y &gt;= wall_y and player_y &lt;= wall_y + 64) and\
        ((player_x &gt; 0 and player_x &lt;= rand_wall*64) or (player_x &gt; (rand_wall+1)*64 and player_x &lt; width+64)): 
        return True
    else:
        return False

# 4 - keep looping through
while 1:
    if not is_game:
        screen.fill((255,255,255))                                              # Rita ut en vit spelplan
        textsurface = myfont.render("Press enter to start", False, (0, 0, 0))   # Skapa en textrad
        screen.blit(textsurface,(180, 200))                                     # Rita ut textraden på en viss position
        pygame.display.flip()                                                   # Uppdatera spelplanen

        for event in pygame.event.get():                     # Undersök alla event - Exempelvis knapptryckningar
            if event.type == pygame.QUIT:                    # Om man kryssar ner spelplanen 
                pygame.quit()                                # Avsluta spelet
                exit(0)                                      # Stäng av programmet

            if event.type == pygame.KEYDOWN:                 # Kolla om en tangent trycks ner
                if event.key==K_RETURN:                      # Om Enter trycks ner, uppdatera alla variablet
                    player_x = 256                           # Startposition i x-led för spelaren
                    player_y = 440                           # Startposition i y-led för spelaren
                    wall_y = -64                             # Sätt väggen i toppen av spelplanen
                    rand_wall = randint(0,8)                 # Slumpa ett nytt hål
                    nmbr_of_walls = 0                        # Sätt antal klarade väggar till 0
                    keys = [False, False, False, False]      # Nollställ alla knapptryck
                    wall_speed = 2                           # Sätt en starthastighet
                    is_game = True                           # Starta spelet
    else:
        # 5 - clear the screen before drawing it again
        screen.fill((255,255,255))
        # 6 - draw the screen elements
        screen.blit(player, (player_x, player_y))

        textsurface = myfont.render(str(nmbr_of_walls), False, (0, 0, 0))
        screen.blit(textsurface,(10, 0))

        wall_y, rand_wall, nmbr_of_walls, wall_speed = wall_handler(wall_y, rand_wall, nmbr_of_walls, wall_speed)
        wall_render(rand_wall, wall_y)

        if collide(player_x, player_y, wall_y, rand_wall):
            is_game = False

        # 7 - update the screen
        pygame.display.flip()
        # 8 - loop through the events
        for event in pygame.event.get():
            # check if the event is the X button 
            if event.type == pygame.QUIT:
                # if it is quit the game
                pygame.quit() 
                exit(0) 
            if event.type == pygame.KEYDOWN:
                if event.key==K_UP:
                    keys[0]=True
                elif event.key==K_LEFT:
                    keys[1]=True
                elif event.key==K_DOWN:
                    keys[2]=True
                elif event.key==K_RIGHT:
                    keys[3]=True

            if event.type == pygame.KEYUP:
                if event.key==pygame.K_UP:
                    keys[0]=False
                elif event.key==pygame.K_LEFT:
                    keys[1]=False
                elif event.key==pygame.K_DOWN:
                    keys[2]=False
                elif event.key==pygame.K_RIGHT:
                    keys[3]=False

        if keys[0]:
            if player_y &gt; 0:
                player_y -= 15
        elif keys[2]:
            if player_y &lt; height-64: 
                player_y += 15 
        if keys[1]: 
            if player_x &gt; 0:
                player_x -= 15
        elif keys[3]:
            if player_x &lt; width-64:
                player_x += 15
Bakåt    |    Framåt