Gunnleggende spillutvikling i Pygame – Skape bevegelse

Skape bevegelse

Sette oppdateringsfrekvens og endre koordinater

For å skape bevegelse så bruker vi bare vanlig animasjon i pygame. Dersom vi viser “ballen” vår 30 ganger i sekundet, og hvis den endrer posisjonen litt for hver gang, så vil det se ut som en jevn bevegelse.

Vi starter selve spill-løkka med linja “while gameOn:”. Denne løkka kjører så raskt som maskinen din klarer. Vi må begrense dette, slik at hastigheten blir f eks 30 ganger i sekundet. Dette er det som ofte refereres til som FPS i spill-verden. La oss sette opp programmet vårt til å kjøre løkka 30 ganger i sekundet: 

Pyton
# oppretter spill-variabler og objekter
GameOn = True # En variabel som brukes for å kontrollere om spillet skal fortsette å kjøre
klokke = pygame.time.Clock()
FPS = 30

# starter mainloop, og den kjører så lenge GameOn er True
while GameOn:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: # Hva skjer om brukeren har trykket på X  øverst i vinduet?
            GameOn = False

    # tegne opp vinduet
    main.fill(ORANGE) # Setter en bakgrunnsfarge i vinduet
    pygame.draw.rect(main, BLACK, (0,0,WIDTH,50)) # Tegner et rektangel fra (0,0) som er 50 høyt
    main.blit(ball, (250, 200))
    pygame.display.update() # oppdaterer displayet slik at alle objekter vises
    klokke.tick(FPS)
# avslutter alle moduler i pygame
pygame.quit()

Her ser du endringene som  jeg har gjort. Jeg opprettet et klokkeobjekt i linje 24, jeg laget en variabel som heter FPS som har fått verdien 30 i linje 25, og tilslutt har jeg brukt objektet i spill-løkka slik at jeg setter ned hastigheten spillet kjøres i. Linje 38 gjør at spillet stopper opp litt hver gang slik at løkka kjøres 30 ganger i sekundet.

Det eneste vi trenger å gjøre nå er å endre posisjonen til ballen for hver gang vinduet oppdateres. Da trenger vi at koordinatene er variabler, og ikke konstanter, slik de er nå (250 og 200). Jeg kaller dem ball_x og ball_y for x og y koordinatene. Deretter endrer jeg disse hver gang løkka kjøres:

Pyton
# oppretter spill-variabler og objekter
GameOn = True # En variabel som brukes for å kontrollere om spillet skal fortsette å kjøre
klokke = pygame.time.Clock() # Oppretter klokke-objekt
FPS = 30 # Variabel som styrer oppdateringsfrekvensen
ball_x = 100 # Koordinater til ballen når programmet starter
ball_y = 100

# starter mainloop, og den kjører så lenge GameOn er True
while GameOn:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: # Hva skjer om brukeren har trykket på X  øverst i vinduet?
            GameOn = False
    
    #endrer variabler
    ball_x += 5 # samme som å skrive ball_x = ball_x + 5
    ball_y += 5

    # tegne opp vinduet
    main.fill(ORANGE) # Setter en bakgrunnsfarge i vinduet
    pygame.draw.rect(main, BLACK, (0,0,WIDTH,50)) # Tegner et rektangel fra (0,0) som er 50 høyt
    main.blit(ball, (ball_x, ball_y))
    pygame.display.update() # oppdaterer displayet slik at alle objekter vises
    klokke.tick(FPS)
# avslutter alle moduler i pygame
pygame.quit()

Dersom du kjører programmet nå, vil du se at ballen beveger seg skrått ned mot høyre. Det er fordi x blir stadig større (mot høyre) og y blir stadig større (nedover).

Få ballen til å sprette langs kanten av skjermen

Hvis vi vil at ballen skal begynne å gå oppover dersom den treffer bunn, så betyr det at ball_y skal begynne å trekke fra 5, i stedet for å legge til 5. Det betyr av hvordan ballen beveger seg i x-retning og hvordan den beveger seg i y-retning ikke er lik. Vi må derfor lage 2 nye variabler…nemlig hvor fort ballen beveger seg i x-retning og hvor fort ballen beverger seg i y-retning. Jeg kaller disse variablene for “ball_dx” og “ball_dy”. “d”en står for “delta”, og i matematikken betyr det endring. Jeg starter med å ha dx’verdier på 5, og når den treffer en kant, så skal verdien bli -5.

Pyton
# importere bibliotek og starte moduler
import pygame
pygame.init()

# sette størrelse og opprette vindu-objekt (main)
WIDTH = 500
HEIGHT = 400
main = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Min tittel") # setter tittel på vindu

# definere farger
RED = (255, 0, 0)
ORANGE = (255, 153, 0)
BLACK = (0, 0, 0)
BLUE = (0, 0, 255)

# oppretter ball-objekt
ball = pygame.Surface((40, 40))
ball.set_colorkey(BLACK)
pygame.draw.circle(ball, RED, (20, 20), 20)

# oppretter spill-variabler og objekter
GameOn = True # En variabel som brukes for å kontrollere om spillet skal fortsette å kjøre
klokke = pygame.time.Clock() # Oppretter klokke-objekt
FPS = 30 # Variabel som styrer oppdateringsfrekvensen
ball_x = 100 # Koordinater til ballen når programmet starter
ball_y = 100
ball_dx = 5
ball_dy = 5

# starter mainloop, og den kjører så lenge GameOn er True
while GameOn:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: # Hva skjer om brukeren har trykket på X  øverst i vinduet?
            GameOn = False
    
    #endrer variabler
    ball_x += ball_dx
    ball_y += ball_dy

    #sjekker om ballen treffer kantene på vinduet
    if ball_y > HEIGHT or ball_y < 50:
        ball_dy = -ball_dy
    if ball_x > WIDTH or ball_x < 0:
        ball_dx = -ball_dx

    # tegne opp vinduet
    main.fill(ORANGE) # Setter en bakgrunnsfarge i vinduet
    pygame.draw.rect(main, BLACK, (0,0,WIDTH,50)) # Tegner et rektangel fra (0,0) som er 50 høyt
    main.blit(ball, (ball_x, ball_y))
    pygame.display.update() # oppdaterer displayet slik at alle objekter vises
    klokke.tick(FPS)
# avslutter alle moduler i pygame
pygame.quit()

Nå har jeg fått lagt til en kode som får ballen til å sprette langs kanten, men som du ser er det et lite problem.

Ballen plasseres med koordinatet øverst i venstre hjørne av ballen (?), og det betyr at ballen ikke spretter før dette punktet treffer kanten på skjermen. Dette skal vi selvfølgelig få gjort noe med…vi oppretter et objekt som kalles rect, som skal fungere som en plassholder til ballen vår. Objektet rect skal altså beskrive posisjonen til ballen.

Lager et rect-objekt av ballen for å kontrollere plasseringen bedre

Det er litt knotete å bruke både en ball_x og en ball_y til å bestemme en plassering. Det finnes et objekt som kan ta vare på begge deler (og mye mer) for meg. Dette kalles et rect-objekt. Vi lager det på denne måten:

Pyton
# importere bibliotek og starte moduler
import pygame
pygame.init()

# sette størrelse og opprette vindu-objekt (main)
WIDTH = 500
HEIGHT = 400
main = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Min tittel") # setter tittel på vindu

# definere farger
RED = (255, 0, 0)
ORANGE = (255, 153, 0)
BLACK = (0, 0, 0)
BLUE = (0, 0, 255)

# oppretter ball-objekt
ball = pygame.Surface((40, 40))
ball.set_colorkey(BLACK)
pygame.draw.circle(ball, RED, (20, 20), 20)
ball_rect = ball.get_rect() # lager et rect-objekt
ball_rect.center = (100, 100)

# oppretter spill-variabler og objekter
GameOn = True # En variabel som brukes for å kontrollere om spillet skal fortsette å kjøre
klokke = pygame.time.Clock() # Oppretter klokke-objekt
FPS = 30 # Variabel som styrer oppdateringsfrekvensen
ball_dx = 5
ball_dy = 5

# starter mainloop, og den kjører så lenge GameOn er True
while GameOn:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: # Hva skjer om brukeren har trykket på X  øverst i vinduet?
            GameOn = False
    
    #endrer variabler
    ball_rect.x += ball_dx
    ball_rect.y += ball_dy

    #sjekker om ballen treffer kantene på vinduet
    if ball_rect.bottom > HEIGHT or ball_rect.top < 50:
        ball_dy = -ball_dy
    if ball_rect.right > WIDTH or ball_rect.left < 0:
        ball_dx = -ball_dx

    # tegne opp vinduet
    main.fill(ORANGE) # Setter en bakgrunnsfarge i vinduet
    pygame.draw.rect(main, BLACK, (0,0,WIDTH,50)) # Tegner et rektangel fra (0,0) som er 50 høyt
    main.blit(ball, ball_rect)
    pygame.display.update() # oppdaterer displayet slik at alle objekter vises
    klokke.tick(FPS)
# avslutter alle moduler i pygame
pygame.quit()

Sånn! Dette gjør susen. Legg merke til:

  • Linje 21: Vi lager et rect-objekt av ball
  • Linje 22: Vi plasserer rect’en. Vi har brukt center her, men kunne benyttet topleft, midbottom osv…
  • Vi har fjernet variablene ball_x og ball_y. ball_rect erstatter begge disse
  • Vi endrer verdier i rect-objektet på linje 38 og 39
  • If-testene på linje 42-45 er nå mye mer presise fordi jeg kan sjekke ballens venstre-side, høyre-side, topp og bunn. Ballen spretter derfor mer riktig nå enn den gjorde i stad.
  • Linje 50: plassering av ball er nå satt til “ball_rect”, som inneholder alle nødvendige koordinater.

Før du går videre; kan du lage en ball til i vinduet ditt som er halvparten så stor, går dobbelt så fort og som er blå?

Hva skjer dersom du endrer FPS til 60 og hastighet til 3 (ball_dx/ball_dy).

DigitAbel – for dypere læring