Zavod svetega Stanislava Škofijska klasična gimnazija Programiranje v Pythonu Računalniška igra kača Maturitetna seminarska naloga iz Informatike Kandidat: Simon Golob Mentor: Helena Starc Grlj Šolsko leto 2018/19 Ljubljana Šentvid
Kazalo vsebine Kazalo vsebine Kazalo vsebine... 2 Stvarno kazalo... 3 Kazalo slik... 3 Povzetek... 4 Abstract... 4 Ključne besede... 4 Uvod... 5 Opredelitev problema... 5 Predstavitev problema... 6 2 Teoretični del seminarske naloge... 7 Problem gibanja... 7 Hrana in njen učinek pri povečavi... 7 Zaključek igre... 8 Poteza... 9 3 Praktični del seminarske naloge... 10 Koda... 10 3.1.1 Definiranje in postavitev temeljev pred pričetkom poteze... 10 3.1.2 Pričetek poteze... 12 Končni izgled... 14 4 Sklep... 15 Odprta vprašanja... 15 Količina dela... 16 5 Viri... 17 2
Stvarno kazalo hrana, 4, 7, 10, 12 igra, 5, 9, 15 kača, 4, 5, 6, 8, 9, 10, 15 konec, 4, 9, 11, 13 koordinate, 7, 8, 9, 11, 12, 13 Python, 4, 5, 10, 14, 15 Kazalo slik Tabela 1 Uporabljena strojna in programska oprema.... 5 Slika 1:Potek igre kača.... 6 Slika 2 Koordinatni sistem... 7 Slika 3 Delovanje novih teles Kx... 7 Slika 4:Digaram poteka algoritma za zaključek igre... 8 Slika 5 Naložimo Python in ga vključimo v PATH... 14 Slika 6 Naložimo modul pygame... 14 Slika 7 V IDLE zaženemo igro... 14 Slika 10 Smerne tipke, potrebne za igranje.... 15 Slika 11 Končni izgled računalniške igre Kača... 15 Grafikon 1 Količina opravljenega dela... 16 3
Povzetek V programskem jeziku Python sem sprogramiral računalniško igro Kača. V njej se na dvodimenzionalni ploskvi premika element kača, ki ga gledamo s ptičje perspektive. Kača se lahko premika gor, dol, levo in desno po polju. Premika se neprestano in mi ji, s pomočjo tipk, spremenimo smer gibanja. Na polju je tudi element hrana, če ga kača zaužije se njeno telo podaljša in pridobiš točke. Takrat se tudi hrana pojavi nekje drugje na polju. Igre je konec, če se kača zaleti v rob polja ali pa sama vase. Abstract I programmed a computer game Snake in a program language Python. In the game you play as a snake on a two-dimensional field from a bird s point of view. The snake can move up, down, left and right. It moves constantly and we can change its direction with the help of computer keys. On the field there is also a food element. If the snake eats it, the snake will grow longer, and you gain score. At that point food will appear somewhere else on the field. The game ends when the snake hits the side of the field or it bumps into itself. Ključne besede Python, kača, hrana, igra, konec 4
Uvod Opredelitev problema Od nekdaj sem si želel, da bi znal sprogramirati računalniško igro. S tem sem se ukvarjal že v različnih programih kot so npr. GameMaker. Ampak ker si želim naučiti vsaj osnove programiranja v programskem jeziku, sem se odločil, da bom sprogramiral eno igro v jeziku Python. Natančneje sem se odločil, da bom sprogramiral igro Kača, ker je dovolj osnovna in preprosta, da bi jo lahko kot začetnik naredil in ker sem to igro tudi sam veliko preigral v otroštvu. Cilj naloge je ustvariti delujočo računalniško igro Kača. V njej bi nadziral kačo, ki bi se premikala po omejenem prostoru in bi se z vsakim zaužitjem hrane podaljšala. Ne bi se smela zaleteti v rob in ne sama vase. Če se zaleti, bi se igra končala. Kača bi za podaljšanje zauživala hrano, ki bi se pojavila nekje na polju vsake toliko časa in bi z zaužitjem dobila tudi točke. Ker se kačino telo daljša in se vanj ne sme zaleteti, je igra z vsakim zaužitjem hrane težja, saj vedno večji del omejenega prostora prekriva kača. Igra je sprogramirana v jeziku Python, s pomočjo integriranega razvojnega območja PyCharm. Kar je bilo grafičnega dela, pa sem uporabil program Slikar. Ker z izdelavo iger v Pythonu, in z programskim jezikom Python na splošno; nimam pretiranih izkušenj, sem se moral veliko sam naučiti s pomočjo spletnih dokumentacij ali pa sem za pomoč povprašal mojega, v programiranju, bolj veščega prijatelja. Tabela 1 Uporabljena strojna in programska oprema. Strojna oprema Programska oprema Intel core i7-7500u Microsoft Windows 10 Pro RAM 8 GB Python 3.7 256 GB SSD Pycharm Nvidia Geforce 940MX Slikar FileZilla 5
Predstavitev problema Za začetek moram ugotoviti, kaj sploh želim doseči. Moj cilj je napraviti igro v kateri bi nadziral premikanje kače, torej gibanje. Cilj bi bil, da kača postane čim večja pred koncem igre. Kača pa zraste kadar zaužije hrano. In vsi algoritmi morajo biti izvedeni v nekem določenem obdobju, ki ga bom poimenoval poteza. Zdaj pa so se pred nami zvrstili naslednji problemi, za katere je ključno, da jih moram rešiti: Gibanje Hrana in njen učinek v povečavi Zaključek igre Poteza Slika 1:Potek igre kača. 6
2 Teoretični del seminarske naloge Problem gibanja Če želimo doseči gibanje moramo najprej definirati prostor. Jaz ga bom definiral z x in y koordinatama (mreža kot je na sliki 1). Ta prostor naj bo omejen z vseh strani. Zdaj ko imamo prostor, lahko v njega postavimo element, ki predstavlja kačjo glavo ali njen začetek (K1, ostala telesa kače so K1+x), ta, in ostala telesa, ima podatek, ki nam pove v katero smer se Slika 2 Koordinatni sistem premika (S). K1 ima na začetku S enak koordinatama (0,0). Ko igralec pritisne na tipko za spremembo smeri, se S v K1 spremeni po naslednjem ključu: če igralec vnese podatek za desno, se S spremeni iz (x,y) v (1,0); če vnese podatek za levo, se S spremeni v (-1,0); če vnese podatek za navzgor, se S spremeni v (0,1); če pa navzdol, se S spremeni v (0,-1). Program po časovnem razmiku izvede funkcijo premikanja v skladu z podatki, ki so zapisani v elementih. Hrana in njen učinek pri povečavi Element imenovan hrana (H), se pojavi nekje znotraj polja, kjer ni elementa K1 ali drugih K elementov. Pojavi se, ko K1 spremeni smer premikanja iz (0,0) v kateri koli drug (x,y). H se ponovno nekje pojavi, ko ima K1 S drugačen od (0,0) in na polju ni H (torej je H = 0). Ko so koordinate K1 enake H, ki je na polju, pridobimo element Kx, element H pa izgine iz polja. V naslednji potezi se nekje na polju ponovno pojavi H. Prav tako se šele v naslednji potezi pojavi na polju element Kx, ki ima koordinato od elementa K4x-1 (torej telesa ki je pred njim)(glej sliko2). 7 Slika 3 Delovanje novih teles Kx
Zaključek igre Igra se konča šele, ko naredi igralec napako. Napaki pa sta: ali se kača zaleti sama vase ali pa se zaleti v zid. Kača se zaleti sama vase, ko ima K1 enake koordinate kot katerikoli drug Kx. V zid pa se zaleti, ko so koordinate K1 zunaj koordinat omejenega polja. Slika 4:Digaram poteka algoritma za zaključek igre 8
Poteza Zelo pomembna pa je poteza. In vse funkcije, ki jih mora program opraviti. Razdeljena je na 3 dele izpis, pregledna in zapis. Na začetku poteze je izpis. V tej fazi program prebere podatke iz zapisne faze prejšnje poteze in izpiše potrebno. Tako se elementi postavijo na mesto, ki jim je zapisano v koordinatah. Tako se šele v tej fazi nariše kača in H. V kolikor je iz zapisne faze prejšnje poteze zapisano, da se je kača v tej potezi zaletela, se igra z izpisno fazo konča. Če je H = 0, kar se zgodi v zapisni fazi, potem H v tej izpisni fazi izgine. Pomembno pa je, da ta faza ni samo faza zapisa, saj v tej fazi tudi prejme podatek o spremembi smeri in se s tem spremeni S. V pregledovalni in zapisni fazi program pregleda stanje v prostoru in kakšno bo v naslednji potezi ter zapiše spremembe. Če je H = 0, se ta spremeni v H = 1 in nastane element Kx. Zdaj se zapišejo nove koordinate elementov kače. Naj prej zadnji element kače, Kx, za svoje koordinate prepiše koordinate prejšnjega elementa kače, Kx-1. Potem enako storijo vsi elementi kače do glave. Koordinate K1 pa se seštejejo s koordinatami S in se zapišejo kot koordinate K1. Zdaj pregleda kako bo v naslednji potezi. Primerja koordinate K1 s koordinatami ostalih elementov. Ko so koordinate enake koordinatam zidu (konca omejenega prostora) ali pa katerega izmed Kx, se zapiše konec igre, ki se izvede v izpisni faze naslednje poteze. Če se pa koordinate skladajo s koordinatami H, se to zapiše kot H = 0. 9
3 Praktični del seminarske naloge Koda Sledi koda, ki sem jo napisal v programskem jeziku Python. V njega sem poskušal pretvoriti zgoraj opisane rešitve problemov. Ustvaril sem element kača, ki se giblje po polju. Na ukaz spremeni smer gibanja. Na polju je tudi hrana, ki jo kača poje in se pri tem podaljša, hrana pa se pojavi nekje drugje na polju. Do konca igre pride, ko se kača zaleti v rob polja ali sama vase 3.1.1 Definiranje in postavitev temeljev pred pričetkom poteze #Za začetek prenesemo potrebne module import pygame import os import sys import random #Funkcija za iskanje datotek dir_name = os.path.dirname( file ) pygame.init() #Ustvarimo osnovne elemente in njihove slike glava_img = pygame.image.load(os.path.join(dir_name, 'Izolda.png')) glava = glava_img.get_rect() hrana_img = pygame.image.load(os.path.join(dir_name, 'Tristan.png')) hrana = hrana_img.get_rect() telo_img = pygame.image.load(os.path.join(dir_name, 'Izolda.png')) telo = telo_img.get_rect() pygame.display.set_caption("kača") #Elementi potrebni za glasbo (vir: https://github.com) pygame.mixer.music.load("cool_snake.mp3") pygame.mixer.music.play() pygame.mixer.music.set_volume(1) # določim dimenzije v naprej width = glava.width*32#mnogokratnik mora biti deljiv z deliteljem postavitelja height = glava.height*32 screen = pygame.display.set_mode((width, height)) black = 0, 0, 0 white = 255, 255, 155 Najprej uvozim module, s tem bomo pridobili funkcije potrebne za izrisovanje, naključje in druge potrebne za izdelavo računalniških iger. Funkcija: os.path.dirname(_file_) nam bo pomagala, da bo program znal najti potreben dokument. Uvozimo sliko (glava_img) in ustvarimo element (glava) ter ga definiramo tvorimo v pravokotnik (funkcija get.rect). Uvozim želeno glasbo, ki želimo da se predvaja med igranjem in jo predvajam. Definiram glasnost Določim velikost prostora in kako velik je program. Definiram tudi črno in belo barvo. 10
#postavim definicijo za konec igre game_over = False #Algoritem, da so začetne koordinate glave kače nekje naključno na polju hrana.x = ((random.randint(0,widthglava.width))//glava.width)*glava.width hrana.y = ((random.randint(0,widthglava.height))//glava.height)*glava.height glava.x = width / 4 glava.y = height / 4 #ostale potrebne spremenljivke (koordinate, točkovnik, ) zeit = 10 clock = pygame.time.clock() kor_y = 0 kor_x = glava.width score = 0 telo_x = [] telo_y = [] avto = 0 #Funkcija za točkovnik(vir: https://github.com) def _draw_score(score, location=((width/4)-glava.x, 2)): x, y = location pygame.draw.rect(screen, black, (x, y, 175, 300)) Definiramo, da na začetku ni konec igre. Hrano postavimo nekje na polje (random.radiant(od kod do kod)). Glavo pa postavimo na četrtino polja (od zgoraj levo). glava.x = postavitev telesa na x os glava.y = postavitev telesa n y osi Določimo ostale spremenljivke. kor je spremenljivka za smer gibanja glave (potem se sešteje koordinati glave) Telo_ sta tabeli ki vsebujejo x ali y koordinate teles Funkcija za izpis točk na zgornjem levem kotu polja. font = pygame.font.font('freesansbold.ttf', 24) text_score_label = font.render("točke", 1, white) screen.blit(text_score_label, (x, y)) text_score = font.render(str(score).rjust(3), 1, white) (_, height) = font.size("score") y = y + height screen.blit(text_score, (x, y)) return 11
3.1.2 Pričetek poteze #začetek igre while not game_over: # for i in range(len(telo_x)): telo.x = telo_x[i] telo.y = telo_y[i] #Če se glava v novi potezi zaleti v telo mora biti igre konec if glava.x == telo.x and glava.y == telo.y: game_over = True for event in pygame.event.get():#gre skozi tabelo, ki jo sestavljajo vse vstavljanje in tipke if event.type == pygame.quit: os.exit(1) #GIBANJE elif event.type == pygame.keydown and event.key == pygame.k_down and kor_y == 0: #preverba, da ne gre nazaj kor_y = glava.width kor_x = 0 elif event.type == pygame.keydown and event.key == pygame.k_escape: game_over = True #HRANA IN NJEN UČINEK PRI POVEČAVI if glava.y == hrana.y and glava.x == hrana.x: hrana.x = ((random.randint(0, width - glava.width)) // glava.width) * glava.width hrana.y = ((random.randint(0, width - glava.height)) // glava.height) * glava.height score += 10 Začetek poteze (traja dokler ni game_over = True) V zanki gre čez vse koordinate teles in jih primerja s koordinatami glave, če sta x in y koordinati enaki, bo game_over postal enak True. Če znotraj dogodka pritisnemo tipko (gre dol ali gor) se koordinate spremenijo ustrezno tipki, ki je bila pritisnjena, pod pogojem, da je bil kor,ki se spremeni, prej enak nič. (if kor_x=0 kor_x=nekaj) Če pa pritisnemo tipko escape, bo game_over postal enak True Če so koordinate glave enake koordinatam hrane, hrana dobi nove koordinate, dobiš deset točk in avto se poveča za ena. In se nadaljuje v pogojnik za nastanek novega telesa. avto += 1 #Nastanek novega telesa if telo_x == []: telo_x.append(glava.x) telo_y.append(glava.y) else: telo_x.append(telo_x[-1]) telo_y.append(telo_y[-1]) Če je tabela telo_x prazna se bodo v tabeli zapisale koordinate od glave (x in y posebej). Če ni prazna, se v tabelo zapišejo koordinate zadnjega telesa. 12
#Nove koordinate if telo_x!= []: for i in range(1,(len(telo_x))): telo_x[-i] = telo_x[-i-1] telo_y[-i] = telo_y[-i-1] telo_x[0] = glava.x telo_y[0] = glava.y glava.y += kor_y glava.x += kor_x #Pospeševanje if avto == 2: zeit += 1 avto = 0 clock.tick(zeit) if glava.x == -glava.width or glava.y == -glava.height or glava.x == width or glava.y == height: game_over = True #Risanje podlage screen.fill(black) _draw_score(score,) screen.blit(glava_img, glava) #Risanje teles for i in range(len(telo_x)): telo.x = telo_x[i] telo.y = telo_y[i] screen.blit(glava_img, telo) screen.blit(hrana_img, hrana) pygame.display.flip() pygame.quit() os._exit(1) Vsa telesa prevzamejo koordinate prejšnjega telesa. Prvo telo v tabeli pa prevzame koordinate glave. Koordinatam glave pa se sešteje kor_ Clock.tick nam upočasnjuje potezo da ne gre prehitro čez. Ko pa poješ dve hrani se malo pospeši. Če so koordinate glave, enake koordinatam robu polja je konec igre. Na koncu zanke poteze se vse izriše. Izriše se polje, točke, glava. Potem se z zanko izrišejo vsa telesa iz tabele telo_. Nariše še hrano. 13
Končni izgled Končni izdelek je v pythonova skripta. Za uporabo potrebujemo tolmač za Python in modul pygame. Zato najprej naložimo Python. Naložimo ga lahko s spletne strani https://www.python.org/downloads/. Pri tem pazimo, da vklučimo Python v PATH (slika 5). Slika 5 Naložimo Python in ga vključimo v PATH Ko je Python naložen, odpremo ukazni poziv (v iskalnik napišemo:»cmd«) in vpišemo:»pip install pygame«(slika 6). Slika 6 Naložimo modul pygame V IDLE (v iskalnik napišemo idle) odpremo datoteko sanke.py (moja računalniška igra na priloženem dvd-ju) in jo zaženemo tako, da pritisnemo f5 ali med orodnimi vrsticami odpremo Run in pritisnemo na Run Module. Slika 7 V IDLE zaženemo igro 14
Potem se zažene igra (slika10). Za igro uporabljamo smerne tipke (slika 11). Kača je kvadrat bele barve, ki se takoj ob pričetku začne premikati desno. Hrana je kvadratek rdeče barve. V zgornjem desnem kotu pa so izpisane točke Slika 8 Smerne tipke, potrebne za igranje. Slika 9 Končni izgled računalniške igre Kača Hitrost kače se vedno, potem ko zaužije dve hrani, poveča. Ko pa gre kača izven okvirja, oziroma se zaleti v steno, se igra konča in se okno z igro samo zapre. Enako se zgodi če se kača zaleti v lastno telo. 4 Sklep S svojo seminarsko nalogo sem zadovoljen. Glede na to, da na začetku leta nisem znal programirati in sem prvič programiral računalniško igro v programskem jeziku Python, ki ni najboljši programski jezik za programiranje računalniških iger. Po navadi metoda izdelave iger tudi ne poteka od niča naprej, ampak za to uporabljajo programe, ki imajo že vsa orodja sprogramirana, tako lahko naredijo bolj kvalitetno igro, kot če začneš vse iz niča. Zato moja igra ni najboljša, ampak sem dosegel pričakovane cilje. Odprta vprašanja Program ima kar nekaj napak, ki sem jih skušal popraviti ampak nisem znal. Za primer kača lahko, če prehitro tipkaš gre nazaj sama vase, kar se v kodi, ki sem jo napisal, ne bi smelo zgoditi. Prav tako kača malo zaostaja in se ne premakne takoj, ko pritisneš tipko za spremembo smeri, kar napravi igro boj okorno. Prav tako bi bilo veliko bolje če bi dodal še dva zaslona. 15
Eden bi bil na začetku kjer bi bil naslov in gumb»start«in tako igralec ne bi bil takoj vržen v igro, ampak ima čas da se na tem prvem zaslonu pripravi in malo pozanima o delovanju igre. Zdaj ko umreš, se program izklopi. Veliko bolje bi bilo če bi namesto tega, ko umreš, prešel na zaslon, kjer bi bila prikazana tabela najboljših točkovnih dosežkov,»highscore«, in kje so na njej tvoje točke. Poleg tega pa bi bil na zaslonu»restart«gumb, ki bi ponovil igro. Količina dela Spodaj prikazani grafikon prikazuje koliko časa sem porabil na posameznem delu ustvarjanja te maturitetne seminarske naloge. Število ur pri posameznem delu naloge 20 18 16 14 12 10 8 6 4 2 0 Učenje pisanja v Pythonu Izdelava teoretične zasnove Izdelava praktičnega dela Konzultacije Izdelava dokumentacije Izdelava spletne strani Število ur pri posamenem delu naloge Grafikon 1 Količina opravljenega dela 16
5 Viri WECHTERSBACH, Rado. 2005. Informatika: Učbenik za srednje izobraževanje. 2. Ljubljana: Saji. ISBN 961-91143-1-0. Pygame dokumentacija (online) [uporabljeno 20. 3. 2019] dostopno na: https://www.pygame.org/docs/> Github dokumentacija pygame (online) [uporabljeno 11. 2. 2019] dostopno na: https://github.com/> W3schools Html (online) [uporabljeno 25. 3. 2019] dostopno na: https://www.w3schools.com/html/default.asp W3schools Python (online) [uporabljeno 25. 3. 2019] dostopno na: https://www.w3schools.com/python/default.asp 17