Part 12: Objects as pygame Sprites

12_sprite_collision

pygame has something called sprites, actors in the game. It is to facilitate easy drawing, creation, and destruction of the actors.

The actors are objects(instances of the class) technically. And the classes inherit (inherit all features from the parent and have some more of their own) from

pygame.sprite.Sprite

Now, to build upon the game, let us use the image of a rocket (stored in the same directory the ‘.py’ code is stored. This rocket is the actor which will move around the SCREEN on pressing WASD keys or arrow keys.

Code.

#The rocket - the actor/sprite that moves with arrows/WASD
class Rocket(pygame.sprite.Sprite):
    def __init__(self, image, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(image)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        #Horizontal
        #self.vertical = 1

Building up on Part 11, this class is a little different. It inherits from

pygame.sprite.Sprite

like this –

class Rocket(pygame.sprite.Sprite):

. And in the “Rocket” constructor (__init__), we need to call the parent class’s constructor like this.

pygame.sprite.Sprite.__init__(self)

The attributes (the things that each object has like a cookie has a ‘shape’, ‘color’) of the ‘Rocket’ sprite are, the

  • Image that the sprite takes the form of
  • The position of the rocket on the screen
  • The rocket’s direction

The rocket, if pointing towards the right, ideally should move only towards the right. This can be done using an extra variable and the value of the variable can be the direction. The current direction will be stored in the ‘rocket’ object and the logic for movement can be modified based on this value.
Challenge: I leave the implementation up to you.

Note:We inherit an actor, here ‘Rocket’ from Sprite, usually only when we need multiple rockets on the SCREEN. Though we have only one, we still use it, assuming you would like to extend it to more.
Further information at

We need three instance methods (behaviours required for each object of the class – akin to “crushCookies” to crush them and make a shake/cake, “cutHalf” to cut them into halves.
These are actions that we need on the rocket object, on each of the rockets on the SCREEN, if we have many.

They are-

  • Draw the rocket on the SCREEN and update the pygame display. We draw it three times,
    • Once before the while loop
    • Once in the while loop for movement of the rocket using WASD/arrow keys and
    • Once when the image is rotated on mouse clicks. Since an image is loaded and cannot change its color, we shall learn how to rotate it.
  • Rotate the image – called when the mouse is clicked
  • Update the position of the image on the SCREEN, post it moves.  Here we are giving a new definition to the “update” method already in the pygame.sprite.Sprite parent class. This is called overriding in OOP (object oriented programming) terminology.

Below is the code for all the three methods:

Draw and update screen

def draw_updatescreen(self):
        SCREEN.fill(BLACK)
        blitrocketrect = SCREEN.blit(self.image, (self.rect.x, self.rect.y))
        pygame.display.update()

First clear the screen by filling it BLACK, there is an efficient way of doing it. You need to get the rectangle where the rocket is drawn and just fill that rectangle BLACK.
Challenge: For doing it, we will have to write additional code for storing, the previous position of th rectangle (if it has moved through arrow/WASD keys) and redraw just that rectangle BLACK. I leave this to you to try.
Challenge 2:Once we know to erase the previous position of the sprite, the display update can be updated specifically by using

pygame.display.update(blitrocketrect)

instead of updating the entire screen with empty parameters.

Secondly, use

SCREEN.blit(self.image, (self.rect.x, self.rect.y))

to copy the image onto the pygame SCREEN.
Lastly, update the display using

pygame.display.update()

Rotate
Rotate using

self.image = pygame.transform.rotate(self.image, angle)

. The rotate function takes the “self.image” assigned using pygame.load.image in the constructor(__init__) and the rotation angle.

Update

rocket.rect.x =  x
        rocket.rect.y =  y

The x,y coordinates we get after using the WASD/arrow keys, are passed on to “update” and assigned to the “rocket” object.

The entire code for the class:

#The rocket - the actor/sprite that moves with arrows/WASD
class Rocket(pygame.sprite.Sprite):
    def __init__(self, image, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(image)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        #Horizontal
        #self.vertical = 1
    def draw_updatescreen(self):
        SCREEN.fill(BLACK)
        blitrocketrect = SCREEN.blit(self.image, (self.rect.x, self.rect.y))
        pygame.display.update()
    def rotate(self, angle):
        self.image = pygame.transform.rotate(self.image, angle)
    def update(self, x, y):
        rocket.rect.x =  x
        rocket.rect.y =  y

Create rocket object and draw the sprite for the first time at a pre-determined location say (40,40).

X = 40
Y = 40
SPRITENAME = 'rocket.png'
rocket = Rocket(SPRITENAME, X, Y)
rocket.draw_updatescreen()

Rotate on mouse click and update screen

ANGLE = 90
if (events.type == pygame.MOUSEBUTTONDOWN):
        rocket.rotate(ANGLE)
        rocket.draw_updatescreen()

After identifying key presses and calculating the X,Y coordinates, call “update” and “draw_updatescreen()”. The below code, as you know is one space from the “while” loop.

user_input = pygame.key.get_pressed()
if(user_input[pygame.K_UP]):
        Y=Y-1
        if(YSCREENHEIGHT):Y=0
    elif(user_input[pygame.K_LEFT]):
        X=X-1
        if(XSCREENWIDTH):X=0

    rocket.update(X,Y)
    rocket.draw_updatescreen()

The whole code till now:

#Import statements are to enable the code to use the functions from the library
import pygame
import sys
import os
import random


#instructions to windows to center the game window in the center of
#the screen, which it might ignore
os.environ["SDL_VIDEO_CENTERED"] = "1"

#initialize pygame
pygame.init()

#Right way
SCREENWIDTH = 500
SCREENHEIGHT = 500
SCREENSIZE = [SCREENWIDTH, SCREENHEIGHT]
SCREEN = pygame.display.set_mode(SCREENSIZE)

#caption for the game
pygame.display.set_caption("My first game in pygame")

ANGLE = 90
BLACK = (0,0,0)

#The rocket - the actor/sprite that moves with arrows/WASD
class Rocket(pygame.sprite.Sprite):
    def __init__(self, image, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(image)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        #Horizontal
        #self.vertical = 1
    def draw_updatescreen(self):
        SCREEN.fill(BLACK)
        blitrocketrect = SCREEN.blit(self.image, (self.rect.x, self.rect.y))
        pygame.display.update()
    def rotate(self, angle):
        self.image = pygame.transform.rotate(self.image, angle)
    def update(self, x, y):
        rocket.rect.x =  x
        rocket.rect.y =  y
        
#This group has only one sprite
X = 40
Y = 40
SPRITENAME = 'rocket.png'
rocket = Rocket(SPRITENAME, X, Y)
rocket.draw_updatescreen()

while True:
    for events in pygame.event.get():
        if events.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if (events.type == pygame.MOUSEBUTTONDOWN):
            rocket.rotate(ANGLE)
            rocket.draw_updatescreen()
            
    #Inside while, a single tab space from while
    user_input = pygame.key.get_pressed()
    if(user_input[pygame.K_UP]):
        Y=Y-1
        if(YSCREENHEIGHT):Y=0
    elif(user_input[pygame.K_LEFT]):
        X=X-1
        if(XSCREENWIDTH):X=0

    rocket.update(X,Y)
    rocket.draw_updatescreen()    

 

The next challenge would be to create “Walls” as sprites and create many of them and when the rocket collides with the walls, the walls disappear.
Excited? Let’s go ahead? Don’t give up now.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s