""" 
A demo with multiple sprites, groups, and collisions
"""
import random
import pygame
from pygame.locals import * 
pygame.mixer.pre_init(44100, -16, 2, 1024)
pygame.init()

class Ball(pygame.sprite.Sprite):
    my_font = pygame.font.SysFont("comicsansms", 16, bold=True)
    base_image = pygame.image.load("small_ball.png")
    
    def __init__(self):
        pygame.sprite.Sprite.__init__(self) #construct the parent component
        self.image = Ball.base_image.copy().convert_alpha()
        self.rect = self.image.get_rect() #loads the rect from the image

        #set the position, direction, and speed of the ball
        self.rect.left = random.randrange(0,background.get_width()-self.rect.width)
        self.rect.top = random.randrange(0,background.get_height()-self.rect.height)
        self.dir_x = random.choice([-1,1])
        self.dir_y = random.choice([-1,1])
        self.speed = random.randrange(2,5)

        self.points = 0
        self.update_label()
        
    def add_points(self, points):
        self.points += points
        self.update_label()

    def get_points(self):
        return self.points

    def update_label(self):
        self.image = Ball.base_image.copy().convert_alpha()
        self.label = Ball.my_font.render(str(self.points), True, (255,0,0))
        label_x = (self.rect.width-self.label.get_width())/2
        label_y = (self.rect.height-self.label.get_height())/2
        self.image.blit(self.label, (label_x, label_y))



    def update(self):
        #Handle the walls by changing direction(s)
        if self.rect.left < 0 or self.rect.right >= background.get_width():
            self.dir_x *= -1
        if self.rect.top < 0 or self.rect.bottom >= background.get_height():
            self.dir_y *= -1
        self.rect.move_ip(self.speed*self.dir_x, self.speed*self.dir_y)

        
class Block(pygame.sprite.Sprite):
    def __init__(self, colour):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((10,10)).convert()
        self.image.fill(colour)
        self.rect = self.image.get_rect()

        #set the position of the block
        self.rect.left = random.randrange(0,background.get_width()-self.rect.width)
        self.rect.top = random.randrange(0,background.get_height()-self.rect.height)


        
#Start of game
screen = pygame.display.set_mode((800, 600))

NUM_BALLS = 8
NUM_BLOCKS = 1000

background = pygame.Surface(screen.get_size()).convert()
background.fill((255, 255, 255))
screen.blit(background, (0,0))


#make a few balls
ball_group = pygame.sprite.Group()
for i in range(NUM_BALLS):
    ball = Ball()
    ball_group.add(ball)

#make some blocks    
block_group = pygame.sprite.Group()
for i in range(NUM_BLOCKS):
    block_colour = (random.randrange(0,255),random.randrange(0,255),random.randrange(0,255))
    block_group.add(Block(block_colour))
    
bounce = pygame.mixer.Sound("ball_bounce.ogg") #used for a sound effect

clock = pygame.time.Clock()
keep_going = True
while keep_going:
    clock.tick(30)
    for ev in pygame.event.get():
        if ev.type == QUIT:
            keep_going = False

            
    #check for collisions, killing the blocks hit
    for ball in ball_group.sprites():
        hits = pygame.sprite.spritecollide(ball, block_group, True)
        ball.add_points(len(hits))
    #We could have used pygame.sprite.groupcollide() and work with the dict.


    #If two balls collide, then they will 'combine'
    balls = ball_group.sprites()
    for ball in balls:
        hits = pygame.sprite.spritecollide(ball, ball_group, False)
        for hit in hits:
            if hit != ball:
                bounce.play()
                if hit.get_points() > ball.get_points():
                    hit.add_points(ball.get_points())
                    ball_group.remove(ball)
                else:
                    ball.add_points(hit.get_points())
                    ball_group.remove(hit)
                    balls.remove(hit)
    
    #handle when the blocks are all gone
    if len(block_group) == 0:
        keep_going = False
        
    ball_group.clear(screen, background)
    block_group.clear(screen, background)
    ball_group.update()
    block_group.draw(screen)
    ball_group.draw(screen)
    pygame.display.flip()
    