Designing a Tetris Clone: Part 2

Wait, what? Part two? Where is part 1? Did we miss it?

Oh, wait… Never mind. I found it.

The story here goes like this: back in 2007 I had this crazy idea to make a Tetris clone. I was also frustrated by shitty “deveopmentstructive” environment I was working in a the time, and I wanted to do something the right way. You know, design it and then code it. Of course I would be cutting corners in the design process but I at least wanted to have some UML diagrams to show off. The other day I picked up this semi-abandoned project once again and coded it up over the weekend. Please keep in mind I have not been working on this software for the last 3 years. I worked on it for about a week (1-2 hours per day give or take) back in 2007, then I abandoned it. Last the weekend I picked it up again and built it from scratch abandoning everything I did in 2007 except for that initial blog post which was actually a pretty decent spec document if you looked at it in the right light.

The end result is not very pretty, but a fully playable and passable little game:

This is how the game looks right now

Here is what I learned from this project:

Don’t over-design it

Software engineering is a good thing. You should not be winging major projects and coding them digital cowboy style. You should be working in a group and from design documents. The group dynamics and good project management make this work. But if you are working alone on a hobby project, you can design yourself out of the whole thing. That’s what I did in 2007. I started by drawing UML diagrams and kept drawing them for a solid week. I agonized over encapsulation, and I was trying to pre-solve a lot of non-existing problems in my head and on paper without actually writing a line of code. In fact, I didn’t even have a clear idea what language/framework I would be using. I ended up with a pile of unfinished diagrams, no code written and a headache.

I had this sudden realization: this was supposed to be a fun weekend project and I’m sitting here agonizing over some stupid design document and totally not enjoying it. This is why I abandoned it altogether. I wasn’t having fun, so the whole exercise was pointless.

My second attempt was different – I went in with the intent of having fun so I pretty much just sat down and started writing code. No design on paper, no idea how I was going to do it. Just decided to figure it out as I go. The result of this was a finished (albeit a bit ugly and shaky) Tetris game about a day and a half later. In fact I the thing was playable (well, interactive – I could move a rectangle on the screen with my keyboard) within the first 10 minutes or so. Which brings me to my second point:

Make it playable as soon as you can

When designing games it is usually a best idea to have something that is playable or at least interactive right away. Don’t start by building a framework or a class structure of some sort. You can do that boring stuff later. Jump right into the heart of the project. The goal is to have something that you can sort of mess around with the first day. You know – a placeholder sprite moving around the screen or something. Start simple, then add complexity on top of it. Added benefit of this is that your simple game engine is easy to modify and re-design on the fly as needed. If you spent 30 hours engineering it on paper, and then you realize it doesn’t do something important forcing you to drop half of your intricate design it may be quite frustrating.

If you don’t do this, you will drown yourself in minute details. That’s what I did in 2007. I tried to design the whole game in my head first and I got lost in the detail. This year I started with just a single rectangle moving around on the screen and built the game around that and it was fun. I was riding the positive feedback loop the whole time. It is very rewarding when you can make some changes to your code, launch the game and see if and how they work right away. You actually see your game grow and take shape right in front of your eyes. In 2007 all I saw was a mountain of work, and the fun part (actually tweaking and testing the game while playing it) was a dim light at the end of a long dark tunnel. No wonder I dropped the project.

This is possibly the most important lesson for hobby projects ever – and it is so simple too. Make it fun now, leave the boring stuff for later. If you notice that are doing a lot of work so that you can get to the “fun part” you are probably doing it wrong. Just skip straight into the fun part.

Some design work does help though

Despite what I said in the previous paragraphs it does usually help to have some idea as to what exactly you are building. In my case I had a list of 17 Tetris facts and rules that helped me to stay on track. I also made drawings when I was designing the functions that would flip the pieces around so that I could keep track of the coordinate offsets. Stuff like that – outlines, sketches, lists of features – they help immensely. So you shouldn’t probably jump in and code straight away. You should first do some research and write down some things you want your game to do. You can feel free to ignore this stuff later on, but I highly advise to gather some research materials in one place early on. Otherwise you will fall into the distraction trap like me.

Here is what happens: sometimes when I write code, I need to look something up. For example how to calculate Tetris scores or whatever. So what do I do? I google it or look for sample code. Firstly, it ruins your flow – it takes you out of the code-mode, and makes you stop what you are doing and go somewhere else. Once you find what you need it will take you a little while to get back to where you where before you interrupted yourself. Secondly, half the time you take a break to look something up, you end up browsing the web for a while doing stupid shit.

Some thoughts on the project:

I used Python and PyGame to make this game. Why? Because I like Python and since I was making a game, it seemed logical to use the popular game creation framework for that language. The combination of these two tools meant that I didn’t really have to worry about excessive boilerplate code, event catching, drawing stuff on the screen and etc. It was all taken care of so I could concentrate on the actual game.

Another screenshot

If you want to see the code it is here. Please keep the following in mind though:

  1. This is by no means a finished game – treat it more like a rough pre-alpha draft
  2. The game and the code are bit ugly – this is my first time working with PyGame and I’m still learning
  3. ???
  4. Profit

In retrospect I think I should have went with sprites for graphics. As it is right now I’m just drawing the blocks using built-in PyGame toolkit and the result is a bit flat and ugly. Especially the text – I don’t really like this font and I sort-of eyeballed the distances so things are not spaced evenly. My next steps would be to make nice backgrounds for the game. A nice grid, a backdrop with slots for score, lines and etc and block pieces with actual shading on them.

That and I need to do some testing. I think the speed is still a bit wonky. The game should gradually speed up with each level, but I still have not found a perfect magical decrement number. I keep making it either to large (so at lever 4 or 5 the game becomes unplayable) or to small (the speedup is so gradual you hardly notice it).

Feel free to mess around with it if you want. The code is under GPL so you can use it as you will. Any suggestions, tips and/or contributions would be greatly appreciated.

I definitely want to play with PyGame some more. My next project… Well, I really want to make a 2d, top-down or isometric RPG. But that’s a huge undertaking and I haven’t figured out any details yet. Do I want it turn based, do I want it real time? Do I want the combat to feel more hack-and-slash or tactical? Do I want a randomly generated dungeon crawl or something more linear with hand crafted levels, quests and story line. Actually no, I know that – I want a game with a storyline, but it will be challenging to pull it off. My brother is on board too – though in a non-programing capacity. Maybe he can make some sprites and backgrounds. I don’t know.

Anyways, this is just an idea right now – as in, “wouldn’t it be awesome to make this” type of deal. Once I sit down and think this through I will make another post about it.

Quick Edit: Someone just told me that there is a occasional glitch in the game. In some special cases the blocks do not drop down properly after a line is removed. So far I was unable to replicate the scenario myself but supposedly it happens at the higher levels where there are many blocks on the screen and you are removing lines from the middle of the stack.

Quick Edit #2: Ah, I think I figured out the issue. The problem happens when you remove two or more non-contiguous lines. Sigh… I think I need a drastically different data structure for storing the immobile blocks. Storing them as an unsorted array of x/y coordinates makes it a bit hairy to perform the whole drop-down-after-line-removal operation.

This entry was posted in programming and tagged . Bookmark the permalink.



8 Responses to Designing a Tetris Clone: Part 2

  1. icebrain PORTUGAL Google Chrome Windows Terminalist says:

    Storing them as an unsorted array of x/y coordinates makes it a bit hairy to perform the whole drop-down-after-line-removal operation.

    Really? I’d think it would be easy, if you have an array like block[row][column], thanks to the wonderful slice list assignment:
    NUMBER_OF_ROWS = 3
    NUMBER_OF_COLUMNS = 3
    block = [[True, False, False],
    [True, False, True],
    [True, True, True]]
    for row in reversed(range(NUMBER_OF_ROWS)):
    columns = block[row]
    if all(columns): #if every column in that row has a block
    block[:row+1] = [[False] * NUMBER_OF_COLUMNS] + block[:row]
    print block
    #result:
    # [[False, False, False],
    # [True, False, False],
    # [True, False, True]]

    As you see, it removed the filled line and “dropped” the other, adding a blank (all False) to the top.

    Warning: poorly tested, on codepad: http://codepad.org/JC64rSu6 (great tool, btw)

    Reply  |  Quote
  2. mcai8sh4 UNITED KINGDOM Google Chrome Linux Terminalist says:

    Nice work! I’m a big fan of this type of development (for hobby coding of course).

    It certainly helps to keep the momentum going if you quickly get something that does something.

    Reply  |  Quote
  3. Luke Maciak UNITED STATES Mozilla Firefox Linux Terminalist says:

    @ icebrain:

    Wow… I was not aware of codepad. Thanks.

    Also, thanks for the tip. I shall see if I can apply it to my code.

    Reply  |  Quote
  4. dawn SWITZERLAND Mozilla Firefox Linux says:

    I was thinking about writing a tetris clone myself and wrote down some design ideas. So I have a solution to:

    # TODO: optimize the shit out of this

    This would change a few things in your program, but why don’t you make the board a boolean array. This way, collision detection is a matter of checking whether there is a 1/true in grid[xi][yi] where xi, yi are the coordinates of square i in the current piece.

    Reply  |  Quote
  5. I agree completely with “Make it playable as soon as you can.” I used to teach an intro to CS class six or seven years ago, and I would have first-semester students writing little C++ games within 12 or 13 weeks. Many of them got really excited about the games they were making because the framework we used allowed you to see things on the screen right away.

    When I first started playing with computers, you could write two lines of BASIC on a Commodore 64, type RUN, and it would work. That kind of immediate gratification is important to get people excited about programming if they’ve never done it before. And unfortunately, you can’t turn on a brand new computer and start writing code as easily these days.

    If I were to teach an intro CS class now, I’d consider using PyGame. Or maybe Randy Pausch’s Alice language.

    PS – If you want to see the games some of my students made, they’re still on an ancient (2005) web site here: http://csci.biola.edu/csci105/ – the only problem is they’re downloadable executables, and I don’t expect anyone to trust me that they’re virus free. But if you had some virtual machine, you could try them out.

    Reply  |  Quote
  6. Luke Maciak UNITED STATES Mozilla Firefox Windows Terminalist says:

    @ dawn:

    Yep, that’s what I was thinking to. I designed it backwards concentrating on the blocks and pieces when I should have been working with a boolean grid with pieces being just 4 sets of grid coordinates and a color.

    Pretty much this will require a complete rewrite – precious little of the code can be salvaged without major alterations. Still it should go much faster now that I know what I’m doing a bit better. :)

    Reply  |  Quote
  7. IceBrain PORTUGAL Mozilla Firefox Linux Terminalist says:

    @ Matthew Weathers:
    Another nice platform is LÖVE, for Lua. The framework comes with all the modules necessary for 2D games (graphics, audio, event handling, input, etc) and Lua is really nice as a language.
    It’s also licensed under zlib, so you can use it to make (as they say) “evil, closed-source commercial” games.

    http://love2d.org/

    Reply  |  Quote
  8. MrJones GERMANY Mozilla Firefox Windows says:

    @ IceBrain:

    Full of Ö’s pretty weird

    Reply  |  Quote

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>