Kinesthetic Sensations: the Making of a Toy Drawing Program

Renaissance painting of Apollo playing the viola.

— an Experiential report

Abstract

I recently made four small arcade games using pygame & python, where the graphics were drawn by hand-code rather than external drawing programs. While the next planned game calls for more advanced graphics, I want to continue using my monochrome pygame-drawn approach. After I realized that a drawing program and the mapmaker program from my breakout game are roughly equal, I then experienced a bodily rush holding the structure of the future drawing program as kinesthetic sensations, and as a result made a toy-sized drawing program (PaintyPaint) in a couple of hours.

Intro

I recently finished a missile command game, following this strategic guide, and despite promising myself to lay off the game development for a while to focus on more important matters… I ended up thinking about how to implement space invaders the moment I got inside the door to my apartment. The game itself seemed immediately straightforwards: make a 2D grid of aliens and reverse direction whenever the extremes touch the screen borders, and use some randomized blacking out of pixels for the barrier destructions.

The graphics, however — different aliens, with poses? Specifying those in terms of drawing primitives by hand seemed annoying. One of the side-effects of the code-generated graphics I liked was the option to change the game colour in the settings, and I wanted to continue having that option. Now, obviously, it’s possible to draw images in a normal drawing program, load the image files, and then do some pixel-by-pixel analysis in order to convert the colour to the desired one. But I didn’t feel like doing that: I wanted to find some simpler solution.

Problem “Analysis” — by kinesthetic sensations

While pondering the potential different paths I could take, I caught myself thinking: “If only I had a drawing program that saved images in a ready-for-my-purposes image format.” And then a moment later, I realized that what if I had a drawing program fit for my purposes? No analysis overhead necessary, just make a load function that draws the graphics from some format specification! And what is an image file format if not a specification of colours over a coordinate system?

This meant that the mapmaker from the breakout game and a drawing program of similar complexity were basically equal, if we treat brick type and colours as subtypes of some abstract display detail! And, at that idea, I felt a rush through my body, and could simply feel the structure and workings of the drawing program, as well as the changes that would be necessary to adapt the mapmaker into it, as prickles and tensions. (I wish I could give more detail, but there’s a time gap between the occurrence and the autopsy here.) While still in that state I found a piece of paper and jotted down some details, and the next morning I found it easy to recall the conception of the drawing program, as if reading the notes let me easily “hook onto” the actual idea.

Implementation

The breakout mapmaker is a simple 128-line program in one single source file featuring some constants, initializations, inclusion of block graphics residing in a file used by both the mapmaker and the breakout game, and a while loop. For the first attempt at the drawing program, I copied the mapmaker, removed the block graphics, made an enum for colours (colour, black & transparent), changed the program draw cycle to handle the pixel graphics rather than breakout maps, and then took care of half a dozen variable handling bugs I had overlooked in my enthusiasm. And then the program mostly worked, except for an odd bug in the program drawing itself, leading to the “pixel” displays along the bottom and rightern edge becoming elongated and reaching out to the edge of the screen rather than staying inside the centralized canvas area. And the corner pixel reached out in both directions, covering about a sixth of the program window. Whoops.

So I re-read the program a couple of times and tried a couple of changes to the formulation of how the squares representing the pixels were drawn, but the bug persisted. Finally, I thought I might have overlooked the handling of some odd variables or something, and started writing the drawing program anew, adding piece by piece, sometimes copying the pieces from the mapmaker, sometimes writing them up by hand. I set a few extra variables to handle the canvas centering vs mapmaker maps. The save, load and new buttons got turned into instances of a base button class rather than just imperative code. The main loop got simpler as I re-wrote it with the colouring of pixels in mind, and I typed in the entire drawing cycle for displaying the “pixels” anew. And the bug remained. At that point, I was using pygame.draw.rect in a double for loop to plaster the relevant colours over the sections of the screen, and I just couldn’t see anything wrong with the math.

So to solve that bug, I instead initiated three different pygame surfaces, each simply a coloured square of the desired size and then I “stamped” them on in the right places, using the same math for locating the upper left corner of each square as when using pygame.draw.rect: et voilà, no more oddly bloated bottom, rightern or corner pixels. Possibly, also more efficient than using pygame.draw.rect since the surfaces could be .convert()’ed to the format required by the screen, rather than potentially figuring that out per pygame.draw call.

Conclusion

For comparison, the drawing program sits at 173 LOCs. It only has a “pencil” functionality, and colour selection through the 1, 2 and 3 buttons on the keyboard. But it works, and may well be sufficient for my purposes in making the rest of the monochrome arcade games. We’ll find out once I set to work actually using it. It was an interesting experience nonetheless, because the conception of the program and its structure didn’t come as a sequential series of logical tidbits, but rather as a kinesthetic sensation of its structure and functional aspects! I didn’t really plan the program, I just jotted down the translations from the kinesthetic sensations to thoughtforms so as to have a record to consult at a later point. In some way, then, the program of around 170 lines was obvious in the same way that I used to be able to simply feel my way for short functions. I’m curious to see whether continued computer work will expand the boundaries of this obviousness to ever bigger (sub-)systems.

The drawing program is very much a toy, though. It does not have undo and redo functions, nor a fill bucket, nor easy selections from a side menu, nor cut-and-paste, invert or other functions like those which might be useful. As a concluding remark, then, allow me to extend an open invitation: If you’re a relatively new programmer and interested in doing so, feel free to look at and poke around in the source code and see if you can improve upon PaintyPaint. After all, PaintyPaint is decently small, and it’s sometimes hard to find small programs.

Click Here to Leave a Comment Below