Use clipping rect size. Determine which is smaller. Width or Height. If even then you can says it hit both angles.
Then you can compare rect.centerx or rect.centery to collision rect.centerx or rect.centery.
I like displacement the best. It the easiest to start with.
Example.
import os
import pygame
import random
from pygame.sprite import Sprite, Group, spritecollide
class Block(Sprite):
def __init__(self, image, position, group):
Sprite.__init__(self)
# Reference the image. Doesn't make new one
self.image = image
# Collision group reference
self.group = group
self.rect = image.get_rect()
self.rect.topleft = position
# Hold the floats position. Since rect only does int
self.position = pygame.Vector2(position)
self.direction = pygame.Vector2(
(random.randint(0, 600) - 300) / 100 / Game.fps,
(random.randint(0, 600) - 300) / 100 / Game.fps)
def update(self):
self.position += self.direction * Game.delta
self.rect.topleft = self.position
self.collision()
def collision(self):
self.wall_bounce()
blocks = spritecollide(self, self.group, False)
for block in blocks:
if block != self:
# Simple displacement
w, h = self.rect.clip(block.rect).size
if w < h:
if self.rect.centerx > block.rect.centerx:
self.rect.left = block.rect.right
self.position.x = self.rect.x
self.direction.x = abs(self.direction.x)
block.direction.x = -abs(block.direction.x)
else:
self.rect.right = block.rect.left
self.position.x = self.rect.x
self.direction.x = -abs(self.direction.x)
block.direction.x = abs(block.direction.x)
else:
if self.rect.centery > block.rect.centery:
self.rect.top = block.rect.bottom
self.position.y = self.rect.y
self.direction.y = abs(self.direction.y)
block.direction.y = -abs(block.direction.y)
else:
self.rect.bottom = block.rect.top
self.position.y = self.rect.y
self.direction.y = -abs(self.direction.y)
block.direction.y = abs(block.direction.y)
def wall_bounce(self):
clamp = self.rect.clamp(Game.rect)
if clamp.x != self.rect.x:
self.rect.x = clamp.x
self.position.x = clamp.x
self.direction.x = -self.direction.x
if clamp.y != self.rect.y:
self.rect.y = clamp.y
self.position.y = clamp.y
self.direction.y = -self.direction.y
class Scene:
def __init__(self):
self.sprites = Group()
self.create_block_images()
self.add_blocks(15)
def add_blocks(self, number):
for n in range(number):
image = random.choice(self.block_images)
position = (random.randint(30, Game.rect.width - 30),
random.randint(30, Game.rect.height - 30))
block = Block(image, position, self.sprites)
block.add(self.sprites)
def create_block_images(self):
self.block_images = []
for x in range(20):
color = pygame.Color('black')
while color.r < 100 and color.g < 100 and color.b < 100:
color.r = random.randint(0, 255)
color.g = random.randint(0, 255)
color.b = random.randint(0, 255)
low, high = 20, 30
size = random.randint(low, high), random.randint(low, high)
surface = pygame.Surface(size)
surface.fill(color)
self.block_images.append(surface)
def draw(self, surface):
self.sprites.draw(surface)
self.sprites.update()
# Namespace for pygame game loop
class Game:
@classmethod
def setup(cls, title, width, height):
# Basic pygame setup
pygame.display.set_caption(title)
cls.surface = pygame.display.set_mode((width, height))
cls.rect = cls.surface.get_rect()
cls.clock = pygame.time.Clock()
cls.delta = 0
cls.fps = 30
cls.scene = Scene()
@classmethod
def mainloop(cls):
cls.running = True
while cls.running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
cls.running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
cls.running = False
cls.surface.fill(pygame.Color('black'))
cls.scene.draw(cls.surface)
pygame.display.flip()
cls.delta = cls.clock.tick(cls.fps)
if __name__ == '__main__':
pygame.init()
os.environ['SDL_VIDEO_CENTERED'] = '1'
Game.setup('Block Bouncing', 800, 600)
Game.mainloop()
pygame.quit()
99 percent of computer problems exists between chair and keyboard.