I have a 15 month old daughter that simply loves to play on the laptop. Pressing random keys until I notice. Because of this I have gotten into the habit of closing my laptop while not using it. This has saved me from sending lots of random messages to random people.
Closing and opening my laptop all day is quite tedious. The best way to resolve this problem is to place a greater temptation in front of her. The only quesiton is what is that?
I found an old netbook laying around that I haven’t used in months. So I wrote a game.
I have been meaning to play with pygame for a while now and this gave me the perfect excuse to do so. The ‘requirements’ for the game were:
- it must be simple enough to do in about an hour
- it should do something on any input
- the input is any keypress.
- it should entertain a 15 month old toddler
- display an image
- hide that image behind a grid of 4×4 black rectangles
- on any key press remove a random rectangle
- this causes a section of the hidden image to be displayed
- if the entire image is shown, next keypress will cycle to the next image.
The above is extremely rudimentary. However, the audience has not acquired sophisticated tastes as of yet.
I wrote the pygame app last night and tested it out this afternoon. She loves it. She now has her very own laptop. She can bash the hell out of the keys and mommy and daddy do not stop her. Also, something happens on the screen too! Most exciting ;)
Usage is simple:
- mkdir -p ~/.phoebe/images
- put as many images as you want in the above dir
- python phoebe.py
Problems and Known limitiations:
- I wrote this in an hour while learning pygame
- I assume a lot and if you aren’t on the latest ubuntu w/ pygame it will probably throw exceptions and crash. Sorry
- I did get it working on an old debian install with python2.5, see comment in World.__init__
If I do more with this I will throw it up on github.
Here is the python source:
#!/usr/bin/env python import os import sys import glob import itertools import random import datetime import pygame from pygame.locals import * world = None def init(): pygame.init() global world world = World() class World: def __init__(self): # this might not be available in older versions of python. If # that is the case, simply hard code the resolution to your # screen size. vid_info = pygame.display.Info() self.size = self.width,self.height = vid_info.current_w/2,vid_info.current_h/2 self.screen = pygame.display.set_mode(self.size) images_files = glob.glob(os.environ["HOME"]+"/.phoebe/images/*.jpg") self.images = itertools.cycle(images_files) self.image = None self.grid_size = 4 self.masks = self._get_masks() self._to_blit =  random.seed(datetime.datetime.now()) def _get_masks(self): black_mask = pygame.Surface((self.width/self.grid_size, self.height/self.grid_size)) black_mask.fill((0,0,0,0)) rv =  for y in range(0,self.grid_size): ay = y * black_mask.get_height() for x in range(0,self.grid_size): ax = x * black_mask.get_width() rv.append((black_mask.copy(),(ax,ay))) return rv def _next_image(self): img = self.images.next() img_surface = pygame.image.load(img).convert() self.image = (pygame.transform.scale(img_surface,self.size),(0,0)) def next(self): self._to_blit =  if not len(self.masks) or not self.image: #no more masks, setup the next image self._next_image() self.masks = self._get_masks() else: # we have masks remove on if len(self.masks) > 1: #if there is only one mask left, then range is 0 to 0, and randrange complains to_r = random.randrange(0,len(self.masks)-1) self.masks.pop(to_r) else: #this is the last mask, self.masks.pop() #put the image into the blit list self._to_blit.append(self.image) self._to_blit += self.masks def blit(self): screen = pygame.display.get_surface() for s,p in self._to_blit: screen.blit(s,p) def main(): global world init() world.next() clock = pygame.time.Clock() done = False while not done: clock.tick(30) world.blit() pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: done = True elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: done = True else: world.next() pygame.quit() return 0 if __name__ == "__main__": sys.exit(main())