A Personal Zoo or A Little About Pygame - Part 1
For those who are not in the know: Pygame is a very, very good framework for developing games in the Python language. Moreover, not only work with 2D and 3D is supported, but you can also install binders to many popular graphic and physical engines if you wish. By the way, Pygame doesn’t need to be used specifically for games, you can also create programs with an unusual interface, for example, some kind of three-dimensional frontend to the database.
So, in fact, I wanted to talk about the basic principles of working with this framework, you never know, maybe someone will come in handy :)
Let's go!
In order to access Pygame classes and methods, it must be initialized. By the way, the global game timer starts when the module is initialized, and the programmer, in turn, at any time can get the time in seconds from the very beginning of the initialization. Create a simple window:
Copy Source | Copy HTML- import pygame
- from pygame.locals import *
-
- def init_window():
- pygame.init()
- window = pygame.display.set_mode((550, 480))
- pygame.display.set_caption('My own little world')
-
- def main():
- init_window()
-
- if __name__ == '__main__': main()
I designed the code in a C-like manner, so it is easier to read. Actually, there is nothing to perceive so far :) First, we import the necessary modules (for sishnikov - describe the namespace), then initialize the framework, create a window with dimensions of 550 by 480 and give it the title “My own little world”.
I think those who tried to run this code noticed that the window disappears immediately after the appearance. This is because we have not yet described a global infinite loop for receiving messages, so the window just has nothing to do. Correct this mistake:
Copy Source | Copy HTML- import sys
- import pygame
- from pygame.locals import *
-
- def init_window():
- pygame.init()
- window = pygame.display.set_mode((550, 480))
- pygame.display.set_caption('My own little world')
-
- def input(events):
- for event in events:
- if (event.type == QUIT) or (event.type == KEYDOWN and event.key == K_ESCAPE):
- sys.exit(0)
- else:
- pass
-
- def action():
- while 1:
- input(pygame.event.get())
-
- def main():
- init_window()
- action()
-
- if __name__ == '__main__': main()
As we can see, an endless cycle of receiving messages starts. If the message QUIT is transmitted (click on the cross of the window) or the ESCAPE button is pressed , the application terminates its work.
But the window is empty, black, uninteresting. What would we do to draw something on it? First, give it a background . You can fill it with solid color or, strangely enough, just upload a picture of a suitable size and display it at the coordinates (0,0):
Copy Source | Copy HTML- import os
-
- def load_image(name):
- fullname = os.path.join('data', name) # Картинки у меня лежат в папке 'data'
- try:
- image = pygame.image.load(fullname)
- except pygame.error, message: # Мало ли :)
- print "Cannot load image:", name
- raise SystemExit, message
- image = image.convert() # Адаптируем картинку для отображения в игре. Если на ней есть альфа-канал - тогда convert_alpha()
- return image, image.get_rect()
-
- def draw_background():
- screen = pygame.display.get_surface() # Получаем поверхность, на которой будем рисовать
- background = pygame.Surface(screen.get_size()) # и ее размер
- background = background.convert()
- background.fill((0, 0, 0)) # заполняем цветом
- screen.blit(background, (0, 0)) # рисуем заполненный одним цветом бэкграунд
- back, back_rect = load_image("grass.jpg") # или загружаем картинку с травой
- screen.blit(back, (0, 0)) # и рисуем ее
- pygame.display.flip() # переключаем буфер экрана
- return back
-
- def main():
- init_window()
- bk = draw_background()
- action()
The most important lines here are screen = pygame.display.get_surface () , screen.blit (back, (0, 0)) and pygame.display.flip () . When working with Pygame, it is important to remember that drawing every time goes on some surface - surface . At the same time, such a thing as a backbuffer acts , that is, drawing goes in the screen buffer, and the flip () method, so to speak, “flips” the screen, displaying the changes that occurred in the buffer on the screen.
Well, now let's add some living creatures to our small world. To do this, create an animal, for example, an elephant :) Just for starters, we will slightly rewrite our image upload function. Now I will explain why.
Copy Source | Copy HTML- def load_image(name, colorkey=None):
- fullname = os.path.join('data', name)
- try:
- image = pygame.image.load(fullname)
- except pygame.error, message:
- print "Cannot load image:", name
- raise SystemExit, message
- image = image.convert()
- if colorkey is not None:
- if colorkey is -1:
- colorkey = image.get_at((0,0))
- image.set_colorkey(colorkey, RLEACCEL)
- return image, image.get_rect()
-
- class Animal(pygame.sprite.Sprite):
- def __init__(self, img, cX, cY):
- pygame.sprite.Sprite.__init__(self)
- self.image, self.rect = load_image(img, -1)
- screen = pygame.display.get_surface()
- self.area = screen.get_rect()
- self.cX = cX
- self.cY = cY
- self.coord = (cX, cY)
- print"Animal spawned at", self.coord
-
- class Elephant(Animal):
- def __init__(self, cX, cY):
- Animal.__init__(self, "Elephant.bmp", cX, cY)
I foresee the indignant exclamations of “why bmp ??”. I will answer - for experience :) Because now we have acquired another skill - taking the color from the image by coordinates ( colorkey = image.get_at ((0,0)) ), we can make this color in the whole picture completely transparent ( image.set_colorkey (colorkey, RLEACCEL) )! Useful if you suddenly need to upload a picture without an alpha channel.
pygame.sprite.Sprite is the standard pygame sprite class. For those who are not in the know: a sprite is a flat picture with a number of properties necessary for a game object. In particular, it can be made to move, taught all kinds of interactions, etc.
And now all we need to do is launch an elephant into our jungle!
Copy Source | Copy HTML- def action(bk):
- creatures_list = [] # Список со всем животными. Пригодится, если будем добавлять новых
- screen = pygame.display.get_surface()
- elephant = Elephant(10,10) # Помещаем слона по координатам х=10, у=10
- creatures_list.append(elephant)
- animals = pygame.sprite.RenderPlain(creatures_list) # Засовываем всех наших животных в класс RenderPlain для отображения спрайтов на экране
-
- while 1:
- input(pygame.event.get())
- screen.blit(bk, (0, 0))
- animals.update() # Стандартный метод проверки, вдруг что-то изменилось. Пригодится для описания движения
- animals.draw(screen)
- pygame.display.flip()
-
- def main():
- init_window()
- bk = draw_background()
- action(bk)
I agree that the above code needs optimization, in particular, do not kick the curve to draw the background, but in general, everything should be clear.
And finally, a working screenshot of my little development, just an introduction to Pygame. The green contours around the pictures are the flaws of bmp processing, now I redraw everything under png. The grid is the simplest example of drawing using Pygame, I’ll talk about this next time. Ready to answer any questions and listen to criticism.