Lesson Notes
While Rect
objects represent a models size and position, a Surface
oibject contains the visual represenation.
You can create a surface object and fill the surface with a color:
surface_obj = pygame.Surface((height, width))
surface_obj.fill((r,g,b))
All surface objects have an intenral rectangle object. You can move the Surface object by altering the internal rectangle coordinates using the .getrect()
method of the Surface class:
surface_obj = pygame.Surface((height, width))
surface_obj.fill((r,g,b))
while True:
surface_obj.get_rect().x += 1
If you want an image instead of a solid color, use the image library to generate the surface object:
surface_obj = pygame.image.load(path_to_image)
A sprite is an Model in your GUI program that can interact with other objects in your program. The pygame Sprite
class adds extra functionality to your model to make it easier to update and interact with other objects.
To make your model a Sprite class, you need to add the following to your Model
import pygame
class Snowman(pygame.sprite.Sprite):
def __init__(self, x, y, img="assets/snowman.png"):
super().__init__()
self.image = pygame.image.load(img)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
Sprite classes must have the following instance variables:
self.image
self.rect
Groups are like lists specifically designed for Sprite objects
By adding your object to a Sprite Group, you are adding the ability to easily update, detect collisions, or delete an entire group of objects from your program.
You can have as many Sprite Groups as you want, and Sprites can belong to multiple groups.
Create empty Sprite groups :
class Controller:
def __init__(self):
#...
self.snowpeoples = pygame.sprite.Group()
self.max_snowmen = 20
#...
I can add
Sprites to Sprite Groups
number_of_starting_snowpeople = 2
interval = self.width/(number_of_starting_snowpeople+1)
xpos = interval
for _ in range(number_of_starting_snowpeople):
new_sm = Snowman(xpos, self.height/2)
self.snowpeoples.add(new_sm)
xpos += interval
When a user writes a function or method that is used by a library, it is called a Hook. Dunders are Pythons hooks.
Just like the Sprite
class assumes you have a self.rect
and self.image
, hooks allow the library to also assume you have certain methods implemented
The most useful pygame hook is the update()
method, which is used to automatically make state changes.
It can contain nothing:
def update():
print(“Nothing to update”)
But it can also update the model's coordinates:
def update():
self.rect.y += random.randint(-10, 10)
self.rect.x += random.randint(-10, 10)
Like all hooks, using the
update()
method is optional
In your Controller
, you call the update
method on the Sprite group, and it calls the update method for every sprite in the group:
self.snowpeoples.update() # calls the update() method for every snowman in the group
Reminder: Updates should happen after events have been handled
One of the most common operations for a GUI program is collisions. We've already seen how collisons work with the pygame.Rect
object.
Suppose we want to add an event when the user clicks on a snowman, it gets deleted:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
for s in self.snowpeoples:
if s.rect.collidepoint(event.pos):
s.kill() #remove from all Groups and delete
Use collisons to easily update your models as well, not just for events. For example, we can use collisons to remove any offscreen sprites by calculating the inverse of the collision:
for s in self.snowpeoples:
if not s.rect.collide_rect(self.background.get_rect()):
s.kill()
#quit if no snowpeople left
if len(self.snowpeoples) == 0:
pygame.quit()
exit()
If we inherit our Models from the Sprite
class and use Groups
, detecting collisions among sprites becomes even easier. The spritecollide()
function lets you determine if a single sprite collides with any sprite in a group. Suppose we want our snowmen to multiply any time they collide with another snowman. If we detetct a collision between one or more sprites, we can add another Snowman
object to the group:
for s in self.snowpeoples:
result = pygame.sprite.spritecollide(s, self.snowpeoples, False)
if len(result) > 1 and len(self.snowpeoples) <= self.max_snowmen:
self.snowpeoples.add(Snowman(s.rect.x, s.rect.y))
pygame.sprite.spritecollide(sprite, group, dokill)
True
any objects from the group
that collide with the sprite
will automatically be returned in a list then automatically deleted from memoryAlways redraw the screen after you have handled events, updated all model data, and handled collisions.
Sprite groups also allow us to draw all the sprites in the group on screen at once, rather than blitting each individual sprite. Redraw the screen using the draw()
method of the Group class:
self.background.fill(self.background_color)
self.screen.blit(self.background, (0, 0))
self.snowpeoples.draw(self.screen)
pygame.display.flip()