I've been working through a few different tutorials found from pygame.org. A link somewhere led me to this blog tutorial. One of the pluses of this particular tutorial is that it has exercises - suggestions to improve your code that require figuring it out yourself.
The exercise that caught my attention was to draw this pattern to the screen:
After staring at it for a few minutes, I still couldn't recognize the pattern. That's frustrating by itself, but I also knew I'd seen it before. I think a larger picture would have helped, but what can you do? Shane looked over and saw the relationship much more quickly, so he had to explain it to me. After that, I could play and tweak the pattern to suit my whims. So here I'll describe how I made the pattern, and variations of it.
Here is a larger image with fewer lines, which I generated to help show the mathematical relationship.
It is relatively simple once you spot it:
- the lines ends are spaced evenly across the two sides
- the first line along the left edge ( the very bottom line ) is also the first line along the top edge ( the left most line )
Now for some code. First, the framework. I'll be changing the code up from my original code a bit, but I'll test it as I go.
import pygame, sys w=800 # width of the screen h=800 # height screen = pygame.display.set_mode((w,h)) # I like to have basic colors predefined white = (255,255,255) black = (0,0,0) # since we are producing a static image, just draw to the screen once. screen.fill(black) pygame.display.flip() # main loop - close the window properly while True: for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit(0)This creates a very exciting 800x800 window filled with black. The only user interaction is to close the window. This Framework (or something very similar) is what all my pygame programs look like so far, since I'm still learning the basics myself.
Next I'm going to draw some lines. Since there's a simple relationship between the start and end points of a line, and each line start is evenly spaced, the situation screams for a function and a for loop. I mean function in the mathematical sense, although it could be implemented in code just as well. I'm only going to present the code that changed. I've added some additional variables to keep track of handy values, and a loop which draws the lines. Place it all between the python.fill(black) and pygame.display.flip() and you're home free. For slightly better organization, place the variables above any of the drawing code.
N = 10 # this is the number of lines to draw (actually, it draws N-1) dx = w/N # this is the horizontal pixel offset (the number of pixels between each line, give or take one pixel) dy = h/N # the same for vertical offset
for i in range(1,N): # loop over the line number pygame.draw.aaline(screen,white, (0,i*dy), (w-i*dx,0)) # express the simple relationship between the line number and its positionNow this code will create the image above (the second shown), which uses only a few lines and a large screen to show the pattern in the line positions. From here on out, I'll probably be using N = 20 and a screen size of 400x400.
Notice that you'll get the same effect if you just set dx and dy to the same value. There's a good reason not to do this though - because then I can't have the pattern scale if I choose a window that is not square (like 600x400). Here is the difference between scaling it for just the y value, and scaling it for both values. You'll see something different if you scale it for the larger value instead - it will look like it is scaled for a 600x600 square, and simply cropped.
If you run this, and play around with the values N,w, and h, you will find you can create very delicate looking images, or something more course looking.
On with the challenge: the goal is to repeat this pattern at all four corners (overlapping). We'll use four calls to python.draw.aaline in the for loop, one for each corner. We only need to add the three lines:
pygame.draw.aaline(screen, white, (0,i*dy), (w-i*dx,0)) # top left pygame.draw.aaline(screen, white, (w,h-i*dy), (i*dx,h)) # bottom right pygame.draw.aaline(screen, white, (0,i*dy), (i*dx,h)) # bottom left pygame.draw.aaline(screen, white, (w,h-i*dy), (w-i*dx,0)) # top rightMy original code was slightly different. The last two lines used the points (0,h-i*dy), (w-i*dx,h) and (w,h-i*dy), (i*dx,0) respectively. The only change this makes is if the lines were drawn one at a time, the order they are placed would be opposite (in fact, I may do this a bit later - if I feel like it. If not, feel free to do so yourself. There is a lesson here: there is more than one way to get the exact same effect. There is a reason I changed it, which I'll point out later. Another inconsequential varient: it does not matter which point is first or last in the line. For the top left pattern, (w-i*dx,0), (0,i*dy) is the same.
There are some cool varients on this as well. I like drawing just two of the four corners. Opposite corners and adjacent corners look very differnt patterns. Another interesting one is if you accidently (or purposely) mix up some of the positions. For example, the bottom left corner can be switched from (0,i*dy) (i*dx,h)to use (0,i*dy) (w-i*dx,h), a pattern which appears much more linear than the original. Just for fun, I also overlapped the original "curvy" image and the linear image, using all four corners. Quite complicated looking, but build from a single, simple idea.
There are more variations of this. What about color?
Color can be varied just as easily as position. Let's try it. Add a delta for color (which can range from 0 to 255): dc = 255/N. Add color = (255,255,255-i*dc) to the for loop, and change the line from using "white" to "color". To reverse the light and dark side of the pattern, use i*dc instead of 255-i*dc. Now for the reason I changed the order the lines were drawn in for two of the colors: when you draw all four colors, you now get this pretty display: If I had not reordered the lines, I would have gotten this one instead: This second image can be achieved by either changing the line order as mentioned above, or adding an additional color alt = (255,255,i*c), and using this new color with the top right and bottom left. Once again, many ways for the same result. As a last touch for now, here's the same colors used with the linear pattern:Labels: math, patterns, pygame, python, tutorial
Leave one.
Top of the blog, but what can I say. This is why firefox rocks my socks. It underlines the words I misspell.
Other than that, I like your shiny pictures. I am an art student. That is the extent of my ability to say anything about anything.
Oh yes, and the green of your blog? Hard to read the text on my screen. Darker/more neutral would help.
THE END