Hello World!

12 Days of Python – Day 6

This is Day 6 of 12 Days of Python  This is the sixth in a series of posts where we use Python and the Pygame module to draw a Christmas scene.  Each day we add something else to the scene, and we show a new aspect of Python or Pygame.  We’re also having a giveaway , where you can win a Kindle Touch!

On Day 1, we made a Pygame window and used the Pygame draw functions to draw Santa using lines circles and polygons.  On Day 2, we made Santa’s arm wave.  On Day 3, we added a calendar.  On Day 4 we added code to cross off the days on the calendar.  On Day 5, we added a background.

For Day 6 we’re going to add a Christmas tree.  The bottom (trunk) of the tree is just a rectangle, and the branches are just triangles.  But, just to make it interesting, the function to draw the branches uses recursion.  Recursion is where a function calls itself.  If you look at the draw_a_tree() function (lines 15-24), you will see that it calls the draw_a _tree() function inside it.  The function is called for the first time in line 51.

We didn’t talk about recursion in our book.  Recursion can be tricky.  It’s easy to write code that gets into an endless loop when you’re writing recursion.  And recursive code can be tricky to debug if something is wrong.

We didn’t need to use recursion to draw the tree.  It would have worked just as well with a simple for loop.  We just thought we show you something different!

# santa_6.py
# This is the code for Day 6 of "12 Days of Python",
# by the authors of "Hello World! Computer Programming for Kids and Other Beginners".

import pygame, sys, math, datetime

def rotatePointAroundCenter(point, center, degrees):
    displacement = (point[0] - center[0], point[1] - center[1])
    radians = math.radians(degrees)
    newPoint = [0,0]
    newPoint[0] = displacement[0] * math.cos(radians) + displacement[1] * math.sin(radians)
    newPoint[1] = displacement[1] * math.cos(radians) - displacement[0] * math.sin(radians)
    return newPoint

def draw_a_tree(surface, leaf_size, (x,y), is_trunk=True):
    if is_trunk:
        rect = pygame.rect.Rect((x - 25, y - 30), (50,60))
        pygame.draw.rect(surface, (102,68,34), rect)
        draw_a_tree(surface, leaf_size, (x, y-30), False)
    elif leaf_size <= 2:
        return
    else:
        pygame.draw.polygon(surface, (0,200,0),((x-leaf_size/2,y),(x+leaf_size/2,y),(x,y-(2*leaf_size/3))))
        draw_a_tree(surface, 3*leaf_size/4, (x, y-leaf_size/3), False)

pygame.init()

pygame.display.set_caption("12 Days of Python")

screen = pygame.display.set_mode((640,480))
santa = pygame.surface.Surface((640,480)).convert_alpha()
santa.fill((0,0,0,0))
screen.fill((0,0,0))

santasArm = pygame.surface.Surface((640,480)).convert_alpha()
santasArm.fill((0,0,0,0))

background = pygame.surface.Surface((640,480))
background.fill((255,0,0))

#---BACKGROUND DRAW
pygame.draw.polygon(background, (148,123,90), ((0,480), (100,320), (540, 320), (640, 480)))
pygame.draw.polygon(background, (139,89,49), ((0,0), (100,0), (100,320), (0,480)))
pygame.draw.polygon(background, (139,89,49), ((640,0), (540,0), (540,320), (640,480)))
pygame.draw.polygon(background, (102,68,34), ((100,0) ,(540, 0), (540, 320), (100, 320)))
calendar = pygame.surface.Surface((189,150))
calendar.fill((255,255,255))

tree = pygame.surface.Surface((640,480)).convert_alpha()
tree.fill((0,0,0,0))
draw_a_tree(tree, 200, (100, 360))

#---CALENDAR DRAW
for i in range(0, 189, 27):
    pygame.draw.line(calendar, (0,0,0), (i,30), (i,150), 2)
for i in range(30, 151, 24):
    pygame.draw.line(calendar, (0,0,0), (0, i), (189, i), 2)

cal_head_font = pygame.font.Font(None, 26)
cal_head_surface = cal_head_font.render("DECEMBER", True, (0,0,0))
cal_head_rect = cal_head_surface.get_rect()
cal_head_rect.center = (94.5, 15)

cal_num_font = pygame.font.Font(None, 20)

for i in range(1,32):
    cal_num_surface= cal_num_font.render(str(i), True, (0,0,0))
    cal_num_rect = cal_num_surface.get_rect()
    cal_num_rect.center = (((i+3) % 7 * 27) + 13.5,((i+3) // 7 * 24) + 42)
    calendar.blit(cal_num_surface, cal_num_rect)

calendar.blit(cal_head_surface, cal_head_rect)

#---CALENDAR CROSSOUT
today = datetime.datetime.now().day

for i in range(1, today):
    pygame.draw.line(calendar, (0,0,0), (((i+3) % 7 * 27) + 27, ((i + 3) // 7 * 24) + 30),
                (((i + 3) % 7 * 27),  ((i + 3) // 7 * 24)+54), 3   )

#---L ARM DRAW
pygame.draw.polygon(santasArm,(255,0,0),((274,207),(264,197),(243,182),(226,168),
                    (215,154),(212,153),(206,158),(192,155),(183,157),
                    (182,172),(204,190),(219,208),(244,231),(261,245))) #arm n hand
pygame.draw.polygon(santasArm, (255,255,255),((243,182),(242,176),(231,167),
                    (226,168),(218,181),(204,190),(204,200),(212,208),
                    (219,208),(232,197))) #arm fur
santasRotArm = santasArm.subsurface(pygame.rect.Rect((182,153),(92, 92)))
#---R ARM DRAW
pygame.draw.polygon(santa,(255,0,0),((358,191),(405,202),(428,207),(448,212),
                    (457,220),(459,226),(457,232),(444,236),(440,243),(421,237),
                    (399,233),(389,233),(344,236))) #arm n hand
pygame.draw.polygon(santa,(255,255,255),((428,207),(418,197),(406,197),
                    (407,204),(400,215),(401,237),(421,238),(421,223))) #arm fur
#---L LEG DRAW
pygame.draw.polygon(santa,(255,0,0),((270,323),(268,345),(266,352),(305,361),
                    (309,352),(317,326),(319,312),(272,306))) #leg
pygame.draw.polygon(santa,(102,68,34),((301,370),(266,361),(247,356),(231,357),
                    (224,368),(227,380),(245,388),(272,386),(274,390),(295,391))) #boot
pygame.draw.polygon(santa,(255,255,255), ((301,370),(312,355),(303,352),(293,348),
                    (279,346),(268,342),(263,343),(266,361))) #fur
#---R LEG DRAW
pygame.draw.polygon(santa,(255,0,0),((322,326),(330,352),(331,359),(372,350),
                            (369,323),(367,311),(316,314))) #leg
pygame.draw.polygon(santa, (102,68,34),((340,369),(373,361),(396,356),(410,359),
                    (415,375),(400,387),(366,386),(365,392),(347,393),(340,386))) #boot
pygame.draw.polygon(santa,(255,255,255),((373,361),(340,369),(334,368),(326,353),
                    (345,348),(359,347),(375,343)))
#---BODY DRAW
pygame.draw.polygon(santa, (255,255,255), ((234,289),(226,299),(230,316),
                    (281,322),(304,327),(317,326),(333,322),(363,324),
                    (408,304),(410,287),(402,275),(328,208),(281,207))) #vest fur
pygame.draw.polygon(santa, (255,0,0), ((271,188),(245,231),(236,259),(234,272),
                    (235,287),(241,295),(294,302),(300,298),(304,285),
                        (298,217))) #vest 1
pygame.draw.polygon(santa, (255,0,0), ((326,235),(328,286),(330,295),(335,300),
                    (369,297),(401,277),(389,234),(357,192),(334,197))) #vest 2

pygame.draw.circle(santa,(0,0,0),(315,243),4)
pygame.draw.circle(santa,(0,0,0),(314,257),4)
pygame.draw.circle(santa,(0,0,0),(315,274),4)
pygame.draw.circle(santa,(0,0,0),(317,293),4)
#---HEAD DRAW
pygame.draw.polygon(santa, (255,255,255),((278,153),(272,188),
                    (281,211),(300,232),(315,238),(326,232),(346,215),(357,191),
                    (351,151),(278,153))) #beard
pygame.draw.polygon(santa, (255, 218, 185),((282,151),(283,166),(309,178),
                    (315,179),(321,177),(345,166),(346,152),(335,140),(310,133),
                    (289,141))) #head
pygame.draw.polygon(santa, (255,0,0),((266,139),(278,123),
                    (293,112),(315,110),(343,115),(312,85),(260,134))) #hat main
pygame.draw.polygon(santa,(255,255,255),((346,152),(335,140),(310,133),
                    (289,141),(282,151),(270,150),(261,146),(266,139),(278,123),
                    (293,112),(315,110),(343,115),(357,132))) #hat rim
pygame.draw.circle(santa,(255,255,255),(255,149),15) #hat ball
pygame.draw.circle(santa,( 50, 50, 50),(307,151),3) #eye
pygame.draw.circle(santa,( 50, 50, 50),(319,151),3) #eye
pygame.draw.polygon(santa,(255,255,255),((310,140),(301,141),(294,145),(294,149),
                    (303,145),(309,144))) #eyebrow
pygame.draw.polygon(santa,(255,255,255),((315,146),(324,146),(330,150),(331,146),
                    (326,142),(317,140))) #eyebrow
pygame.draw.polygon(santa,(255,255,255),((283,167),(287,177),(296,182),(311,176),
                    (305,169),)) #mustachelet
pygame.draw.polygon(santa,(255,255,255),((344,168),(323,166),(319,176),(336,178))) #mustachelet
pygame.draw.lines(santa, (0,0,0), False, ((307,165),(307,169),(310,173),(321,171),(322,164)),2) #nose
counter = 0
clock = pygame.time.Clock()
while 1:
    clock.tick(30)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
    screen.fill((0,0,0))
    #screen.blit(santasArm, (0,0))
    rotatedArm = pygame.transform.rotate(santasRotArm,math.sin(counter/5.0)*10-7)
    rotArmRect = rotatedArm.get_rect()
    rotArmPos = rotatePointAroundCenter((86,73),santasRotArm.get_rect().center,-math.sin(counter/5.0)*10+7)
    rotArmPos[0] += 190
    rotArmPos[1] += 180
    rotArmRect.center = rotArmPos
    screen.blit(background, (0,0))
    screen.blit(tree, (0,0))
    screen.blit(calendar, (400, 20))
    screen.blit(rotatedArm, rotArmRect)
    screen.blit(santa, (0,0))
    pygame.display.flip()
    counter += 1

Here’s what it looks like when you run it:

To try the code out yourself, you can cut-and-paste it from the code window above into your favorite Python editor.

On Day 7, we’ll add some Christmas lights to the scene.

Warren & Carter