In which I Pursue Progress with Programming in Python

99er MagazineIn  1981 or so, my brother and I were 12 and 13 years old and we both had paper routes.  We pooled the fruits of our paper carrier jobs, and Dad took us down to the Alberta Treasury Branch where he co-signed a $1200 personal loan at a whopping 23% interest so that we could buy our first personal computer– a TI-99/4.  In fact it was the first personal computer anyone had in our neighbourhood.  We poured over the accompanying manuals, got all sorts of books from the library, and subscribed to 99er magazine.  These early computer enthusiast magazines offered articles about the future of computing, ads for enticing new peripherals and gadgets, and most importantly programs.  Each magazine contained printouts– recipes I guess, for dozens of programs.  We learned to program by painstakingly copying programs from printouts in these magazines, even more painstakingly debugging our errors then figuring out how to fix the inevitable mistakes in the magazine’s code.

30 year later, as I make the transition from SCRATCH, to PYTHON, I find myself transported back to the same learning process.  As I undertook to learn a new programming language, I found myself seeking out familiar “Teach yourself programming by copying these game’ books.  But this time I did not need to go to the magazine stand, or the library, or order in by mail.  The resources are all a google away.  I think it says something about my personal learning style that I chose the cookbook style of print resources over the many multimedia and video tutorials available on youtube.

I’ve spent most of the last week trying to understand some of the basic structure and commands of python, as I worked my way through a variety of tutorial programs.  First impression is compared to scratch there is alot more fiddly typing and figuring out exactly how to initialize then execute each step.  Unlike scratch, it is much harder in python to just poke around and see what will happen.  If you don`t know the precise order, structure, and syntax for any small part… the whole program may not even start.  I think here is a fundamental difference between Scratch and python.  Constructivist philosophy is at the core SCRATCH.  It is designed to be explored, tinkered with and discovered.  On the other hand, Python is designed to be functional, readable, and infinitely extensible.  Alex Martelli, author of the Python Cookbook, summed up the Python Philosophy:

To describe something as clever is not considered a compliment in the Python culture.” Python’s philosophy rejects the Perl “there is more than one way to do it” approach to language design in favor of “there should be one—and preferably only one—obvious way to do it”.  From:  Python Programming Language on Wikipedia.

Bricka by codeNtronix

Download the original Brika Source code from codeNtronix

and here is my revised source code for Bricka.

'''
 bricka (a breakout clone)
 Developed by Leonel Machava <leonelmachava@gmail.com>
 http://codeNtronix.com

with revisions by Sean McGaughey http://edalchemy.mcgaughey.ca
during Creative Computing Online Workshop

'''
import sys, pygame
from pygame.locals import *

SCREEN_SIZE   = 640,480

# Object dimensions
BRICK_WIDTH   = 60
BRICK_HEIGHT  = 15
PADDLE_WIDTH  = 60
PADDLE_HEIGHT = 12
BALL_DIAMETER = 16
BALL_RADIUS   = int(BALL_DIAMETER / 2)   #source code was just BALL_DIAMETER / 2 This through an error of floating point vs Int error
                                        # I added an int function to make sure it is an integer value

MAX_PADDLE_X = SCREEN_SIZE[0] - PADDLE_WIDTH
MAX_BALL_X   = SCREEN_SIZE[0] - BALL_DIAMETER
MAX_BALL_Y   = SCREEN_SIZE[1] - BALL_DIAMETER

# Paddle Y coordinate
PADDLE_Y = SCREEN_SIZE[1] - PADDLE_HEIGHT - 10

# Color constants
BLACK = (0,0,0)
WHITE = (255,255,255)
BLUE  = (0,0,255)
BRICK_COLOR = (200,200,0)

# State constants
STATE_BALL_IN_PADDLE = 0
STATE_PLAYING = 1
STATE_WON = 2
STATE_GAME_OVER = 3

mousex = 0 #x coordinate of mouse event
mousey = 0 # y coordinate of mouse event

class Bricka:

    def __init__(self):
        pygame.init()

        self.screen = pygame.display.set_mode(SCREEN_SIZE)
        pygame.display.set_caption('bricka (a breakout clone by codeNtronix.com)')

        self.clock = pygame.time.Clock()

        if pygame.font:
            self.font = pygame.font.Font('freesansbold.ttf',20)
        else:
            self.font = None

        self.init_game()

    def init_game(self):
        self.lives = 3
        self.score = 0
        self.state = STATE_BALL_IN_PADDLE

        self.paddle   = pygame.Rect(300,PADDLE_Y,PADDLE_WIDTH,PADDLE_HEIGHT)
        self.ball     = pygame.Rect(300,PADDLE_Y - BALL_DIAMETER,BALL_DIAMETER,BALL_DIAMETER)

        self.ball_vel = [5,-5]

        self.create_bricks()

    def create_bricks(self):
        y_ofs = 35
        self.bricks = []
        for i in range(7):
            x_ofs = 35
            for j in range(8):
                self.bricks.append(pygame.Rect(x_ofs,y_ofs,BRICK_WIDTH,BRICK_HEIGHT))
                x_ofs += BRICK_WIDTH + 10
            y_ofs += BRICK_HEIGHT + 5

    def draw_bricks(self):
        for brick in self.bricks:
            pygame.draw.rect(self.screen, BRICK_COLOR, brick)

    def check_input(self):
        for event in pygame.event.get(): # event handling loop
            if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
                pygame.quit()
                sys.exit()
            elif event.type == MOUSEMOTION: # I added these mouse controls.  It works well.
                mousex, mousey = event.pos
                if mousex >= MAX_PADDLE_X:
                    self.paddle.left = MAX_PADDLE_X
                else:
                    self.paddle.left = mousex

            elif event.type == MOUSEBUTTONUP:
                mousex, mousey = event.pos
                self.paddle.left = mousex
                mouseClicked = True
                if self.state == STATE_BALL_IN_PADDLE:
                    self.state = STATE_PLAYING

        keys = pygame.key.get_pressed()

        if keys[pygame.K_LEFT]:
            self.paddle.left -= 5
        if self.paddle.left < 0:             self.paddle.left = 0         if keys[pygame.K_RIGHT]:             self.paddle.left += 5         if self.paddle.left > MAX_PADDLE_X:
            self.paddle.left = MAX_PADDLE_X

        if keys[pygame.K_SPACE] and self.state == STATE_BALL_IN_PADDLE:
             self.state = STATE_PLAYING
        elif keys[pygame.K_RETURN] and (self.state == STATE_GAME_OVER or self.state == STATE_WON):

            self.init_game()

    def move_ball(self):
        self.ball.left += self.ball_vel[0]
        self.ball.top  += self.ball_vel[1]

        if self.ball.left <= 0:             self.ball.left = 0             self.ball_vel[0] = -self.ball_vel[0]         elif self.ball.left >= MAX_BALL_X:
            self.ball.left = MAX_BALL_X
            self.ball_vel[0] = -self.ball_vel[0]

        if self.ball.top < 0:             self.ball.top = 0             self.ball_vel[1] = -self.ball_vel[1]         elif self.ball.top >= MAX_BALL_Y:
            self.ball.top = MAX_BALL_Y
            self.ball_vel[1] = -self.ball_vel[1]

    def handle_collisions(self):
        for brick in self.bricks:
            if self.ball.colliderect(brick):
                self.score += 3
                self.ball_vel[1] = -self.ball_vel[1]
                self.bricks.remove(brick)
                break

        if len(self.bricks) == 0:
            self.state = STATE_WON

        if self.ball.colliderect(self.paddle):
            self.ball.top = PADDLE_Y - BALL_DIAMETER
            self.ball_vel[1] = -self.ball_vel[1]
        elif self.ball.top > self.paddle.top:
            self.lives -= 1
            if self.lives > 0:
                self.state = STATE_BALL_IN_PADDLE
            else:
                self.state = STATE_GAME_OVER

    def show_stats(self):
        if self.font:
            font_surface = self.font.render('SCORE: ' + str(self.score) + ' LIVES: ' + str(self.lives), False, WHITE)
            self.screen.blit(font_surface, (205,5))

    def show_message(self,message):
        if self.font:
            size = self.font.size(message)
            font_surface = self.font.render(message,False, WHITE)
            x = (SCREEN_SIZE[0] - size[0]) / 2
            y = (SCREEN_SIZE[1] - size[1]) / 2
            self.screen.blit(font_surface, (x,y))

    def run(self):
        while 1:
            for event in pygame.event.get():     # I added these lines from Sweigart, making Games with Python
                if event.type == pygame.QUIT:
                    sys.exit                    # To check for Quit

            self.clock.tick(50)
            self.screen.fill(BLACK)
            self.check_input()

            if self.state == STATE_PLAYING:
                self.move_ball()
                self.handle_collisions()
            elif self.state == STATE_BALL_IN_PADDLE:
                self.ball.left = self.paddle.left + self.paddle.width / 2
                self.ball.top  = self.paddle.top - self.ball.height
                self.show_message('PRESS SPACE TO LAUNCH THE BALL')
            elif self.state == STATE_GAME_OVER:
                self.show_message('GAME OVER. PRESS ENTER TO PLAY AGAIN')
            elif self.state == STATE_WON:
                self.show_message('YOU WON! PRESS ENTER TO PLAY AGAIN')

            self.draw_bricks()

            # Draw paddle
            pygame.draw.rect(self.screen, BLUE, self.paddle)

            # Draw ball

            pygame.draw.circle(self.screen, WHITE, (self.ball.left + BALL_RADIUS, self.ball.top + BALL_RADIUS), BALL_RADIUS)

            self.show_stats ()
            pygame.display.flip()

if __name__ == '__main__':
    Bricka().run()

  

 Bonus:

Here is my first attempt at programming a game in Scratch from November of 2011.

1921SeaCowFlickr-theirhistory

2 thoughts on “In which I Pursue Progress with Programming in Python

    1. mrmcgaughey Post author

      Thank you Leonel. Your tutorials are written very clearly and have helped to made it easy for me to understand the basics of Python.

      Reply

Leave a Reply to Leonel Machava Cancel reply