Hello World!

12 Days of Python – Day 10

This is Day 10 of 12 Days of Python  This is the tenth 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. On Day 6, we added a Christmas tree (using recursion). On Day 7, we drew some Christmas lights. On Day 8, we added a picture on the wall behind Santa.  On Day 9, we added some presents

For Day 10 we’re adding a window to the scene.  This one is pretty simple.  We use a black polygon for the window itself (filled with black, because it’s dark outside).  Then a couple of lines for the cross pieces, and another rectangle – this one not filled – for the frame.

The only tricky part was figuring out the exact shape of the polygons to give the window some perspective.  We just played around with the points until it looked right.

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

import pygame, sys, math, datetime, random

def draw_a_light(surface, pos):
    pygame.draw.circle(surface, pygame.color.THECOLORS[random.choice(pygame.color.THECOLORS.keys())], pos, 6)

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_present(surface, (x,y)):
    (w,h) = random.choice([(100, 100), (50, 50), (75, 75)])
    present = pygame.surface.Surface((w,h))
    present.fill(pygame.color.THECOLORS[random.choice(pygame.color.THECOLORS.keys())])
    spotcolor = pygame.color.THECOLORS[random.choice(pygame.color.THECOLORS.keys())]
    for i in range(20):
        spotpos = (random.randint(0, 100), random.randint(0,100))
        pygame.draw.circle(present, spotcolor, spotpos, 10)
        pygame.draw.circle(present, (0,0,0), spotpos, 10, 2)
    presentrect= present.get_rect()
    presentrect.bottom = y
    presentrect.centerx = x
    surface.blit(present, presentrect)

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)
        if leaf_size > 30:
            light_rect=pygame.rect.Rect((0,0), (1,1))
            light_rect.width = leaf_size
            light_rect.height = 2*leaf_size/3
            light_rect.bottom = y
            light_rect.centerx = x
            pygame.draw.arc(surface, (0,0,0), light_rect, math.radians(-143), math.radians(74-110), 2)
            draw_a_light(surface, (x,y))
            draw_a_light(surface, (x - leaf_size/4, y-leaf_size/20))
            draw_a_light(surface, (x + leaf_size/4, y-leaf_size/20))

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))

#---ARTWORK DRAW
artwork = pygame.surface.Surface((640,480))
artwork.fill((0,0,0))

for i in range (100):
    width = random.randint(0, 250)
    height = random.randint(0, 100)
    top = random.randint(0, 400)
    left = random.randint(0, 500)
    color_name = random.choice(pygame.color.THECOLORS.keys())
    color = pygame.color.THECOLORS[color_name]
    line_width = random.randint(6, 9)
    pygame.draw.rect(artwork, color, [left, top, width, height], line_width)
artwork = pygame.transform.scale(artwork, (160, 120))

#---WINDOW DRAW
pygame.draw.polygon(background, (0,0,0), [(550,200),(630,280),(630,80),(550,60)])
pygame.draw.line(background,(0,80,0),(590,70),(590,240),10)
pygame.draw.line(background,(0,80,0),(550,130),(630,180),10)
pygame.draw.lines(background, (0,80,0), True, [(550,200),(630,280),(630,80),(550,60)], 10)

#---PRESENT DRAW
presents = pygame.surface.Surface((640,480)).convert_alpha()
presents.fill((0,0,0,0))
draw_a_present(presents, (500,400))
draw_a_present(presents, (460,430))
draw_a_present(presents, (70,420))
draw_a_present(presents, (130,440))

#---LIGHTS DRAW
pygame.draw.arc(background, (0,0,0), pygame.rect.Rect((0,-30),(320, 60)), -math.pi, 0, 5)
pygame.draw.arc(background, (0,0,0), pygame.rect.Rect((320,-30),(320, 60)), -math.pi, 0, 5)
draw_a_light(background, (6,6))
draw_a_light(background, (80,25))
draw_a_light(background, (160,30))
draw_a_light(background, (240, 25))
draw_a_light(background, (320, 6))
draw_a_light(background, (400,25))
draw_a_light(background, (480,30))
draw_a_light(background, (560, 25))
draw_a_light(background, (634, 6))
#---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(artwork, (120,50))
    screen.blit(tree, (0,0))
    screen.blit(presents, (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 11, we’ll make the lights (that we added on Day 7) blink.

Warren & Carter