Home
2D Game Tutorials
Arcade Game   Tutorials
Miscellaneous   Tutorials
Code Dump
Forum
Links







Falling Blocks Part 1: Introduction

What this tutorial covers

  • The creation of a Tetris clone
  • Collision detection
  • Victory and losing conditions
  • Moving 2D objects
  • Using user-defined objects in a game project
  • Storing multiple images in a single file

Introduction

Welcome to this series' first actual game tutorial! By the end of this tutorial you'll know how to write a full featured Tetris clone. Before you start, you might want to familiarize yourself with the std::vector. It's essentially just an array with added features. I've written a very brief tutorial that can be found here that will teach you all you need to know right now about the std::vector.

Note that this tutorial, as well as the other tutorials in this series, all build off of the Introduction tutorial. If you haven't read it yet, you should do it now.

Setting Up

The first thing we need to do is start a new project called "Falling Blocks" and copy in "Main.cpp" and "Defines.h" from the Introduction tutorial.

Also remember to copy "SDL.dll", "SDL_ttf.dll", and "ARIAL.TTF" into you project directory and set Project->Falling Blocks Properties->C/C++->Code Generation->Runtime Library to Multi-threaded DLL (/MD).

You'll also need the bitmap for this tutorial, which can be found in the downloadable source code. See the table of contents for a link to the downloadable source code.

The Code

Before we begin there's one thing I need to make clear. When I say "block", I mean the actual objects in our game. These are usually called "Tetrinos" but that name's probably copyrighted. When I say "square", I mean the individual squares that make up our Tetrin...er...blocks.

Defines.h

There are some changes and additions we need to make to "Defines.h". First, our window dimensions are way to big. We also need to change our window caption. Make the following changes to "Defines.h":

#define WINDOW_WIDTH   300
#define WINDOW_HEIGHT  400
#define WINDOW_CAPTION "Falling Blocks"

Now we need to add some new values to "Defines.h". If you run the executable that comes with the downloadable source code, you'll see that the game area does not take up the entire screen. We'll need to know the location and dimensions of our game area within our window, so let's add the following to "Defines.h":

#define GAME_AREA_LEFT   53
#define GAME_AREA_RIGHT  251
#define GAME_AREA_BOTTOM 298

We want there to be a finite amount of levels in our game, so we'll define that here. We'll keep all of the values that are dependent on the number of levels in our game in "Defines.h". This way we only have to change a couple of values in "Defines.h" to add more levels.

In Tetris, everytime you clear a line of squares you get points. If you reach a certain number of points, you advance to the next level. Every time you advance to the next level, the blocks start moving down faster. We'll define the speed of the blocks in moves/frames so if the block is moving down every 60 frames, and we're running our game at 30 frames per second, our blocks will move down every two seconds. Add the following to "Defines.h":

#define NUM_LEVELS       5    // number of levels in the game
#define POINTS_PER_LINE  525  // points player receives for completing a line
#define POINTS_PER_LEVEL 6300 // points player needs to advance a level

#define INITIAL_SPEED 60  // initial interval at which focus block moves down
#define SPEED_CHANGE  10  // the above interval is reduced by this much each level

When the current block (we'll call it the "focus block") reaches the bottom of the game area, the player should be given a brief moment in which to slide it left or right. This works great when the focus block hits another block and the player quickly slides it into a better place. We'll define the amount of time the player gets to slide the focus block here.

The main purpose of our game is to fill rows of squares in order to clear them and receive points. We'll need to define the number of squares that can fit in a row. We'll use this value later when we determine which rows are full of squares.

When we specify the locations of our squares within the game area, we'll be using our squares' centers. For this reason, we need to record the distance from the center of a square to its sides. This value will be used for getting the locations of the sides of our squares as well as for determining if two blocks are touching.

Add the following to "Defines.h":

#define SLIDE_TIME      15
#define SQUARES_PER_ROW 10  // number of squares that fit in a row
#define SQUARE_MEDIAN   10  // distance from the center of a square to its sides

The rest of our defines involve locations within our game area and our bitmap. We need to define the starting point for our blocks, and where to display the current score, level, required score, and next block in line. Add the following to "Defines.h":

// Starting position of the focus block
#define BLOCK_START_X 151
#define BLOCK_START_Y  59

// Location on game screen for displaying...
#define LEVEL_RECT_X        42   // current level
#define LEVEL_RECT_Y        320
#define SCORE_RECT_X        42   // current score
#define SCORE_RECT_Y        340
#define NEEDED_SCORE_RECT_X 42   // score needed for next level
#define NEEDED_SCORE_RECT_Y 360
#define NEXT_BLOCK_CIRCLE_X 214  // next block in line to be focus block
#define NEXT_BLOCK_CIRCLE_Y 347

In most games, each image is not actually stored in a separate file. Games generally cram as much information into as few files as possible. Because there isn't much to our game, we can easily store all of our images in a single file. To make this work, we need to define the locations within our bitmap of the game's background screens and squares. Add the following to "Defines.h":

// Locations within bitmap of background screens
#define LEVEL_ONE_X   0
#define LEVEL_ONE_Y   0
#define LEVEL_TWO_X   300
#define LEVEL_TWO_Y   0
#define LEVEL_THREE_X 300
#define LEVEL_THREE_Y 0
#define LEVEL_FOUR_X  0
#define LEVEL_FOUR_Y  396
#define LEVEL_FIVE_X  300
#define LEVEL_FIVE_Y  396

// Location within bitmap of colored squares
#define RED_SQUARE_X    600
#define RED_SQUARE_Y    400
#define PURPLE_SQUARE_X 620
#define PURPLE_SQUARE_Y 400
#define GREY_SQUARE_X   640
#define GREY_SQUARE_Y   400
#define BLUE_SQUARE_X   660
#define BLUE_SQUARE_Y   400
#define GREEN_SQUARE_X  680
#define GREEN_SQUARE_Y  400
#define BLACK_SQUARE_X  700
#define BLACK_SQUARE_Y  400
#define YELLOW_SQUARE_X 720
#define YELLOW_SQUARE_Y 400

Enums.h

A new file we'll be adding to our project is "Enums.h". This is a fairly simple file and could probably be fit into one of our other files but I like to keep things organized in separate files.

We only need two enumerations for this project. The first will be used for the types of blocks in our game. We enumerate our block types so we can generate random numbers to determine what block to add to our game next. The second will be used for directions. Blocks can be moved left, right, or down.

Add the following to "Enums.h":

#pragma once

enum BlockType
{
    SQUARE_BLOCK,
    T_BLOCK,
    L_BLOCK,
    BACKWARDS_L_BLOCK,
    STRAIGHT_BLOCK,
    S_BLOCK,
    BACKWARDS_S_BLOCK
};

enum Direction
{
    LEFT,
    RIGHT,
    DOWN
};

Falling Blocks Part 2: cSquare and cBlock

 

This site is © Copyright Aaron Cox 2004-2005, All Rights Reserved.
Website templates