Simulering med Pygame 3

Bevegelse med konstant akselerasjon

I forrige leksjon såg vi på rettlinja bevegelse. No skal vi sjå på bevegelse med konstant akselerasjon. Vi skal simulera ein ball som blir kasta. Som vi veit frå fysikken vil denne blir påvirka av tyngdekrafta og få konstant akelerasjon retta nedover. Dette er tyngdeakselerasjonen, og er vanligvis sett til 9.8 m/s2. Men sidan vi enno ikkje har innført skikkelige enheter, og opererer på spill-nivå, så set vi den lik 0.1 Så den (nesten) einaste endringen frå det rettlinja tilfellet vil egentlig vera at vi for kvar iterasjon oppdaterer farten i y-retning:

In [ ]:
vy += 0.1

Husk at nedover i eit pygame-vindu er i positiv y-retning. Vi beheld koden for kollisjonshåndtering, og legg koden for akselerasjonen inn i ein else-betingelse:

In [ ]:
        # Hvis kollisjon med venstre eller høgre kant, reverserer vi farten i x-retning
        if x + RADIUS > BREDDE or x < RADIUS:
            vx = -vx
        # Hvis kollisjon med øvre eller nedre kant, reverserer vi farten i y-retning
        if y + RADIUS > HOYDE or y < RADIUS:
            vy = -vy
        else:
            vy += 0.1 # akselerasjon pga "tyngdekraft"

Husk at kollisjonen skjer i løpet av et enkelt klokketikk, så mesteparten av tida vil det vera else-betingelsen som gjeld, og ballen blir akselerert nedover. Det betyr at når den er på vei oppover (vy negativ), så vil farten minka, og når den er på vei nedover (vy positiv) så vil farten auka. Sidan farten i kollisjon med bakken bare vil snu, så er det ingen tap av kinetisk energi her. Så ballen vår vil fortsetja å spretta i all evighet. For å få ein viss form for realisme i sprettinga, så innfører vi demping. Litt prøving og feiling fører til følgande kode:

In [ ]:
    DEMPING1 = 0.94
    DEMPING2 = 0.99
    
        # Hvis kollisjon med venstre eller høgre kant, reverserer vi farten i x-retning
        if x + RADIUS > BREDDE or x < RADIUS:
            vx *= -DEMPING1
        # Hvis kollisjon med øvre eller nedre kant, reverserer vi farten i y-retning
        if y + vy + RADIUS > HOYDE or y + vy < RADIUS:
            vy *= -DEMPING1
            vx *= DEMPING2
        else:
            vy += 0.1 # akselerasjon pga "tyngdekraft"

"DEMPING1" blir brukt i alle kollisjonar, og fører til tap av energi når ballen sprett. "DEMPING2" er tatt med for å få meir realitisk stopping av ballen, når den ikkje lenger sprett. Når ballen har stoppa å spretta, så vil betingelse to vera oppfylt heile tida, og for å stoppa ballen i x-retningen så må vi redusera (men ikkje snu) farten i x-retning. Så dette virkar som ein form for rullemotstand.

Den oppmerksomme vil også sjå at testen for kollisjon med bakke og tak er endra. Her er vy tatt med slik at vi har erstatta y med y + vy. Det betyr at vi testar no for kor ballen vil vera i neste tidssteg. Dette er for å hindra at ballen blir "fanga" i bunn. Koden ser dermed slik ut:

In [ ]:
import pygame 

pygame.init() # Startar pygame

BREDDE = 400 # Bredden på vinduet
HOYDE = 300 # Høyden på vinduet

# Definerer RGB-fargar
BAKGRUNN =  (100, 200, 255)
BALL = (255, 80, 0)

FPS = 200 #Frames Per Second, dvs kor fort animasjonen skal gå.

vindu = pygame.display.set_mode((BREDDE, HOYDE)) # Definerer vindu / overflate
pygame.display.set_caption("Sprettball: ") # Overskrift for vinduet
clock = pygame.time.Clock()

def game_loop():

    DEMPING1 = 0.94
    DEMPING2 = 0.99
    
    RADIUS = 15          # Radius
    
    x = 150         # startverdi for x
    y = 50          # Startverdi for y
    vx = 1          # Startfart i x-retning
    vy = 1          # Startfart i y-retning

    running = True # Boolsk variabel. Løkka vil løpa så lenge denne er SANN

    while running:
        
        # Lukker vindu og stoppar programmet:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return pygame.quit() 
       
        # Hvis kollisjon med venstre eller høgre kant, reverserer vi farten i x-retning
        if x + RADIUS > BREDDE or x < RADIUS:
            vx *= -DEMPING1
        # Hvis kollisjon med øvre eller nedre kant, reverserer vi farten i y-retning
        if y + vy + RADIUS > HOYDE or y + vy < RADIUS:
            vy *= -DEMPING1
            vx *= DEMPING2
        else:
            vy += 0.1 # akselerasjon pga "tyngdekraft"
            
        x += vx # Oppdaterer x-koordinat
        y += vy # Oppdaterer y-koordinat

        # Tegnar vindu og ball
        vindu.fill(BAKGRUNN) # Fyller vindu med ein farge
        pygame.draw.circle(vindu, BALL, (int(x), int(y)), RADIUS, 0)
        pygame.display.update()
        clock.tick(FPS)

game_loop()