# This code creates a polygon and then rotates it around one of its points. # Two static polygons are here so you can experiment with them, but you'll # have to uncomment them first. # Practice: # When you start this example, the two lines of text will be too close to each other. # How could that be fixed? # # Also, the starting shape is kinda small. We can increase it with our Up arrow, # but can you find what should be changed in this example so that that shape # starts larger by default? import pippy, pygame, sys from pygame.locals import * from random import * from math import cos, sin from math import pi as Pi import gtk # always need to init first thing pygame.init() # XO screen is 1200x900 size = width, height = gtk.gdk.screen_width(), gtk.gdk.screen_height() # create the window and keep track of the surface # for drawing into screen = pygame.display.set_mode(size) # turn off the cursor pygame.mouse.set_visible(False) # This is used to define how our shapes (polygons) look like and behave. # By default, a polygon will have three sides (a triangle), each 300 in length. class Polygon(object): # If you don't specify the number of sides and length you with your # polygon to have, it will take these values as default. def __init__(self, n = 3, length = 300): if n < 3: print "Number of points cannot be less than three" return self.n_sides = n self.side_length = length self.points = [] starting_point = (0, 0) self.points.append(starting_point) for i in range(n-1): point = self.points[i][0] + cos(2 * Pi * i/n) * length, \ self.points[i][1] - sin(2 * Pi * i/n) * length self.points.append(point) # This defines how our polygon will draw itself on a surface we give it. # The surface variable is called "screen" in this example. # Variable "start" defines the point from which we'll start drawing it, and # then later rotating it. By default, it's the middle of the screen. # def draw(self, screen, start = (screen.get_width() / 2, \ screen.get_height() / 2) ): real_coordinates = [] for point in self.points: real_point = point[0] + start[0], point[1] + start[1] real_coordinates.append(real_point) # draw a line between each two neighbouring points for i in range(len(real_coordinates)-1): pygame.draw.line(screen, (0, 255, 0), real_coordinates[i], real_coordinates[i+1]) # another line between the last point and the first one to close the polygon pygame.draw.line(screen, (0, 255, 0), real_coordinates[i+1], real_coordinates[0]) # This rotates the polygon around its starting point. # It doesn't draw anything - it recalculates where all the other vertices # will be when the triangle is rotated. def rotate(self, angle): # delete everything but the starting point, since we need to # calculate all the other points again self.points = [(0,0)] for i in range(self.n_sides-1): point = self.points[i][0] + cos(angle + 2 * Pi * i/self.n_sides) * self.side_length, \ self.points[i][1] - sin(angle + 2 * Pi * i/self.n_sides) * self.side_length self.points.append(point) # OK, let's create out polygon! # Set some values it will use.. (practice hint here!) side_length = 50 number_of_sides = 5 rotation_angle = 0 speed_factor = 0 poly1 = Polygon(number_of_sides, side_length) # Commented out is the code which creates two more polygons. You could # uncomment it to try it out. Code: # poly2 = Polygon(number_of_sides, side_length) # triangle1 = Polygon(length = side_length) # Background color will be black. bgcolor = (0, 0, 0) # for displaying the instructions and rotation speed font_size = 36 font_colour = (0, 250, 0) font = pygame.font.Font(None, font_size) # Conversion from degrees to radians. For us, it represents the smallest amount # of rotation possible. If you wish to understand it better, it has to do with # math (trigonometry) so you can try finding some information about it. degree = Pi / 180 # While L or R arrow is pressed and held, these variables will change so that # our program knows to keep increasing the speed of the rotation. # Left arrow increases the rotation in the counter clockwise direction (+) and # the right one clockwise (-). less = False more = False # for controling the polygon size when U or D arrow is pressed size_changed = False while pippy.pygame.next_frame(): for event in pygame.event.get(): if event.type == QUIT: sys.exit() # right arrow makes it rotate clockwise elif event.type == KEYDOWN and event.key == K_RIGHT: less = True # left arrow makes it rotate counterclockwise elif event.type == KEYDOWN and event.key == K_LEFT: more = True # when a key is lifted, stop changing speed elif event.type == KEYUP and event.key == K_RIGHT: less = False elif event.type == KEYUP and event.key == K_LEFT: more = False # Changing the size of our polygon with up and down keys. # Practice: Unlike L and R keys, this does not keep changing size # while the keys are pressed. Could you make it so? Look to L and R # examples to understand how it's done. elif event.type == KEYDOWN and event.key == K_UP: side_length += 5 size_changed = True elif event.type == KEYDOWN and event.key == K_DOWN and side_length > 5: side_length -= 5 size_changed = True elif event.type == KEYDOWN and event.key == K_q: sys.exit() screen.fill(bgcolor) # display instructions, speed and size msg = "Use left and right arrows for controling speed. Speed: " msg = msg + str(speed_factor) msg2 = "Use up and down arrows for controling size. Size : " + str(side_length) msg3 = "Press q to quit." text1 = font.render(msg , True, font_colour) text_box1 = text1.get_rect() text_box1.top = height / 20 text2 = font.render(msg2 , True, font_colour) text_box2 = text2.get_rect() text_box2.top = height / 20 + 14 text3 = font.render(msg3 , True, font_colour) text_box3 = text3.get_rect() text_box3.top = height / 20 + 28 # if the L or R arrow is pressed (and held), keep adjusting speed # You'll have to click it real fast if you with to change the speed by # only one! if less == True: speed_factor = speed_factor - 1 if more == True: speed_factor = speed_factor + 1 # The new angle by which our polygone is turned is the previous angle + the # change in rotation due to speed_factor being changed by L or R keys. rotation_angle = rotation_angle + degree * speed_factor # If the size was changed (with up and down keys), create a new polygon # with that size. if size_changed == True: poly1 = Polygon(number_of_sides, side_length) size_changed = False poly1.rotate(rotation_angle) poly1.draw(screen) # This should also be uncommented if you with to see some other polygons # we've prepared for you. # Practice: Uncomment the code and change some values. What happend? # Code to uncomment: # poly2.draw(screen) # triangle1.rotate(30 * Pi / 180) # triangle1.draw(screen, (800, 650)) # draw the text screen.blit(text1, text_box1) screen.blit(text2, text_box2) screen.blit(text3, text_box3) # refresh the screen pygame.display.flip()