Detect the overlapping between two game objects with Pygame

Pygame has a a few great interfaces that we can use to detect whether game character has overlapped each other or not and today we are going to look at one of them which is the pygame.sprite.collide_rect method. This method will take in two sprite objects that will then be used to find out the condition of the overlap. If no overlap happens then the above method will return False or else it will return True.

The script below is not perfect because it will only detect the overlapping once in the entire game and moves the enemy sprite in the opposite direction after the first overlapping occurs. This program is uses just to demonstrate to you how the above mentioned method works.

First thing we need to do before going into the main module is to modify the previous GameSprite module by making it a subclass of the pygame.sprite.Sprite class and then change it’s getImage method so we do not need to create a new GameSprite object on every loop pass just like before. Finally we will include a new detectCollide method which will return a boolean value indicates whether two sprite have overlapped each other or not.

import pygame
from pygame.locals import *

class GameSprite(pygame.sprite.Sprite):

    # Constructor. Pass in the image file
    # and it's width and height
    def __init__(self, image, width, height):
        # Call the parent class (Sprite) constructor
        pygame.sprite.Sprite.__init__(self)

        # Create the spritesheet surface from the image file
        self.sprite = pygame.image.load(image).convert_alpha()
        
        #register the width and height of the sprite
        self.width = width
        self.height = height
        
    def getImage(self, x_sprite, y_sprite, flip): # this method will return a subsurface which represents a portion of the spritesheet
    
        #the rectangle object uses in clipping
        self.clip_rect = Rect((x_sprite, y_sprite), (self.width, self.height))
        
        self.sprite.set_clip(self.clip_rect) # clip a portion of the spritesheet with the rectangle object
        sub_surface = self.sprite.subsurface(self.sprite.get_clip()) #create sub surface
        return pygame.transform.flip(sub_surface, flip, False) #return a new flip surface
    
    def detectCollide(self, right, player_draw_pos, enemy_draw_pos): #return a boolean value indicates whether the player has collided with enemy or not
        # create the rectangle object for both enemy and player that will be used in the collide_rect function
        self.rect = Rect(player_draw_pos.x, player_draw_pos.y, self.width, self.height)
        right.rect = Rect(enemy_draw_pos.x, enemy_draw_pos.y, right.width, right.height)
        return pygame.sprite.collide_rect(self, right)

The next thing we need to do is to include the detectCollide method in our main game loop to detect the overlapping of two objects.

#!/usr/bin/env python

import pygame
from pygame.locals import *
from sys import exit
from vector2d import Vector2D
from game_sprite import GameSprite

robot_sprite_sheet = 'left.png'

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32) #return a screen surface with desire screen size
pygame.display.set_caption("Pygame Demo")

w, h = 64, 64 # width and height of the sprite
sprite_counter = 0 # initialize the sprite_counter
game_frame = 0 # initialize the game_frame counter

#direction control for player
flip = False

#direction control for enemy
face_left = True

clock = pygame.time.Clock() # initialize the clock object
player_pos = Vector2D(30, 240) # initial position of the player sprite
enemy_pos = Vector2D(450, 240) # initial position of the enemy sprite
game_speed = 70. # speed per second

#create the player sprite 
game_sprite = GameSprite(robot_sprite_sheet, w, h)

#the enemy sprite object
game_sprite_two = GameSprite(robot_sprite_sheet, w, h)

while True:
   
    for event in pygame.event.get():
        
        if event.type == QUIT:
            exit()
            
    v = Vector2D(0., 0.) # reset the speed to zero on each pass
    
    pressed_keys = pygame.key.get_pressed() # get all the keys from key-press events 
        
    if pressed_keys[K_LEFT]: 
        flip = True # if the user pressed the left arrow key then makes the sprite object facing left
        v = Vector2D(-1., 0.) # move the object one unit to the left
        
    elif pressed_keys[K_RIGHT]:
        flip = False # if the user pressed the right arrow key then makes the sprite object facing right
        v = Vector2D(1., 0.) # move the object one unit to the right
            
    screen.fill((205, 200, 215))
    
    #blit the player with new position
    player_draw_pos = Vector2D(player_pos.x-w/2, player_pos.y-h/2)
    game_sprite_surface = game_sprite.getImage(sprite_counter * 64, 0, flip) # get the new sprite surface
    screen.blit(game_sprite_surface, player_draw_pos)
    
    #blit the enemy with new position
    enemy_draw_pos = Vector2D(enemy_pos.x-w/2, enemy_pos.y-h/2)
    game_sprite_surface_two = game_sprite_two.getImage(sprite_counter * 64, 0, face_left) # get the new sprite surface
    screen.blit(game_sprite_surface_two, enemy_draw_pos)
    
    #increase the sprite counter after x numbers of frame
    if(game_frame % 50 == 0):
        
        sprite_counter += 1
        
        if(sprite_counter > 5):
            sprite_counter = 0
            
    game_frame += 1
    
    time_passed = clock.tick() #delta time for each frame
    time_passed_seconds = time_passed / 1000.0
       
    #set the player's new position after each frame
    player_pos+= v * game_speed * time_passed_seconds   
    
    #if player collides with enemy, enemy flips and changes it's direction
    if(game_sprite.detectCollide(game_sprite_two, player_draw_pos, enemy_draw_pos)):
        face_left = False
    
    if(face_left == True):
        enemy_pos += Vector2D(-1., 0.) * game_speed * time_passed_seconds 
    else:
        enemy_pos += Vector2D(1., 0.) * game_speed * time_passed_seconds
    
    pygame.display.flip()

By running the above module you will see that after a contact has occurred the enemy sprite will move in the opposite direction.


pygame.sprite.collide_rect method