Thursday, 10 December 2015

Pygame : Shoot moving ball

In this post I am going to explain simple game, where a ball keep on bouncing and user has to hit the ball using an arrow. Game is finished when user hits the ball.

Requirements
1.   We need to design a ball
2.   We need to design a player
3.   We need to design arrows
4.   Once arrow hits the ball, game is over.
5.   We need to prompt user, whether he wants to continue (or) quit the game.
6.   We need to display total arrows consumed by user.
7.   We need to display total time taken by user

I am going to define three classes Ball, Player, Bullet.


Class
Description
Ball
Ball is used to draw a moving ball. Class provide methods to update the color, speed and reset the position of the ball.
Player
Player is used to hit the ball. Provide method to change the position of player relevant mouse moves.
Bullet
Bullet represent the arrow

# import pygame
import pygame
import random
import time

# initialize game engine
pygame.init()

# Window dimensions
window_width=500
window_height=500

clock_tick_rate=20

# Open a window
size = (window_width, window_height)
screen = pygame.display.set_mode(size)

# Set title to the window
pygame.display.set_caption("Shoot me")

dead=False

# Initialize values for color (RGB format)
WHITE=(255,255,255)
RED=(255,0,0)
GREEN=(0,255,0)
BLUE=(0,0,255)
BLACK=(0,0,0)

clock = pygame.time.Clock()

# Design a ball
class Ball(pygame.sprite.Sprite):
    def __init__(self, width, color, bounceLimit):
        super().__init__()
        self.color=color
        self.width=width
        self.colorCounter=0

        self.image = pygame.Surface([width, width])
        self.image.fill(WHITE)
        self.rect = self.image.get_rect()
        pygame.draw.ellipse(self.image, color, [0, 0, width, width])

    def updateColor(self, color):
        self.color=color
        pygame.draw.ellipse(self.image, color, [0, 0, self.width, self.width])

    def updatePosition(self, speed):
        if(self.rect.x>=window_width):
            self.rect.x=0

        self.rect.x+=speed

    def reset(self):
        self.rect.x=0
        self.rect.y=0

# Player class
class Player(Ball):
    def __init__(self, width, height, color):
        super().__init__(width, height, color)
        self.rect.y = window_height-10

    def updatePosition(self):
        pos = pygame.mouse.get_pos()
        self.rect.x = pos[0]

# Class represent Bullets
class Bullet(pygame.sprite.Sprite):
    def __init__(self, color):
        super().__init__()

        self.image = pygame.Surface([20, 20])
        self.image.fill(WHITE)

        pygame.draw.line(self.image, RED, [5,0], [5, 15], 3)
        pygame.draw.line(self.image, RED, [5,0], [0, 5], 3)
        pygame.draw.line(self.image, RED, [5,0], [10, 5], 3)

        self.rect = self.image.get_rect()

# Class is used to start/restart the game
class Game():
    def __init__(self, ball):
        self.ball=ball

        self.playerSprite=Player(20, 20, RED)

        self.allSprites=pygame.sprite.Group()
        self.bullet_list=pygame.sprite.Group()
        self.block_list=pygame.sprite.Group()

        self.allSprites.add(ball)
        self.allSprites.add(self.playerSprite)

        self.block_list.add(ball)

    def start(self):
        self.playerSprite=Player(20, 20, RED)

        self.allSprites=pygame.sprite.Group()
        self.bullet_list=pygame.sprite.Group()
        self.block_list=pygame.sprite.Group()

        self.allSprites.add(self.ball)
        self.allSprites.add(self.playerSprite)

        self.block_list.add(self.ball)
        self.ball.reset()

gameBall=Ball(20, RED, 100)
myGame =  Game(gameBall)

font = pygame.font.SysFont('Calibri', 25, True, True)
text = font.render("Game is Over, Click any where to restart the game",True,BLACK)
flag=False

startTime=time.time()
endTime=time.time()
if __name__=="__main__":
    bulletCount=0

    while(dead==False):
        # Logic to restart the game
        if flag==True:
            timeTaken=font.render("Time taken is " + str(endTime-startTime) + " seconds", True, BLACK)
            bulletsUsed=font.render("Total bullets used" + str(bulletCount), True, BLACK)

            screen.blit(text, [0, 200])
            screen.blit(timeTaken, [50, 230])
            screen.blit(bulletsUsed, [100, 260])

            pygame.display.flip()
            clock.tick(clock_tick_rate)

            for event in pygame.event.get():
                if event.type == pygame.MOUSEBUTTONDOWN:
                    flag=False
                    bulletCount=0
                    myGame.start()
                    startTime=time.time()
                    break
                if event.type == pygame.QUIT:
                    dead = True
            continue;

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                dead = True
            elif event.type == pygame.MOUSEBUTTONDOWN:
                # Whenever mouse button down, release the arrow
                bullet = Bullet(BLACK)
                bullet.rect.x = myGame.playerSprite.rect.x
                bullet.rect.y = myGame.playerSprite.rect.y
                myGame.allSprites.add(bullet)
                myGame.bullet_list.add(bullet)
                bulletCount+=1

        myGame.playerSprite.updatePosition()

        for tempBullet in myGame.bullet_list:
            tempBullet.rect.y-=10

            blocks_hit_list = pygame.sprite.spritecollide(tempBullet, myGame.block_list, True)

            if(tempBullet.rect.y<=0):
                myGame.bullet_list.remove(tempBullet)
                myGame.allSprites.remove(tempBullet)

            if(len(blocks_hit_list) > 0):
                myGame.allSprites.remove(gameBall)
                flag=True
                endTime=time.time()
                myGame.allSprites=pygame.sprite.Group()

        screen.fill(WHITE)
        myGame.ball.updatePosition(2)
        myGame.ball.colorCounter+=1

        if(myGame.ball.colorCounter == 15):
            myGame.ball.updateColor([random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)])
            myGame.ball.colorCounter=0

        myGame.allSprites.draw(screen)
        pygame.display.flip()
        clock.tick(clock_tick_rate)3424809, 3820683, 3835512, 3829314, 3829302, 3447619, 3429419

Output

Once you hit the ball, you will get following kind of screen.




Previous                                                 Next                                                 Home

No comments:

Post a Comment