Ahogy említettem már, a Surface egy olyan objektum, amely egy felületet reprezentál, amire rajzolhatunk. De nem csak rajzolhatunk rájuk, hanem betölthetünk képállományokat "beléjük", ezzel a játék egyes elemeit nem vagyunk kénytelenek a pygame nehézkes és soványka rajzolóképességeivel előállítani, hanem használhatunk komoly grafikai szoftvereket ezek elkészítésére.
Javaslom mindenkinek az Inkscape használatát, mert vektoros (emellett ópenszósz és ingyenes), így ha később változtatni akarunk a felbontáson, egyszerűen más mérettel exportáljuk ki a rajzainkat.
Fejlesszül tovább pattogó labdánkat, és csináljunk egy jobban kinéző labdát!
Ehhez csináltam egy strandlabdaszerűséget négy fázissal, hogy úgy nézzen ki mintha forogna pattogás közben. Elég gagyi lett mert csak összeférceltem, de arra, amit mutatni szeretnék, tökéletesen megfelel.
Nézzük a feladatot!
Azt szeretnénk csinálni, hogy a forgó strandlabdánk egy szürke "kockás" háttér felett mozogva pattogjon nekünk az ablakunkban. Hogyan tudjuk ezt elérni?
Nos, kell egy háttérkép, aztán egy labda, aminek a képét cserélgetjük, ezzel keltve a forgó hatást. A mozgatás hasonlóan megy az előző részben megismertekhez.
Hogy fog működni a programunk?
Csinálunk egy háttérkép, és egy labda objektumot. A főciklusban kirajzoljuk a háttérképet, elvégezzük a labda mozgatását, frissítjük a labda aktuális fázisát, és kirajzoljuk. Megnézzük történt-e lekezelendő esemény (pl. ablak bezárás) amit lekezelünk, majd várakozunk a megadott fps betartásához, és kezdjük elölről.
Nem hangzik túl bonyolultnak ugye? Hogy mégis az legyen, objektumorientáltan készítjük el ;)
A főciklusunk a következően fog kinézni:
# fő ciklus # ismétlődik amíg ki nem lépünk while True: render() # aktuális képkocka létrehozása # ki akart lépni a felhasználó? if kilep(): pygame.quit() sys.exit() # kirakjuk az ablak tartalmát a képernyőre pygame.display.flip() # szabályozzuk a futási sebességet clock.tick(fps)
- vagyis -
kirajzolunk egy képkockát, megnézzük az előző képkocka óta bekövetkezett eseményeket - jelen esetben csak a kilépési szándékot vizsgáljuk -, frissítjük a képernyőt, és szabályozzuk a futási sebességet, majd kezdjük ezeket előlről.
Eddig nem bonyolult. Most nézzük meg, hogyan hozzuk létre a képkockát:
def render(): screen.blit(hatter,hatter.rect) labdak.update() labdak.draw(screen)
Szavakban: rakjuk a képernyőre a hátteret, frissítsük a labdákat, és rajzoljuk ki őket.
Hát ez sem tűnik bonyolultnak... De azért álljunk meg egy kicsit. Adós vagyok még a hatter és labdak objektumok bemutatásával, de előtte a blit metódusról ejtünk szót.
A screen ugye nem felejtettük el, hogy egy pygame.Surface, amire rajzolni lehet. A Surface objektumoknak van egy blit metódusa (BLock Image Transfer), aminek segítségével más Surface objektumok képét lehet rájuk rajzolni. Ennek két paramétert kell adni, mit akarunk kirajzolni, és hova. A mit egy másik Surface objektum kell legyen, a hova pedig egy pygame.Rect objektum. A Rect tulajdonképpen egy téglalap, amit megadhatnánk a bal felső sarkának két koordinátájával, és szélességi, magassági adatával is, ám a Rect objektum használatának előnye az, hogy ő a téglalap több adatát menedzseli, amelyeket le lehet kérdezni (pl. középpont, alsó koordináta, jobb alsó sarok koordinátája, stb.). Ezek automatikusan módosulnak, ha a téglalap valamelyik adata módosításra kerül.
A labdak objektum itt egy pygame.sprite.Group. Aki nem találkozott még játékprogramok készítésével, a sprite szó nem mond semmit. A szó maga manót jelent, de az ősjátékok kialakulásakor ez az alapvető mozgatható grafikai elemet takarta, aminek van grafikája, fázisai, mérete, pozíciója, stb. A group csoportot jelent, vagyis a labdak egy sprite-okból álló csoport. A labdak.update() a csoport minden tagját frissíti (mozgatja, és ha kell fázist módosít), majd a labdak.draw(screen) kirajzolja a csoport minden elemét a screen felületünkre.
A két objektumunk bemutatása előtt még egy kitérőt teszünk, megnézzük, hogy a főciklus indítása előtt miket állítottunk be.
# ablak megjelenítése és a játékadatok beállítás SCREEN_SIZE = (800,600) # ablak mérete screen = pygame.display.set_mode(SCREEN_SIZE) # ablak "surface" hatter = Hatter(SCREEN_SIZE,50,((192,192,192),(255,255,255))) labdak = pygame.sprite.Group() labdafazisok = [pygame.image.load('labda1.png').convert_alpha(),pygame.image.load('labda2.png').convert_alpha(),pygame.image.load('labda3.png').convert_alpha(),pygame.image.load('labda4.png').convert_alpha()] labda = Labda(labdafazisok,[6,5],SCREEN_SIZE,5,group = labdak) fps = 30
Megalkotjuk ugye a screen felületünket, elkészítjük a hatter objektumot a Hatter nevű classunkból, definiáljuk a labdak sprite csoportot.
Betöltjük a labdafázisokat a labdafazisok listába. Ehhez a pygame.image.load-ot használjuk, ami egy képfájlt betöltve Surface objektumokat hoz létre. Ahhoz, hogy a blit utasítások hatékonyak legyenek a sebességet tekintve, érdemes a Surface objektumok képadatait egy belső formátumra konvertálni, erre szolgál a Surface objektumok convert() és convert_alpha() metódusa. Ez utóbbit akkor használjuk, ha kép átlátszó területeket alkalmaz. Ha ezt a konvertálást nem végezzük el, a blit metódusok menet közben elvégzik minden alkalommal automatikusan, de ez természetesen hatással van a kész játék futási sebességére és processzoréhségére.
Elkészítjük a labda objektumot a Labda classunkból, és beállítjuk az fps változót, amit a főciklus időzítésénél használunk.
Elérkeztünk classaink bemutatásához, nézzük tehát, hogyan is néznek ki.
A Hatter class:
class Hatter(pygame.Surface): def __init__(self,size,msize,colors): super(Hatter,self).__init__(size) self.rect = self.get_rect() xq = size[0] / msize yq = size[1] / msize colorindex = 0 for y in range(yq): firstcolor = colorindex for x in range(xq): pygame.draw.rect(self,colors[colorindex],(x*msize,y*msize,msize,msize),0) colorindex = 0 if colorindex == 1 else 1 colorindex = 0 if firstcolor == 1 else 1
Látható, hogy egy származtatott Surface osztályról van szó. A lényege, hogy a megadott méretek és színek alapján egy "kockás" felületet hoz létre (tessék játszani a paraméterekkel bátran...).
A Labda class:
class Labda(pygame.sprite.Sprite): def __init__(self,imagelist,vector,screen_size,animspeed = 15, startpoint = [0,0],group = None): super(Labda,self).__init__() self.imagelist = imagelist self.image = self.imagelist[0] self.rect = self.image.get_rect() self.rect.topleft = startpoint self.index = 0 self.phases = len(self.imagelist) - 1 self.vector = vector width = self.rect.width height = self.rect.height self.xlimits = (0,screen_size[0] - width) self.ylimits = (0,screen_size[1] - height) self.speed = animspeed self.counter = 0 if group != None: self.add((group)) def update(self): x = self.rect.topleft[0] + self.vector[0] y = self.rect.topleft[1] + self.vector[1] if x < self.xlimits[0]: x = self.xlimits[0] self.vector[0] = -self.vector[0] if x > self.xlimits[1]: x = self.xlimits[1] self.vector[0] = -self.vector[0] if y < self.ylimits[0]: y = self.ylimits[0] self.vector[1] = -self.vector[1] if y > self.ylimits[1]: y = self.ylimits[1] self.vector[1] = -self.vector[1] self.rect.topleft = x, y self.counter += 1 if self.counter > self.speed: self.counter = 0 self.index += 1 if self.index > self.phases: self.index = 0 self.image = self.imagelist[self.index]
Labda osztályunk egy olyan származtatott pygame.sprite.Sprite osztály, amely tárolja a saját animációs fázisait, a labda sebességét, az animáció sebességét, a pozícióját, és már az objektum létrehozásakor hozzáadható egy létező sprite-group-hoz.
Az update() metódusa a beállított sebességadatok alapján megváltoztatja a labda pozícióját, az animációsebesség alapján pedig a fázisát. Tessék elemezni, ha valami nem érthető akkor meg kérdezni!
A kész alkotásról egy képernyőkép:
És itt a teljes forráskód egyben:
#!/usr/bin/env python # -*- coding:utf8 -*- import sys,pygame from pygame.locals import * # pygame inicializálása pygame.init() class Hatter(pygame.Surface): def __init__(self,size,msize,colors): super(Hatter,self).__init__(size) self.rect = self.get_rect() xq = size[0] / msize yq = size[1] / msize colorindex = 0 for y in range(yq): firstcolor = colorindex for x in range(xq): pygame.draw.rect(self,colors[colorindex],(x*msize,y*msize,msize,msize),0) colorindex = 0 if colorindex == 1 else 1 colorindex = 0 if firstcolor == 1 else 1 class Labda(pygame.sprite.Sprite): def __init__(self,imagelist,vector,screen_size,animspeed = 15, startpoint = [0,0],group = None): super(Labda,self).__init__() self.imagelist = imagelist self.image = self.imagelist[0] self.rect = self.image.get_rect() self.rect.topleft = startpoint self.index = 0 self.phases = len(self.imagelist) - 1 self.vector = vector width = self.rect.width height = self.rect.height self.xlimits = (0,screen_size[0] - width) self.ylimits = (0,screen_size[1] - height) self.speed = animspeed self.counter = 0 if group != None: self.add((group)) def update(self): x = self.rect.topleft[0] + self.vector[0] y = self.rect.topleft[1] + self.vector[1] if x < self.xlimits[0]: x = self.xlimits[0] self.vector[0] = -self.vector[0] if x > self.xlimits[1]: x = self.xlimits[1] self.vector[0] = -self.vector[0] if y < self.ylimits[0]: y = self.ylimits[0] self.vector[1] = -self.vector[1] if y > self.ylimits[1]: y = self.ylimits[1] self.vector[1] = -self.vector[1] self.rect.topleft = x, y self.counter += 1 if self.counter > self.speed: self.counter = 0 self.index += 1 if self.index > self.phases: self.index = 0 self.image = self.imagelist[self.index] # ablak megjelenítése és a játékadatok beállítás SCREEN_SIZE = (800,600) # ablak mérete screen = pygame.display.set_mode(SCREEN_SIZE) # ablak "surface" hatter = Hatter(SCREEN_SIZE,50,((192,192,192),(255,255,255))) labdak = pygame.sprite.Group() labdafazisok = [pygame.image.load('labda1.png').convert_alpha(),pygame.image.load('labda2.png').convert_alpha(),pygame.image.load('labda3.png').convert_alpha(),pygame.image.load('labda4.png').convert_alpha()] labda = Labda(labdafazisok,[6,5],SCREEN_SIZE,5,group = labdak) fps = 30 def kilep(): """kilep(): Megnézi, hogy megnyomták-e az ESC gombot vagy megpróbálták bezárni az ablakot""" for event in pygame.event.get(): if event.type==QUIT: return True elif (event.type==KEYDOWN and event.key==K_ESCAPE): return True return False def render(): screen.blit(hatter,hatter.rect) labdak.update() labdak.draw(screen) # ezzel az objektummal tudjuk szabályozni a játék sebességét clock = pygame.time.Clock() # fő ciklus # ismétlődik amíg ki nem lépünk while True: render() # aktuális képkocka létrehozása # ki akart lépni a felhasználó? if kilep(): pygame.quit() sys.exit() # kirakjuk az ablak tartalmát a képernyőre pygame.display.flip() # szabályozzuk a futási sebességet clock.tick(fps)
Vajon mi történik, ha a labda = ... sor alá beteszünk még egy sort ezzel a tartalommal?
labda2 = Labda(labdafazisok,[4,9],SCREEN_SIZE,4,group = labdak)
Tessék kipróbálni!
A kövektező résznél van problémám:
VálaszTörlésxq = size[0] / msize
yq = size[1] / msize
colorindex = 0
for y in range(yq):
firstcolor = colorindex
A kövektező a hibaüzenet:
TypeError: 'float' object cannot be interpreted as an integer
Megoldás
xq = size[0] // msize
yq = size[1] // msize
colorindex = 0
for y in range(yq):
firstcolor = colorindex
Jogos, valóban, python3-tól ;)
VálaszTörléspython 2.7-nél a '/' int-et ad vissza, ha az osztandó is int
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 800.0/15
53.333333333333336
>>> 800/15
53
Play Free Casino Web Apps in Costa Rica
VálaszTörlésHere you will find all your favorite social casinos 카지노사이트 available in Costa Rica. Browse our list of the best social casino 바카라 사이트 apps to play free slots and table 다파벳 games