I have made the game Tetris using a PIC16F84 running @ 12MHz. Tetris is an old Russian computer game where you should try to fit in block into a play-field, quite simple but really fun. All blocks are built from four bricks (the name Tetris is derived from the ancient greek word for four: “tetra”), there are seven combinations of the four bricks as seen here to the left. This version is using my PIC Game System as platform, generating a video signal in software. The only hardware used for the video generation is two resistors forming a 2-bit DA converter. Usually the video signal is generated in video games is created with a dedicated video chips, reading the image data from a graphics memory. In this project the video signal is calculated in real-time by the microprocessor as the electron beam sweeps over the screen. This page only describes the software, you can find schematics and description of the hardware here and for your service I also sell the parts for building the system if you want to make sure you get the correct stuff, don’t have a programmer or can’t make PCBs yourself.
How to play the game.
When the power is turned on the game starts! (was no memory left for a fancy intro screen or similar). The score is shown in the bottom right corner, and the next block to come is shown in the upper left corner of the screen. See picture of the game in action here to the left. As the blocks fall down, they can be moved sideways by using the joystick (left gameport on hardware), the fall speed can temporary be increased by moving joystick down. The fire-button is used to rotate the blocks. When one horizontal line is full, then it is removed. You get points for full lines and placed blocks. As you get more points the difficult level is increased by increased block falling speed. The musics speed is increased as the game speed increases. You get game over when the playfield level has reached to the top and there is not room for more blocks.
With a processor performing 3MIPS, it is not easy to make a video signal in software. Each instruction performed takes 1/3 us. Each scan-line on the screen takes 64us, where 52us are visible, so it gives 52*3=156 visible clock cycles per line. Maximum resolution that can be obtained is 156 pixels in x-axis if the software is setting one pixel per clock (using for example only bcf and bsf), but more is needed to make a game, like loops and such. A loop quantifies the time to 3-clock pieces, giving a resolution of 52 pixels. (One could obtain a kind of 156pixels resolution with one or two offset nops, but the code to select this would eat to many clock cycles to do any good). However Tetris is quite simple, the resoluton is quite low, and there is no motion, the blocks of pixels are just turned on and off. The most demanding part of the game is to show the score at the bottom of the screen, it is shown in the bottom of the screen. It obtains higher resolution by loading the PORTB with the bitmap for the number and shift it out one pixel per clock cycle.
So far I’ve only talked about the graphic generation. But there is more to it to get a video signal. All scan-lines first have a 4us-sync pulse, then black for 8us, then the 52us graphic comes. These horizontal sync-pulses makes the TV understand when a scan-line starts, but there is needed to send information about when a new picture starts too, it is called vertical sync, and is a special pattern that tells the TV that a new image is coming. There are two kinds of vertical sync, because the image is divided into two part images, showing even and odd lines, to get less flickering. In Tetris, the two images are identical, so the game is not using the full y-resolution possible, but it doesn’t matter because it is way better than the x-resolution anyway, making the x-resolution the biggest problem.
The game-field is kept in memory as a 32byte array, 16×16 bits, where one bit is one pixel-block on the screen. The area to the upper left is for showing the next block, and by making it a part of the game field it is possible to use the same block-drawing routines as for the game, and thereby saving memory. Each frame, the falling block is first removed from the game-field, and then tests are performed if the block can move, as the player wants it to. Then the block is drawn back to the screen at the new position. When a block is to be tested, put or removed, it first must be generated. To generate a block means compressing it from the compressed data, rotating it and then store the relative coordinates of the block in the block array. The block data is compressed in relative coordinates. In compressed format, each coordinate is stored in two bits for both x and y, where the two bits can represent the numbers –1,0,1,2. These values need to be uncompressed to 4*2 byte sized values representing the coordinates in two’s complement format. Depending of the angle the block should have, the coordinates might need to be mirrored or/and swapped. When the block have been created it can easily be put, removed or tested. The test routine checks if there is any pixels set on the block positions where the block should be put. If pixels are set, then the block can’t be put there. New blocks are selected at random, where the random number is a counter that increases for every frame, making the random number dependent of how long it takes for the player to place the block, making a quite good random number.
For more detail: PIC-Tetris
Current Project / Post can also be found using:
- tetris vga com pic
- pic tetris
- pic16f886 tetris vga
- pic18f tetris vga