Building a game for ET. Day 1 with Pygame 14 Feb 2010

Earlier this week I was checking out Pygame, pondering what I could possibly build with it that could keep me motivated enough to finish it. Motivation would like be the primary problem for me with any amount of game programming; I’m not a gamer, I don’t harbor a dislike of games, they’re just not something I typically spend time playing (I do like to play “haggard late night open-source hacker” though, that’s a fun one). Friday night I stumbled across an idea, ET likes to play (casual) games, perhaps we could write a game together; ask any engineer at EA or Ubisoft, there’s nothing more romantic than working on a game.

Talking over the idea with ET on the ride home from the office, we talked about creating a typing-oriented game and started to brainstorm. The tricky aspect of a typing-oriented game is you have to walk the fine line of “educational gaming”, that is to say, the game’s goal is not to teach the player how to type. That sucks. Contrasted to some other games where the means of progressing in some games is by solving a puzzle, killing noobs in others, in this game we wanted the player to progress through levels/situations with their typing ability (ET finds this fun, we do not have this in common).

Over pizza we discussed more about how the levels would work, I decided that I wanted to use stories/articles instead of random words for the “content” of the game. We settled on a couple fundamental concepts: the player would earn coins by correctly completing a words as the scrolled from right to left (similar to a ticker tape), they would lose coins if they made a mistake or could not keep up. After a player completed a level (i.e. a “story”) they would find themselves in a “store” of sorts, where they could purchase “tools” for future levels with their coins. The tools we decided would be a very important, as the player reached their upper bound of typing speed the utility of these various tools would necessary as a means of strategically conquering the level. One of the few things we didn’t particularly cover was the “end game”, whether the player would simply play increasingly more difficult levels (a la Tetris) or if they could actually “beat” the game. With at least the basics of the concept sketched out, it was time to start writing some code.

Starting with Pygame

It’s incredibly important to mention that I’ve never programmed a game before. Never-ever. From my work with network programming I was already familiar with the concept of the run-loop that’s pretty core to Pygame, but I had never really made use of any to animate objects on the screen or deal with handling any kind of events from mouse movements to key presses, etc. Fortunately I’m already a professional Python developer, so writing code wasn’t the difficult part so much as laying it out. Orienting things into classes to handle separate components such as animating text (which is a painful in Pygame, in my opinion) to keeping track of user-input.

Animating text across the screen wasn’t particularly difficult, with Pygame you first create your primary “surface” (i.e. the window) and then you can render things onto that surface. With text, you end up rendering a surface which contains your text, “hello world” which you then place onto the primary surface. Easy peasy thus far: import pygame surface = pygame.display.set_mode((640, 680), pygame.HWSURFACE | pygame.DOUBLEBUF) font = pygame.font.SysFont('Courier', 42) ### render(text, antialias, rgb color tuple font_surface = font.render('hello world', 0, (0, 0, 0)) ### draw `font_surface` onto `surface` at (x=0, y=0) start_x, start_y = 0, 0 surface.blit(font_surface, (start_x, start_y)) while True: ### Holy runloop batman pygame.display.update()

That was fun, I now have “hello world” rendered onto my screen, now to animate I suppose I’ll just render font_surface a little further right every iteration of the runloop, i.e. while True: ### Holy runloop batman surface.blit(font_surface, (start_x, start_y)) start_x += 0.5 pygame.display.update() This blurs the text however, so I then changed to: while True: ### Holy runloop batman surface.blit(font_surface, (start_x, start_y)) surface.fill((0, 0, 0)) start_x += 0.5 pygame.display.update() This will cause the (primary) surface to be repainted (washed over) every iteration of the runloop ensuring that the text will properly animate, drawing the text in one spot, wiping the surface then drawing it slightly further to the left, resulting in the scrolling animation. All’s fine and good until you determine that you want to have other elements on the screen and you also don’t want to redraw them every time around the carousel. I then discovered how to “fill” just one particular rectangle on the surface, i.e. the rectangle behind the text: text_w, text_h = font.size('hello world') while True: ### Holy runloop batman surface.blit(font_surface, (start_x, start_y)) surface.fill((0, 0, 0), rect=pygame.Rect(start_x, start_y, text_w, text_h)) start_x += 0.5 pygame.display.update()

Once I was able to get text properly scrolling across the screen, the rest of the afternoon of hacking was far easier. My confidence in my ability to grok Pygame in order to do what I wanted. I then set forth organizing my code into some logical classes, for example I created a LetterSpool class which would record the user’s progress through the current word, rendering it at the bottom-center of the screen and firing an event when the user hit the space bar (denoting the word “complete”), additionally I wrapped my text animation code into AnimatedWord so I could easily string words together to scroll across the screen in conjunction similar to a textual screensaver.

Not a whole lot more to write about with regards to my progress today, hooked up some music and basic sound effects which was trivial after looking at some sample code. Next I need to start addressing some more fundamentals for user-interaction: scoring and level-changing.

You can track the progress of the game “Typy” (pronounced: typey) on GitHub