Skip to content

Kõik WordPressist, veebiarendusest — ja mitte ainult

🎮 Esimene mäng Pygame'iga: Pythonis nullist kirjutamine

🎮 Esimene mäng Pygame'iga: Pythonis nullist kirjutamine

Tahad kirjutada oma esimest mängu, aga ei tea, kust mänguarendusega alustada? Pygame eemaldab selle tõkke. Kirjutad puhtas Pythonis ja näed kohe tulemust ekraanil: liikuv sprait, klaviatuurisisendi reaktsioon, elavad mehaanikad. Ei mingeid raskeid mootoreid ega tuhandeid ridu baaskoodi.

Enamiku õpetuste probleem on see, et need kas matavad sind 40 lehekülje teooria alla või jätavad su olukorda „tee ise lõpuni". Siin valime kesktee: selgitame täpselt nii palju, et saad igast reast aru, ja ehitame kohe töötava mängu, kus tegelane liigub WASD-klahvidega üle ekraani. Kogu kood mahub 60 rea sisse.

💡 Kiire ülevaade:

  • Paigalda Pygame pip kaudu ja loo mängufail, see võtab paar minutit
  • Mõista mängutsüklit: sündmused, arvutused, renderdamine, kolm faasi, mis elavad lõputus while True sees
  • Kirjuta mängija klass ja too see ellu: WASD-klahvid liigutavad spraiti, ekraan joonistub ümber 60 korda sekundis
  • Mõista koordinaatsüsteemi ja värvikäsitlust, kaht nurgakivi, mis toetavad igasugust 2D-graafikat

Mis on Pygame ja miks seda valida

Pygame on Pythoni teek, mis mähib multimeedia SDL-i (Simple DirectMedia Layer) mugavasse Pythoni API-sse. SDL tegeleb madala taseme graafika, heli ja sisendseadmete tööga, samas kui Pygame pakub juurdepääsu tuttavate klasside ja meetodite kaudu. Praegune versioon 2.6.0 on aktiivselt hooldatud ja töötab Windowsis, macOS-is ja Linuxis.

Algajatele on Pygame'il kolm vaieldamatut eelist. Esiteks, madal sisenemisbarjäär: kasutad tavalist Pythoni koodi, ei mingit uut keelt ega visuaalset redaktorit. Teiseks, kohene tagasiside: kirjutad pygame.draw.rect(...) ja ekraanile ilmub ristkülik, ei mingit maagiat. Kolmandaks, aluste mõistmine: Pygame ei peida sinu eest mängutsüklit ja sündmuste järjekorda, sa näed, kuidas ükskõik milline mäng seestpoolt töötab. Pärast Pygame'i on Godot'le või Unityle üleminek lihtsam, sest sa juba tead, mis on delta-aeg ja sündmuste küsitlemine.

See teek ei püüa olla mängumootor. Sellel pole stseenisüsteemi, füüsikat ega sisseehitatud tasemeredaktorit ja see on teadlik otsus. Sina kontrollid iga pikslit ja iga tiksu, mis tähendab, et õpid mõtlema nagu mänguarendaja, mitte nagu kellegi teise tööriista operaator.

Pygame'i paigaldamine kahe minutiga

Kas sul on juba Python 3.9 või uuem? Siis ava terminal ja käivita üks käsk:

1pip install pygame

Projekti isoleerimiseks on parem luua virtuaalkeskkond:

1python -m venv game_env
2game_env\Scripts\activate # Windows
3source game_env/bin/activate # macOS / Linux
4pip install pygame

Kontrolli, et teek on paigaldatud:

1import pygame
2print(pygame.version.ver)

Kui vastuseks tuleb 2.6.0 (või uuem, praegust versiooni saad kontrollida pygame.org-ist), oled valmis. Loo projektikaust, pane sinna suvaline 80×80 piksline spraidipilt nimega player.png ja tekstifail game.py, alustame sellest.

Kuidas mängutsükkel töötab: sündmused, arvutused, renderdamine

Iga mängu süda on peatsükkel. Kuni mäng töötab, vahelduvad lõputu while True sees kolm faasi:

  • Sündmuste töötlemine, mis juhtus pärast eelmist kaadrit? Klahvivajutus? Hiire liikumine? Akna sulgemine? Pygame kogub kõik sündmused järjekorda ja me itereerime selle üle for event in pygame.event.get() abil.

  • Loogika arvutamine, kuidas maailm sündmustele reageerides muutus? Mängija vajutas W, suurenda Y-koordinaati. Kuul põrkas asteroidiga kokku, märgi mõlemad eemaldamiseks.

  • Renderdamine, joonista kõik, mis peaks ekraanil olema. Täida taust, aseta spraidid uutele koordinaatidele, kutsu välja pygame.display.update() ja mängija näeb kaadrit.

Need kolm sammu korduvad 60 korda sekundis, täpselt see kaadrisagedus (FPS), mille me taimerile seame. Liikumise illusioon põhineb sellel, et sprait nihkub kaadrite vahel paar pikslit, samal ajal kui silm tajub seda pideva animatsioonina.

Esimese koodi kirjutamine: spraidi liigutamine üle ekraani

Siin on täielik mängukood. Salvesta see kui game.py ja aseta player.png samasse kausta:

1#!/usr/bin/env python3
2
3import pygame
4import sys
5
6WIDTH, HEIGHT = 360, 480
7WHITE = (255, 255, 255)
8
9class Player(pygame.sprite.Sprite):
10
11 def __init__(self, image_path):
12 super().__init__()
13 self.image = pygame.image.load(image_path)
14 self.x = WIDTH / 2
15 self.y = HEIGHT / 2
16 self.speed = 5
17
18 def move(self, dx, dy):
19 self.x += dx
20 self.y += dy
21
22def main():
23 pygame.init()
24 screen = pygame.display.set_mode((WIDTH, HEIGHT))
25 pygame.display.set_caption("First Game on Pygame")
26
27 clock = pygame.time.Clock()
28 fps = 60
29
30 player = Player("player.png")
31 dx, dy = 0, 0
32
33 running = True
34 while running:
35 for event in pygame.event.get():
36 if event.type == pygame.QUIT:
37 running = False
38
39 elif event.type == pygame.KEYDOWN:
40 if event.key == pygame.K_d:
41 dx = player.speed
42 elif event.key == pygame.K_a:
43 dx = -player.speed
44 elif event.key == pygame.K_w:
45 dy = -player.speed
46 elif event.key == pygame.K_s:
47 dy = player.speed
48
49 elif event.type == pygame.KEYUP:
50 if event.key in (pygame.K_d, pygame.K_a):
51 dx = 0
52 elif event.key in (pygame.K_w, pygame.K_s):
53 dy = 0
54
55 player.move(dx, dy)
56 screen.fill(WHITE)
57 screen.blit(player.image, (player.x, player.y))
58 pygame.display.update()
59 clock.tick(fps)
60
61 pygame.quit()
62 sys.exit()
63
64if __name__ == "__main__":
65 main()
80x80 mängijasprite ekraanil liikumiseks

Käivita python game.py, avaneb aken valge tausta ja sinu spraidiga keskel. Hoia all W, A, S või D, tegelane liigub. Lase lahti, ta peatub. See on juba päris mäng, olgugi minimaalne.

Mis on võrreldes klassikaliste õpetustega paremaks tehtud: lisatud on KEYUP töötleja klahvi vabastamise jaoks. Ilma selleta rändaks sprait pärast esimest vajutust igaveseks ekraanilt välja. Ja kood on mähitud if __name__ == "__main__" konstruktsiooni, hea tava, mis võimaldab faili moodulina importida ilma mängu käivitamata.

Koordinaatsüsteem ja värvikäsitlus

Pygame'is loetakse koordinaate ülemisest vasakust nurgast: (0, 0), päris üleval vasakul. Paremale liikudes X suureneb, alla liikudes Y suureneb. See erineb kooli koordinaatsüsteemist, kus Y kasvab ülespoole, lihtsalt jäta see meelde ja kontrolli end esimestel käivitustel: vajutasid S, sprait liikus alla, vajutasid W, üles.

Värv määratakse kolmest numbrist koosneva ennikuga (R, G, B), igaüks vahemikus 0 kuni 255. Valge vastab väärtusele (255, 255, 255), must vastab väärtusele (0, 0, 0), punane vastab väärtusele (255, 0, 0). Meetod screen.fill(WHITE) täidab enne iga kaadri renderdamist kogu ekraani valitud värviga. Kui sa seda ei tee, jätab sprait endast eelmiste asukohtade jälje.

Mis toimub kapoti all: rida-realt lahtiseletus

Klass Player pärib klassist pygame.sprite.Sprite, Pygame'i sisseehitatud klassist mänguobjektide jaoks. Konstruktoris laeme pildi pygame.image.load() abil ja seame algpositsiooni ekraani keskele: WIDTH / 2 ja HEIGHT / 2. Meetod move(dx, dy) võtab vastu nihke ja liidab selle praegustele koordinaatidele, puhas aritmeetika, ei mingit maagiat.

Funktsioon main() toob kõik kokku. pygame.init() käivitab sisemised alamsüsteemid. pygame.display.set_mode() loob akna ja screen on pind (Surface), millele me joonistame. pygame.time.Clock() loob taimeri: selle tick(fps) meetod tsükli lõpus ütleb Pygame'ile „oota, kuni eelmisest kaadrist on möödunud 1/60 sekundit", nii fikseerime kaadrisageduse ega raiska protsessorit.

Peatsükkel while running pöörleb seni, kuni lipp running muutub väärtuseks False. Sees on kolm faasi, millest eespool rääkisime:

Pygame mänguaken tegelase spraidiga valgel taustal

Tsüklis for event in pygame.event.get() küsitleme sündmuste järjekorda. pygame.QUIT on signaal „kasutaja vajutas akna sulgemise nuppu": sea running = False ja järgmisel iteratsioonil tsükkel lõpeb. pygame.KEYDOWN käivitub, kui klahv alla vajutatakse, ja KEYUP, kui see vabastatakse. D ja A puhul muudame dx, W ja S puhul muudame dy. Kui klahv vabastatakse, nullime vastava kiiruskomponendi, sprait peatub.

screen.blit(player.image, (player.x, player.y)), meetod, mis „asetab" ühe pildi teise peale. Meie juhul mängija spraidi peamisele ekraanipinnale praegustel koordinaatidel. pygame.display.update() värskendab akent ja mängija näeb valmis kaadrit.

Märkus: player.move() kutsutakse välja enne screen.fill(). Kui need ära vahetada, kustutatakse sprait samal millisekundil, kui see ilmub, sa lihtsalt ei näe seda ekraanil. Tehete järjekord mängutsüklis on kriitiline.

Vajuta sulgemisnuppu, pygame.quit() laadib Pygame'i alamsüsteemid korrektselt maha ja sys.exit() lõpetab Pythoni protsessi. Ilma pygame.quit()-ita võib aken sulgemisel hanguda, väike detail, aga kood peaks olema puhas.

Lühike video teemal

Kui tekstijuhis päriselt kohale ei jõua, siis siin on suurepärane ingliskeelne videokursus, kus ehitatakse Pygame'iga samm-sammult Space Invaders. Kõiki artikli kontseptsioone näidatakse otse-eetris:

⁉️🤔 Korduma kippuvad küsimused

Kas mul on Pygame'i jaoks vaja OOP-d osata?

Jah, algtasemel. Klasse, meetodeid, pärimist ja self-i läheb sul esimesest päevast vaja: mängija, vaenlased, kuulid ja boonused sobituvad loomulikult objektmudelisse. Kui oled läbinud mõne Pythoni sissejuhatava kursuse, mis selgitas class ja __init__, siis sellest piisab. Ülejäänu omandad töö käigus: Pygame ei nõua disainimustreid, tavalisest Sprite-pärimisest piisab kümnetele prototüüpidele. Mänguobjekt Pygame'is on klass, mis pärineb pygame.sprite.Sprite-ist. Konstruktoris laed spraidi pygame.image.load() abil, määrad algkoordinaadid ja kiiruse. update() meetod (või sinu enda, nagu move()) muudab igas kaadris asukohta. Peatsükkel kutsub kõigil objektidel välja update() ja seejärel renderdab need screen.blit() abil. Ei mingit maagiat, lihtsalt meetodite väljakutsumine õiges järjekorras 60 korda sekundis.

Kas Pygame muutub keeruka 2D-graafika puhul aeglaseks?

Mõistliku spraitide arvu juures mitte. Pinnad (Surfaces) Pygame'is elavad RAM-is ja blit on kiire pikslite kopeerimine, mitte tarkvaraline renderdamine. Tuhande samaaegselt liikuva objektiga võid tabada Pythoni jõudluse piiri, kuid platvormimängu, ülalt-alla tulistamismängu või tornikaitse jaoks on varu olemas. Kui on vaja maksimaalset jõudlust välja pigistada, kasuta pygame.sprite.Group automaatse renderdamise ja määrdunud ristkülikutega (dirty rectangles) osaliste ekraaniuuenduste jaoks.

Kas ma saan Pygame'is heli ja muusikat lisada?

Jah, kohe karbist välja. Moodul pygame.mixer oskab mängida WAV-i ja MP3-te. Lasuheli käivitatakse pygame.mixer.Sound("shoot.wav").play() abil ja taustamuusika laetakse pygame.mixer.music.load("theme.mp3") ja pygame.mixer.music.play(-1) abil (lipp -1 kordab seda lõputult). Ainus nüanss: pygame.mixer.init() tuleb enne helide laadimist välja kutsuda ja MP3 jaoks Linuxis võib vaja minna libmpg123 teeki.

Kas on mõtet 2026. aastal Pygame'i õppida, kui olemas on Godot ja Unity?

Absoluutselt. Pygame ei ole Godot' konkurent, see on hariduslik tööriist ja kerge kiht 2D-prototüüpide jaoks. Sa ei õpi C#-i selleks, et ruutu liigutada, ega hakka Pong'i jaoks sõlmesüsteemi (node system) nuputama. Pygame annab sulle arusaama, kuidas mängud madalamal tasemel töötavad: mängutsükkel, kaadripuhverdus, kokkupõrked. Programmeerijatel, kes alustasid Pygame'iga, on Unity ja Godot'ga lihtsam, sest nad näevad mootori abstraktsioonide taga elavaid mehaanikaid. Pygame'is kirjutatakse päris indie-projekte, sealhulgas kommertsprojekte, väikese platvormimängu või pusle saab Steamis välja anda ilma C++-i puutumata.

Mida teha, kui sprait läheb ekraanilt välja?

Lisa move() meetodisse piirikontroll: kui self.x < 0, sea see väärtusele 0; kui self.x + sprite_width > WIDTH, sea see väärtusele WIDTH - sprite_width. Sama Y jaoks. Seda nimetatakse piiramiseks (clamping) ja ilma selleta rändab tegelane lõpuks nähtamatule alale. Keerukamates mängudes on piirid taseme seinad, mis on määratletud paanide ruudustiku (tile grid) või kokkupõrkemaatriksi kaudu.

Valmis oma esimest mängu käivitama?

Kopeeri kood jaotisest „Esimese koodi kirjutamine", salvesta see kui game.py, aseta suvaline spraidipilt selle kõrvale ja mõne sekundi pärast näed akent liikuva tegelasega. See on sisenemispunkt mänguarendusse: mitte lugemine, vaid käivitamine ja parameetrite näppimise alustamine.

Muuda WIDTH ja HEIGHT, aken läheb suuremaks. Sea player.speed = 10, tegelane liigub kiiremini. Asenda WHITE väärtusega (35, 35, 35), saad tumeda tausta. Eksperimenteeri ja saad aru, et mänguprogramm ei ole maagia, vaid sammude jada, mida sina kontrollid.

Kui liikumine on selge, võta ette kokkupõrked (pygame.sprite.collide_rect()), animatsioon (spraidilehe kaadrite vahetamine) ja protseduraalne tasemete genereerimine. Alustuseks piisab ühest game.py failist ja soovist mõista, kuidas see töötab.