Bygg spill med Python 3 og Pygame Del 1

Oversikt

Mange utviklere går inn i programvareutvikling fordi de vil bygge spill. Ikke alle kan være en profesjonell spillutvikler, men alle kan bygge sine egne spill for moro og kanskje profitt. I denne femdelte serien vil jeg vise deg hvordan du lager 2D single-player spill ved hjelp av Python 3 og den utmerkede Pygame-rammen. 

Vi vil bygge en versjon av det klassiske Breakout spillet. Når alt er sagt og gjort, vil du ha en klar forståelse av hva som trengs for å lage ditt eget spill, du vil bli kjent med Pygams evner, og du vil få et utvalgspill. 

Her er funksjonene og egenskapene vi skal implementere:

  • enkel generisk GameObject og TextObject
  • Enkelt generisk spillobjekt
  • enkel generisk knapp
  • config-fil
  • håndtering av tastatur og mus hendelser
  • murstein, padle og ball
  • administrere padle bevegelse
  • håndterer kollisjoner av ballen med alt
  • bakgrunnsbilde
  • lydeffekter
  • utvidbare spesial effekter system

Hva du burde ikke Forvent er et visuelt hyggelig spill. Jeg er en programmerer og ikke en artist. Jeg bekymrer meg mer om estetikken til koden. Resultatet av min visuelle design kan være ganske sjokkerende. På plussiden, hvis du vil forbedre hvordan denne versjonen av Breakout ser ut, har du tonn av rom for forbedring. Med den dystre advarselen ut av veien, er her et skjermbilde:

Full kildekoden er tilgjengelig her.

Rask introduksjon til spillprogrammering

Spill handler om å flytte piksler på skjermen og lage støy. Nesten alt video / dataspill har de fleste av følgende elementer. Utenom omfanget av denne artikkelen er klient-server spill og multi-player spill, som involverer mye nettverksprogrammering også.

Main Loop

Hovedløkken i et spill løper og oppdaterer skjermen med faste intervaller. Dette er din bildefrekvens, og det dikterer hvordan glatte ting er. Spillene oppdateres vanligvis 30 til 60 ganger i sekundet. Hvis du går sakte, vil objekter på skjermen virke rykkete. 

Inne i hovedløkken er det tre hovedaktiviteter: håndtering av hendelser, oppdatering av spilltilstanden og tegning av nåværende tilstand på skjermen.

Håndtering av hendelser

Hendelser i et spill består av alt som skjer utenfor kontrollen av spillets kode, men er relevant for spillets drift. For eksempel, hvis i Breakout spilleren trykker på venstre piltast, må spillet bevege padlen til venstre. Typiske hendelser er nøkkelpresser (og utgivelser), musebevegelse, museknappklikk (spesielt i menyer) og timerhendelser (for eksempel en spesiell effekt utløper etter 10 sekunder).

Oppdateringsstat

Kjernen til hvert spill er dens tilstand: de ting det holder styr på og trekker på skjermen. I Breakout, inkluderer staten plasseringen av alle mursteinene, stillingen og hastigheten til ballen, og plasseringen av padleen, så vel som liv og poengsummen. 

Det er også hjelpestaten som hjelper til med å håndtere spillet: 

  • Viser vi en meny nå? 
  • Er spillet over? 
  • Vunnet spilleren?

Tegning

Spillet må vise sin tilstand på skjermen. Dette inkluderer tegning geometriske former, bilder og tekst.

Spillfysikk

De fleste spill simulerer et fysisk miljø. I Breakout bounces ballen av objekter og har a veldig rå stiv kroppsfysikk system på plass (hvis du kan kalle det det). 

Mer avanserte spill kan ha mer sofistikerte og realistiske fysikk systemer (spesielt 3D-spill). Vær oppmerksom på at noen spill som kortspill ikke har mye fysikk i det hele tatt, og det er helt greit. 

AI (kunstig intelligens)

Det er mange spill hvor du spiller mot en kunstig datamaskin motstander eller motstandere, eller det er fiender som prøver å drepe deg eller verre. Disse figurer av spillets fantasi virker ofte på en tilsynelatende intelligent måte i spillets verden. 

For eksempel vil fiender jage deg og være klar over plasseringen din. Breakout presenterer ikke en AI. Du spiller mot de kalde, harde mursteinene. Imidlertid er AI i spill ofte veldig enkelt og følger bare enkle (eller komplekse) regler for å oppnå pseudo-intelligente resultater.

Spille av lyd

Å spille lyd er et annet viktig aspekt av spill. Det er generelt to typer lyd: bakgrunnsmusikk og lydeffekter. I Breakout fokuserer jeg på lydeffekter som spiller kort når ulike hendelser skjer. 

Bakgrunnsmusikk er bare musikk som spiller konstant i bakgrunnen. Noen spill bruker ikke bakgrunnsmusikk, og noen bytter det til alle nivåer.

Lev, Score og Nivåer

De fleste spill gir deg en viss mengde liv, og når du går tom for liv, er spillet over. Du har også ofte en poengsum som gir deg en følelse av hvor godt du gjør og en motivasjon til å forbedre neste gang du spiller eller bare skryter til vennene dine om dine friske ferdigheter. Mange spill har nivåer som enten er helt forskjellige eller øker vanskelighetsgraden.

Møt Pygame

Før du dykker inn og begynner å implementere, la oss lære litt om Pygame, som vil gjøre mye av den tunge løftingen for oss.

Hva er Pygame?

Pygame er et Python-rammeverk for spillprogrammering. Den er bygget på toppen av SDL og har alle de gode greiene:

  • moden
  • flott samfunn
  • åpen kilde
  • kryssplattform
  • gode dokumenter
  • masse prøve spill
  • lett å lære

Installere Pygame

Type pip installere pygame for å installere den. Hvis du trenger noe annet, følger du instruksjonene i Komme i gang-delen av Wiki. Hvis du kjører MacOS Sierra som jeg gjør, kan det hende at du får problemer. Jeg var i stand til å installere Pygame uten problemer, og koden syntes å løpe helt fint, men spillvinduet viste aldri opp. 

Det er litt bummer når du kjører et spill. Jeg måtte til slutt dra til Windows på en VirtualBox VM. Forhåpentligvis, når du leser denne artikkelen, har problemet blitt løst.

Spillarkitektur

Spillene må håndtere mye informasjon og utføre lignende operasjoner på mange objekter. Breakout er et mini-spill, men prøver å administrere alt i en fil vil være overveldende. I stedet valgte jeg å lage en filstruktur og arkitektur som ville være egnet for mye større spill.

Katalog og filstruktur

├── Pipfile ├── Pipfile.lock ├── README.md ├── ball.py ├── breakout.py ├── brick.py ├── button.py ├── colors.py ├── config .py ├── game.py ├── game_object.py ├── bilder │ └── background.jpg ├── paddle.py ├── sound_effects │ ├── brick_hit.wav │ ├── effect_done.wav │ ├── level_complete.wav │ └── paddle_hit.wav └── text_object.py 

Pipfile og Pipfile.lock er den moderne måten å håndtere avhengigheter i Python. Bilder katalogen inneholder bilder som brukes av spillet (kun bakgrunnsbildet i denne inkarnasjonen), og lyden-effektkatalogen inneholder korte lydklipp brukt som (du gjettet det) lydeffekter. 

Ball.py, paddle.py og brick.py-filene inneholder kode som er spesifikk for hver av disse Breakout-objektene. Jeg vil dekke dem i dybden senere i serien. Text_object.py-filen inneholder kode for å vise tekst på skjermen, og background.py-filen inneholder Breakout-spesifikke spilllogikken. 

Imidlertid er det flere moduler som danner et løs, generelt formålskjelett. Klassene som er definert der, kan gjenbrukes for andre Pygame-baserte spill.

The GameObject Class

GameObject representerer et visuelt objekt som vet hvordan man gjør seg selv, opprettholder sine grenser, og beveger seg rundt. Pygame har faktisk en Sprite-klasse som har en lignende rolle, men i denne serien vil jeg vise hvordan ting fungerer på et lavt nivå og ikke stole på for mye ferdigpakket magi. Her er GameObject-klassen:

fra pygame.rect import Rect klasse GameObject: def __init __ (selv, x, y, w, h, hastighet = (0,0)): self.bounds = Rect (x, y, w, h) self.speed = hastighet @ selvtillit til venstre (selv): return self.bounds.left @property def right (selv): return self.bounds.right @property def top (selv): return self.bounds.top @property def bottom (selv): returnere self.bounds.bottom @property def bredde (selv): return self.bounds.width @property def høyde (selv): return self.bounds.height @property def center (selv): returner self.bounds.center @property def centerx (selv): return self.bounds.centerx @property def centery (selv): return self.bounds.centery def trekke (selv, overflate): pass def move (selv, dx, dy): self.bounds = self .bounds.move (dx, dy) def oppdatering (selv): hvis self.speed == [0, 0]: return self.move (* self.speed) 

GameObject er designet for å fungere som en grunnklasse for andre objekter. Det eksponerer direkte mye av egenskapene til selvbindingens rektangel, og i dens Oppdater() Metode det beveger objektet i henhold til gjeldende hastighet. Det gjør ikke noe i det tegne() metode, som bør overstyres av underklasser.

Spillklassen

Spillklassen er kjernen i spillet. Den kjører hovedløkken. Den har mye nyttig funksjonalitet. La oss ta det metoden etter metode.

De __i det__() Metoden initierer Pygame selv, skriftsystemet og lydmikseren. Grunnen til at du må gjøre tre forskjellige anrop er at ikke alle Pygame-spill bruker alle komponentene, slik at du kontrollerer hvilke delsystemer du bruker og initierer bare de med deres spesifikke parametere. Den skaper bakgrunnsbilde, hovedoverflaten (hvor alt er tegnet), og spilleklokken med riktig rammeprosent. 

Selvobjektmedlemmet vil beholde alle spillobjektene som må gjengis og oppdateres. De ulike behandlerne håndterer lister over håndteringsfunksjonen som skal kalles når visse hendelser skjer.

import pygame import sys fra samlinger import defaultdict klasse Spill: def __init __ (selvbilde, bredde, høyde, back_image_filename, frame_rate): self.background_image = \ pygame.image.load (back_image_filename) self.frame_rate = frame_rate self.game_over = False self.objects = [] pygame.mixer.pre_init (44100, 16, 2, 4096) pygame.init () pygame.font.init () self.surface = pygame.display.set_mode ((bredde, høyde)) pygame. display.set_caption (caption) self.clock = pygame.time.Clock () self.keydown_handlers = defaultdict (liste) self.keyup_handlers = defaultdict (liste) self.mouse_handlers = [] 

De Oppdater() og tegne() metoder er veldig enkle. De gjenkjenner bare over alle de administrerte spillobjektene og kaller deres tilsvarende metoder. Hvis to spillobjekter overlapper, bestemmer rekkefølgen i objektlisten hvilken gjenstand som skal gjengis først, og den andre vil helt eller delvis dekke den. 

 def oppdatering (selv): for o i self.objects: o.update () def draw (selv): for o i self.objects: o.draw (self.surface) 

De handle_events () Metoden lytter til hendelser generert av Pygame, som nøkkel og mus hendelser. For hver hendelse påkaller den alle håndteringsfunksjonene som er registrert for å håndtere denne type hendelsen.

 def handle_events (selv): for hendelsen i pygame.event.get (): hvis event.type == pygame.QUIT: pygame.quit () sys.exit () elif event.type == pygame.KEYDOWN: for handler i self.keydown_handlers [event.key]: handler (event.key) elif event.type == pygame.KEYUP: for handler i self.keydown_handlers [event.key]: handler (event.key) elif event.type i (pygame .MOUSEBUTTONDOWN, pygame.MOUSEBUTTONUP, pygame.MOUSEMOTION): for handler i self.mouse_handlers: handler (event.type, event.pos) 

Endelig, den løpe() Metoden kjører hovedløkken. Det går til den spillet er slutt medlem blir sant. I hver iterasjon gjør det bakgrunnsbildet og påkaller i rekkefølge handle_events (), Oppdater(), og tegne() fremgangsmåter. 

Deretter oppdaterer skjermen, som faktisk oppdaterer det fysiske displayet med alt innholdet som ble gjengitt under denne iterasjonen. Sist, men ikke minst, kaller det clock.tick () metode for å kontrollere når neste iterasjon vil bli kalt.

 def run (selv): mens ikke self.game_over: self.surface.blit (self.background_image, (0, 0)) self.handle_events () self.update () self.draw () pygame.display.update () self.clock.tick (self.frame_rate)

Konklusjon

I denne delen har du lært grunnleggende om spillprogrammering og alle komponentene som er involvert i å lage spill. Da så vi på Pygame selv og hvordan den ble installert. Til slutt delved vi inn i spillarkitekturen og undersøkte katalogstrukturen, GameObject klassen og spillklassen. 

I del to ser vi på TextObject Klassen brukes til å gjengi tekst på skjermen. Vi lager hovedvinduet, inkludert et bakgrunnsbilde, og så lærer vi hvordan vi tegner gjenstander som ball og padle.

I tillegg kan du se hva vi har tilgjengelig for salg og for studier i Envato Market, og ikke nøl med å stille spørsmål og gi din verdifulle tilbakemelding ved å bruke feedet under.