Program O takes you to recall the classic: developing a brick playing game with native Python~

Posted by alemapo on Wed, 15 Dec 2021 09:30:32 +0100

Introduction

well! I just gave it to you not long ago ✍ Had a bouncing ball game!

Do you remember? I don't remember looking at the content of the previous issue. I upgraded this small tour with large transfer on the basis of the previous issue

Play, the interface is also very simple, classic color, original, hahaha.

hello everyone 👌, I am mumuzi, a female code farmer in the hall under the programming! Today, I will take you to write a classic brick playing game!

🌞 Popular science:

Brick making was originally an independent game developed by yadali company. It is also the childhood memory of countless people.

Search for "atari breakout" in Google pictures, and the search results will become this game. Put all bricks

After all blocks are cleared, you can continue to enter the next round of challenges.

You can also try hahaha ~ I hope to introduce more programming knowledge to you!

text

1, In preparation

1) Rules of the game:

After removing all the bricks, you can continue to the next challenge

Initialize 2 chances for each player and win after hitting all the bricks, otherwise the game will fail!

(there are few level materials and background music, and the required homepage source code base is not displayed. See HA)

2) Environment installation

The environment used in this article: Python 3, pychar, Pygame module and some built-in modules.

Environmental installation: pip install -i https://pypi.douban.com/simple / + module name

2, Start typing code

1) Configuration file

import os

'''Some values in the game interface'''
SCREENWIDTH = 640
SCREENHEIGHT = 480
BRICKWIDTH = 10
BRICKHEIGHT = 10
PADDLEWIDTH = 60
PADDLEHEIGHT = 12
BALLRADIUS = 8
'''Game material path'''
FONTPATH = os.path.join(os.getcwd(), 'resources/font/font.TTF')
HITSOUNDPATH = os.path.join(os.getcwd(), 'resources/audios/hit.wav')
BGMPATH = os.path.join(os.getcwd(), 'resources/audios/bgm.mp3')
LEVELROOTPATH = os.path.join(os.getcwd(), 'resources/levels')
LEVELPATHS = [os.path.join(LEVELROOTPATH, '%s.level' % str(i+1)) for i in range(len(os.listdir(LEVELROOTPATH)))]
'''Some colors'''
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
PINK = (212, 149, 174) 
PURPLE = (168, 152, 191)
YELLOW = (245, 237, 162)
BLUE  = (51, 170, 230)
AQUA = (182, 225, 225)

2)Define some classes

import random
import pygame


'''board'''
class Paddle(pygame.sprite.Sprite):
    def __init__(self, x, y, width, height, SCREENWIDTH, SCREENHEIGHT, **kwargs):
        pygame.sprite.Sprite.__init__(self)
        self.init_state = [x, y, width, height]
        self.rect = pygame.Rect(x, y, width, height)
        self.base_speed = 10
        self.SCREENWIDTH = SCREENWIDTH
        self.SCREENHEIGHT = SCREENHEIGHT
    '''Moving board'''
    def move(self, direction):
        if direction == 'left':
            self.rect.left = max(0, self.rect.left-self.base_speed)
        elif direction == 'right':
            self.rect.right = min(self.SCREENWIDTH, self.rect.right+self.base_speed)
        else:
            raise ValueError('Paddle.move.direction unsupport %s...' % direction)
        return True
    '''Bind to screen'''
    def draw(self, screen, color):
        pygame.draw.rect(screen, color, self.rect)
        return True
    '''Reset'''
    def reset(self):
        self.rect = pygame.Rect(self.init_state[0], self.init_state[1], self.init_state[2], self.init_state[3])
        return True


'''ball'''
class Ball(pygame.sprite.Sprite):
    def __init__(self, x, y, radius, SCREENWIDTH, SCREENHEIGHT, **kwargs):
        pygame.sprite.Sprite.__init__(self)
        self.init_state = [x, y, radius*2, radius*2]
        self.rect = pygame.Rect(x, y, radius*2, radius*2)
        self.base_speed = [5, 5]
        self.direction = [random.choice([1, -1]), -1]
        self.radius = radius
        self.SCREENWIDTH = SCREENWIDTH
        self.SCREENHEIGHT = SCREENHEIGHT
    '''Moving ball'''
    def move(self):
        self.rect.left += self.direction[0] * self.base_speed[0]
        self.rect.top += self.direction[1] * self.base_speed[1]
        if self.rect.left <= 0:
            self.rect.left = 0
            self.direction[0] = -self.direction[0]
        elif self.rect.right >= self.SCREENWIDTH:
            self.rect.right = self.SCREENWIDTH
            self.direction[0] = -self.direction[0]
        if self.rect.top <= 0:
            self.rect.top = 0
            self.direction[1] = -self.direction[1]
        elif self.rect.bottom >= self.SCREENHEIGHT:
            return False
        return True
    '''Change the speed and direction of movement(When it collides with the racket)'''
    def change(self):
        self.base_speed = [random.choice([4, 5, 6]), random.choice([4, 5, 6])]
        self.direction = [random.choice([1, -1]), -1]
        return True
    '''Bind to screen'''
    def draw(self, screen, color):
        pygame.draw.circle(screen, color, (self.rect.left+self.radius, self.rect.top+self.radius), self.radius)
        return True
    '''Reset'''
    def reset(self):
        self.rect = pygame.Rect(self.init_state[0], self.init_state[1], self.init_state[2], self.init_state[3])
        return True


'''brick'''
class Brick(pygame.sprite.Sprite):
    def __init__(self, x, y, width, height, **kwargs):
        pygame.sprite.Sprite.__init__(self)
        self.init_state = [x, y, width, height]
        self.rect = pygame.Rect(x, y, width, height)
    '''Bind to screen'''
    def draw(self, screen, color):
        pygame.draw.rect(screen, color, self.rect)
        return True
    '''Reset'''
    def reset(self):
        self.rect = pygame.Rect(self.init_state[0], self.init_state[1], self.init_state[2], self.init_state[3])
        return True

3) Define start and end interfaces

 '''Start interface'''
    def __startInterface(self):
        clock = pygame.time.Clock()
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
                    pygame.quit()
                    sys.exit(-1)
                if event.type == pygame.KEYDOWN and event.key == pygame.K_RETURN:
                    return
            self.screen.fill(self.cfg.AQUA)
            text1 = 'Press <Enter> to start the game'
            text2 = 'Press <Esc> to quit the game'
            text_render1 = self.font_big.render(text1, False, self.cfg.BLUE)
            text_render2 = self.font_big.render(text2, False, self.cfg.BLUE)
            self.screen.blit(text_render1, ((self.cfg.SCREENWIDTH-text_render1.get_rect().width)//2, (self.cfg.SCREENHEIGHT-text_render1.get_rect().height)//4))
            self.screen.blit(text_render2, ((self.cfg.SCREENWIDTH-text_render2.get_rect().width)//2, (self.cfg.SCREENHEIGHT-text_render2.get_rect().height)//2))
            pygame.display.flip()
            clock.tick(30)
    '''End interface'''
    def __endInterface(self, is_win):
        if is_win:
            text1 = 'Congratulations! You win!'
        else:
            text1 = 'Game Over! You fail!'
        text2 = 'Press <R> to restart the game'
        text3 = 'Press <Esc> to quit the game.'
        clock = pygame.time.Clock()
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
                    pygame.quit()
                    sys.exit(-1)
                if event.type == pygame.KEYDOWN and event.key == pygame.K_r:
                    return
            self.screen.fill(self.cfg.AQUA)
            text_render1 = self.font_big.render(text1, False, self.cfg.BLUE)
            text_render2 = self.font_big.render(text2, False, self.cfg.BLUE)
            text_render3 = self.font_big.render(text3, False, self.cfg.BLUE)
            self.screen.blit(text_render1, ((self.cfg.SCREENWIDTH-text_render1.get_rect().width)//2, (self.cfg.SCREENHEIGHT-text_render1.get_rect().height)//4))
            self.screen.blit(text_render2, ((self.cfg.SCREENWIDTH-text_render2.get_rect().width)//2, (self.cfg.SCREENHEIGHT-text_render2.get_rect().height)//2))
            self.screen.blit(text_render3, ((self.cfg.SCREENWIDTH-text_render3.get_rect().width)//2, (self.cfg.SCREENHEIGHT-text_render2.get_rect().height)//1.5))
            pygame.display.flip()
            clock.tick(30)

4)Define game

'''Brick game'''
class breakoutClone():
    def __init__(self, cfg, **kwargs):
        pygame.init()
        pygame.display.set_caption('Breakout clone ')
        pygame.mixer.init()
        self.screen = pygame.display.set_mode((cfg.SCREENWIDTH, cfg.SCREENHEIGHT))
        self.font_small = pygame.font.Font(cfg.FONTPATH, 20)
        self.font_big = pygame.font.Font(cfg.FONTPATH, 30)
        self.hit_sound = pygame.mixer.Sound(cfg.HITSOUNDPATH)
        pygame.mixer.music.load(cfg.BGMPATH)
        pygame.mixer.music.play(-1, 0.0)
        self.cfg = cfg
    '''Run the game'''
    def run(self):
        while True:
            self.__startInterface()
            for idx, levelpath in enumerate(self.cfg.LEVELPATHS):
                state = self.__runLevel(levelpath)
                if idx == len(self.cfg.LEVELPATHS)-1:
                    break
                if state == 'win':
                    self.__nextLevel()
                else:
                    break
            if state == 'fail':
                self.__endInterface(False)
            else:
                self.__endInterface(True)
    '''Run a level'''
    def __runLevel(self, levelpath):
        score = 0
        num_lives = 2
        # running: the game is in progress, fail: the game fails, win: the game succeeds
        state = 'running'
        paddle = Paddle((self.cfg.SCREENWIDTH-self.cfg.PADDLEWIDTH)/2, self.cfg.SCREENHEIGHT-self.cfg.PADDLEHEIGHT-10, self.cfg.PADDLEWIDTH, self.cfg.PADDLEHEIGHT, self.cfg.SCREENWIDTH, self.cfg.SCREENHEIGHT)
        ball = Ball(paddle.rect.centerx-self.cfg.BALLRADIUS, paddle.rect.top-self.cfg.BALLRADIUS*2, self.cfg.BALLRADIUS, self.cfg.SCREENWIDTH, self.cfg.SCREENHEIGHT)
        brick_sprites = pygame.sprite.Group()
        brick_positions = loadLevel(levelpath)
        for bp in brick_positions:
            brick_sprites.add(Brick(bp[0]*self.cfg.BRICKWIDTH, bp[1]*self.cfg.BRICKHEIGHT, self.cfg.BRICKWIDTH, self.cfg.BRICKHEIGHT))
        clock = pygame.time.Clock()
        while True:
            if state != 'running':
                return state
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit(-1)
            keys_pressed = pygame.key.get_pressed()
            if keys_pressed[pygame.K_LEFT]:
                paddle.move('left')
            elif keys_pressed[pygame.K_RIGHT]:
                paddle.move('right')
            self.screen.fill(self.cfg.AQUA)
            is_alive = ball.move()
            # Judge if you catch the ball
            if not is_alive:
                ball.reset()
                paddle.reset()
                num_lives -= 1
                if num_lives == 0:
                    state = 'fail'
            # Ball and brick collision detection
            num_bricks = pygame.sprite.spritecollide(ball, brick_sprites, True)
            score += len(num_bricks)
            # Ball and racket collision detection
            if pygame.sprite.collide_rect(ball, paddle):
                ball.change()
            # Judge whether the brick has been finished
            if len(brick_sprites) == 0:
                state = 'win'
            # Bind game sprites to the screen
            paddle.draw(self.screen, self.cfg.PURPLE)
            ball.draw(self.screen, self.cfg.WHITE)
            for brick in brick_sprites:
                brick.draw(self.screen, self.cfg.YELLOW)
            text_render = self.font_small.render('SCORE: %s, LIVES: %s' % (score, num_lives), False, self.cfg.BLUE)
            self.screen.blit(text_render, (10, 10))
            pygame.display.flip()
            clock.tick(50)
    '''Level switching'''
    def __nextLevel(self):
        clock = pygame.time.Clock()
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit(-1)
                if event.type == pygame.KEYDOWN and event.key == pygame.K_RETURN:
                    return
            self.screen.fill(self.cfg.AQUA)
            text = 'Press <Enter> to enter the next level'
            text_render = self.font_big.render(text, False, self.cfg.BLUE)
            self.screen.blit(text_render, ((self.cfg.SCREENWIDTH-text_render.get_rect().width)//2, (self.cfg.SCREENHEIGHT-text_render.get_rect().height)//3))
            pygame.display.flip()
            clock.tick(30)

5) Main function and operation interface

import cfg
from modules import breakoutClone


'''Main function'''
def main():
    game = breakoutClone(cfg)
    game.run()


'''run'''
if __name__ == '__main__':
    main()

3, Effect display

1) Video effect display——

program ⚪ Take you to recall the classic: a brick playing game developed by native Python~

2) Screenshot effect display——

Game start interface——

Operation interface——

summary

to 🐟 The vast sea of people meet - thank you for reading! Meeting is fate. If it helps you, remember to connect three times~

I am mumuzi, a female code farmer who can not only program, but also teach you to play games, make Festival surprises, and even tease your little sister and brother's confession applet

Write at the end - there are many wonderful contents in the past, welcome to read! Follow me and update daily 💖💖

🎯 Complete free source code collection office: remember me!

Didi, I can!

Previous game recommendations——

Item 1.0: Kaixin Xiaole 🐥

[Pygame practice] happiness -- xiaoxiaole, you, me and everyone~

Item 1.3: Adventure Games 🪂
[Pygame practice] The Adventures of meow: the programmer's Guide to cat smoking: it's really great~

Item 4.6 bubble Dragon

Pygame actual combat: the classic bubble dragon game popular all over the world is coming. Will you like it? (source code attached)

Item 4.7: Game Collection

 [Pygame classic collection] the ultimate free trick: let you have fun (with a variety of game source codes)

🍓 Article summary——

Item 1.0 Python-2021 | summary of existing articles | continuously updated. It's enough to read this article directly

(more content + source code are summarized in the article!! welcome to read ~)

Topics: Python Game Development pygame