Game Development Tutorial

Everything a total beginner needs for game programing!

21. Time for a coffe break

Ok, we programmed almost everything that I wanted to see in our gameplay. But this tutorial is far from over. You remember the game screenshot from the first chapter? Our game doesn't look anything like that... In the next few chapters we'll add some practical functions to our game, like 'Pause' button, 'High Score' list, and then we'll move on to the decoration!

Almos every game has a 'Pause' button. It's almost normal that you can't play any game without interuption. Maybe your wife sends you to the store to fetch some ingredients for lunch, or your two-year-old starts pulling the mouse out of your hand, or something else comes in your way... In every case, you don't want your game to go on... So, to satisfy our players, we'll add a pause button. Well, not actualy add - we'll just use our existing 'New Game' button, and programatically make it a multifunctional 'gadget'.
Ok, now, we'll update our code to give our game/pause button the funcionality that it needs. Basically, we'll just stop our timer when the user clicks on the button, and start it again when the user clicks 'Continue'. We won't add a new button for the 'Continue' command. We'll use our current 'Pause' button to do this...

Here's the code:
(overwrite your existing 'GameButton_Click' code!)

if (butGame == "New Game")
{
  //NEW GAME
  picGameField.Show();
  picGameField.Refresh();
  NewGame();
  butGame.Text = "Pause";
}
else if (butGame.Text == "Pause")
{
  //GAME PAUSED
  Game.Stop();
  picGameField.Visible = false;
  lblDisplay.Text = "Game Paused";
  lblDisplay.Visible = true;
  butGame.Text = "Continue";
}
else
{
  //CONTINUE GAME
  picGameField.Show();
  butGame.Text =
"Pause";
  picGameField.Visible = true;
  Game.Start();
  butNG.Visible = false;
}


You probably noticed that we hide the game field when the player clickes 'Pause'. That's because we don't want our players to cheat, and have extra time to plan their moves... Wicked, right? ;)

Now, add another button to the game, and apply it's properties:

Button

  • (name): butNG
  • Location: 276; 6
  • Size: 126; 53
  • Text: New Game

This one is going to offer our player the possibility to start a new game. Let's add some code to it. Double click on the new button, and put this code there:

//NEW GAME
picGameField.Show();
picGameField.Refresh();
NewGame();
butGame.Text = "Pause";
butNG.Visible = false;

 

Ok, let's go on - in the next chapter we'll add a High Scores list to our game. Just so our players can brag about their achievements, and to give them a little bit of motivation for playing the game (if they don't hold the #1 spot on the list!). :)

20. How about a raise?

To make things a little interesting, we'll give the player bonuses after he completes each level. I've thought of two bonuses: One that is awarded for empty columns, and one that is awarded on top, if there are no blocks left on the game field. To calculate the 'Empty Column Bonus' I used this formula: Level * # of Empty Columns * 100. For the second bonus, I used this formula: Level * 1000. So, If a player manages to clear all block in level 4, he would recieve (4*15*100) 6000 points from the Empty Column Bonus, and additional (4*1000) points from the Cleared Level Bonus. That's 10000 points! Nice! To show the player how many points he was awarded, we'll use our existing label (lblDisplay). And we'll pause the game for a few seconds between the levels. In the end, we'll create a method to switch us between levels. Ok, enough talking.

Let's start coding!This is the code that goes into the LevelScore() method:

// A variable for holding
// TEMPORARY empty column
// bonus:

int iColBonus = 0;
//Stop the game play...
Game.Stop();
// Calculate the bonus 
// for empty columns


// Go trough all columns:
for (int c = 0; c < iWidth; c++)
{
  // If the column is empty, 
  // increase empty column
  // bonus. The column is
  // empty whene there's no
  // block in the lowest field.
  // (Since we have gravity)

  if (Field[iHeight - 1, c] == 0)
  {
    // You can play with this
    // code to adjust how many
    // points are awarded for
    // every empty column:

    iColBonus += (100 * iLevel);
  }
}

// Add the empty column
// bonus to the total
// score, and show it:

iScore += iColBonus;
lblScore.Text = iScore.ToString();

// Calculate the bonus for
// cleared level :)
// (Mission impossible)

// Temporary variable:

int iLvlClrBonus = 0;
if (iColBonus ==
iWidth * (100 * iLevel))
{
  // Code that defines
  // and shows the bonus:

  iLvlClrBonus = iLevel * 1000;
  iScore += iLvlClrBonus;
  lblScore.Text = iScore.ToString();
}

// Inform the user that 
// the level is over.

lblDisplay.Text = "Level Complete!";
lblDisplay.Visible = true;
this.Refresh();

// Show bonuses, 
// if they exist:

if (iColBonus > 0)
{
 
// Pause 2 seconds:
  System.Threading.Thread.Sleep(2000);
  // Display first bonus:
  lblDisplay.Text = "Empty Column Bonus: "
  + iColBonus.ToString();
  this.Refresh();
}

if (iLvlClrBonus > 0)
{
  // Pause 2 seconds:
  System.Threading.Thread.Sleep(2000);
  // Display second bonus:
  lblDisplay.Text = "Clear Level Bonus: "
  + iLvlClrBonus.ToString();
  this.Refresh();
}

// Pause 2 seconds:
System.Threading.Thread.Sleep(2000);
// Reset the display
// label, and hide it.

lblDisplay.Visible = false;
lblDisplay.Text =
"GAME OVER!";

So, let's move to the next chapter and see how we can play with the parameters of our gameplay to make things more interesting.

Update: I finally managed to sort out the feed for this site. (Before, the feed for this site was copyed from my other blog... uh...)

19. How to get a promotion

Almost all games have levels. As the player advances, the game becomes more and more difficult. We'll do just that. We'll speed up our gameplay from level to level, and add a new color to the blocks every three or four levels... That should spice things up nicely... Uh! Oh! Another idea: let's increase the number of columns from level to level! So, that would mean that the player needs to survive 15 columns in the first level to move on, 16 in the second, and so on... Our game will not have a finall level. If the player is skilled enough, he could play trough an infinite number of levels. But hey, that's almost impossible. Reaching level 10 will be almost like winning in a lottery ;) Hehe...

So, when the player starts a new game we should reset the level count, score, speed, colors.. So we'll fill our 'NewGame' method.

// Reset the level and
// score value, and the
// number of colors in the game:

iLevel = 0;
lblLevel.Text = iLevel.ToString();
iScore = 0;
lblScore.Text = iScore.ToString();
iColor = 3;
iColors = 0;

// Reset the game speed
Game.Interval = 4000;

// We don't have the IOBox yet,
// so, the next line is commented
// out:
// IOBox.Visible = false;

lblDisplay.Visible = false;

NewLevel();

Now, add a new label to the form. Here are the settings:

Label

  • (name): lblLevel
  • BackgroundColor: Web > Transparent
  • Location: 555;81
  • Font: Microsoft Sans Serif; 9,75pt; style=Bold
  • Text:1

And here's the code for going from level to level.
(Put it in the NewLevel() method)

//Increase the level number.
iLevel++;

// Increase the number of 
// columns needed to complete
// the level. You can play
// with this code to make the
// game harder or easier.

iColumns = iWidth - 1 + iLevel;

// Reset the column count.
iColumn = 0;

// Increase the number of colors.
// But only to 10. (because we
// didn't prepare more colours in
// our DrawField method)

if (iColor < 10)
{
  // Do it every three levels...
  // The number '3' in the next 
  // line tells the game how
  // many levels to skip before
  // adding a new color:

  if (iColors == 3)
  {
    iColor++;
    iColors = 0;
  }
  else
  {
    iColors++;
  }
}

// Speed up the game.
// We speed it up for 50 
// miliseconds from level
// to level. This, probably,
// will stay unnoticed by
// the player. But you can
// change this to increase
// the difficulty.

if(iLevel > 1 &&
Game.Interval > 1500)
{
Game.Interval =
Game.Interval - 50;
}

// Display level text
lblLevel.Text =
iLevel.ToString();

// Create our new level's
// game field (empty):

CreateField();
// And the first column:
CreateNewColumn();

// Show it on the screen:
Redraw();

// Start the game:
Game.Start();

And the last thing is to change your 'New Game' button's code to this:

NewGame()

In the next chapter, we'll add some nice bonuses, that'll show between levels, and give the player to 'breathe' for a second or two... Ok, moving on!

18. Keeping score

Every game has a way to put a value to the player's effort. In racing games that's done with time (in most cases). In tycoon games, that would be done with money. In our game, we'll just use numbers. So how should we evaluate our players effort? First of all, we have to give him points for every block he destroys. We could make our game give him more points with every new level, and some extra points for the number of different block colors for that level. And some extra scoring math: We could make every block color more valuable... So, let's start with adding a new label to our form, so we could display the score to the player.

The score label properties:

Label

  • (name): lblScore
  • BackgroundColor: Web > Transparent
  • Location: 555;65
  • Font: Microsoft Sans Serif; 9,75pt; style=Bold
  • Text: 0

Then, add this code to your project:
(put it in the DoTheScoreMath() method.)

// We'll process the score only
// if there's multiple blocks
// in the 'Connected List'.

if (ConnectedList.Count > 1)
{
  // I've declared some
  // variables to hold
  // some values I intend
  // on using to calculate
  // the score.

  int a = ConnectedList.Count;
  int b = iLevel;
  int c = iColor;
  int d = ConnectedList[0].iFieldColor;

  // Scoring formula...
  // You can play with it
  // as you like :)

  int e = a * (b + c) * d;
  
  // Just don't forget to
  // add it to the total
  // score:

  iScore += e;
}
// Oh, and to be a little
// naughty, we'll substract
// a point for every click
// the user makes...
// BUAHAAHAAHHAAAAA!

iScore--;

// Display the total score:
lblScore.Text = iScore.ToString();

Now, add the call in the 'picGF_MouseClick' method, after the existing code:

DoTheScoreMath()

Done? Cool! Ok, what now? Levels would be cool... Right, then! Next chapter: Levels!

17. To help, or not to help

So, our game is almost playable… Well, it is, but there's a lot of stuff to add… Like, random blocks appearing on the game field. The game I 'borrowed' the idea from, had these blocks apearing at radnom time intervals and random places on the game field… And those fields were cool, because, sometimes, they helped to clear you some additional blocks, and sometimes, they filled that valuable empty columns… Ok, back to the drawing board. Litteraly. Here are two examples, first one that shows when the block is helpful, and another one wich shows when it's not that helpful.

Take a look at the picture. The player has only two empty columns left. Let's think about the next situaion:  

a) Let's imagine that in this moment, our game 'spawns' a red field at [4,5]. That would help the player, since he would be able to clear that red field, and the field one block to the right. (the one under [5,4]). The result would be - three empty columns.

b) If we would spawn a blue field at [4,5] - that wouldn't affect the player a lot - he would clear the field, and the blue one on the left. The result would be the same: Two empty columns.
 
c) If we wolud spawn a green field at that location, that would be the worst case scenario for the player. He would be stuck with only one empty column.
 
Looking at the Field[5,4], the best thing for the player would be, if we created a red block there. In that case, he could empty the #5 column. Spawning a green block wouldn't make a big difference. When the columns would be moved to the right, the green fields could be cleared. Creating a blue field there would be the worst thing for the player, but that wouldn't mean any disadvantages for him. The empty column count would stay the same.

So, the code for creating a 'random' block:(Put it in the DropBlock() method)

// Once again, we'll use the
// random function. We'll
// generate a random color,
// and a random position for
// our new block.

Random Rndm = new Random();

// Increasing the random range
// decreases the chance to drop
// the block.

int R = Rndm.Next(1, 3);

switch (R)
{
  case 1:
    // Drop the block!
    // Generate the position:

    int RX = Rndm.Next(iHeight - 1);
    int RY = Rndm.Next(iWidth - 2);

    // We dont allow the new block to
    // spawn in the last column - so
    // we don't cause possible gameover's ;)


    // We have to see if the field is empty...
    // So we don't overwrite some other field.
    // This also affects the possibility
    // of creating a random block...

    if (Field[RX, RY] == 0)
    {
      // Fill the block with a random
      // color;

      Field[RX, RY] =
      Rndm.Next(1, iColor + 1);
      // Make it fall down...
      GoGravity();
    }
    break;

    default:
      break;

 
In the next chapter, we'll make a score method, so we can let the player know how succesful he was...

16. Thing that makes apples fall

Uhm, I admit – I lost a whole day to figure this stupid stuff out. And in the end, i ended up with just a few lines of code. It's true that simplicity is the best way. And after writing, like, fifty lines of code that didn't work, i decided to delete it, and to start over. Basically, I took every single block in the game, and checked if it's floating. If it was, I moved it down… This would be the result:

This is the code that goes in the GoGravity() method:

// So, bassicaly, i just use 
// a couple of loops to go trough 
// all the fields.


// Looping through columns:
for (int s = 0; s < iWidth; s++)
{
  // Looping through rows:
  for (int l = 0; l < iHeight; l++)
  {
    for (int v = iHeight - 1; v > 0; v--)
    {
      // In every column, I start  
      // checking from the bottom.

      if (Field[v, s] == 0)
      {
        // If the field is empty, I  
        // drop the field above it 
        // down one block.

        Field[v, s] = Field[v - 1, s];
        Field[v - 1, s] = 0;
      }
    }
  }
}
// And to show the changes, 
// I call the Redraw() method:

Redraw();


And this is the code that goes into the Redraw() method:

//Drawing our field and grid:
DrawGrid()
DrawField()


15. Destroying the blocks

Like I said, this is going to be pretty straight-forward chapter. To destroy the blocks, all we need to do is set their value to 0. And, since we have a list of blocks to destroy, we'll just use a simple FOR loop. The only thing we have to check is that the list contains more than one field. If not, the user clicked on a field that is not connected to any fields of the same color. Nothing fancy here. Here's the code (put it in your DestroyBlocks() method!):

// First, we'll check if the
// List contains more than
// one block. If it does, we
// destroy all the fields in
// it by setting their value
// to 0.

if (ConnectedList.Count > 1)
{
  for (int d = 0;
  d < ConnectedList.Count;
  d++)
  {
    Field[ConnectedList[d].iXcoordinate,
    ConnectedList[d].iYcoordinate] = 0;
  }
}

Simple, right? So, if you remember the picture from the last chapter – here's how that field would look now, after destroying the selected blocks:

In the next chapter, we'll create some gravity. Gravity will force all those floating blocks to fall down. See the floating blocks? (Hint: Field[0,0], Field[0,1] and Field[1,0]). And after that, our game will be almost playable. When we finish gravity, we'll start working on different 'bonus' stuff, levels (like promissed), scoring (and high score lists), design and graphics, and a little 'Drop Block' feature wich will randomly create a single block somewhere in our game field… So, click on, and discover the secrets of Gravity!

14. Connections make the world spin

So, to explain what we need to do – I've drawn an image:

Let's say that the player clicks on the Field[1,1]. Our game should detect that the [1,1] field is connected to two more blue fields (Field[2,1] and Field[2,0]). In our game, the rule will be that fields are connected horizontal and vertical, but not diagonal. How do we do this? First of all, we'll create a list of connected fields. We'll put in the field user clicked. And then, we'll check fields above it, below, to the right and to the left to see if they hold the same (color) value. If they do, we'll put them too in our list. And then we'll go trough our list, field by field, searching for connections for every field in our list. If we find any connections, we'll check if they are already in the list. If no, we'll add them. Sounds complicated. Even I can't understand what I just wrote. :o) I'll try to write this as a step by step list:


  1. Player clicks Field[1,1]
  2. We add Filed[1,1] to our list
  3. We check the field above it (Field[0,1]) to see if it's the same color. Since it's not, we ignore it.
  4. We check the field below if (Field[2,1]) to see if it's the same color. It is, so we add it to the list.
  5. We check the field on the left (Field[1,0]) – it's not the same color, so we ignore it.
  6. We check the field on the right (Field[1,2]) – it's not the same color, so we, once again, ignore it.
  7. We move to the next item (Field[2,1]) in our list, and repeat the steps for it…
  8. We check the field above it (Field[1,1]), but we ignore it since it's already in our list…
  9. Eventualy we find the Field[2,0], add it to our list, and that's it…

So, how does this look like, code wise? First we'll have to declare our list, and then create a couple of methods for checking connections: A method that goes up, down, left and right, another one that cheks if the field is already in our list, and another one that makes sure that we check connections for every field from the list. There's one new thing here, thoug – structs. Think of them as some sort of containers that can hold a lot of different variables… So, first declare our struct. Put the declaration on top of the code, where you have your other public declarations.

// Struct for our  connected
// fields.
struct stField
{
public int iFieldColor;
public int iXcoordinate;
public int iYcoordinate;
}

And then declare the list to hold the connected fields:

// List of our connected fields.
List<stField> ConnectedList =
new
List<stField>();

Right. Now, check the code - the method & function declarations are a little different... So, be careful :)

private void CheckConnected
(int Xpos, int Ypos, bool bClick)
{
// This is the struct that will hold the
// Connected field position and value.

stField stField = new stField();
stField.iFieldColor = Field[Xpos, Ypos];
stField.iXcoordinate = Xpos;
stField.iYcoordinate = Ypos;

// bClick actualy means that the field
// was clicked on by player, so we add
// it to the list automatically.

if (bClick == true)
{
// So, we add the field to our list,
// we check if it's already in the list,
// and we add it if not. This isn't
// necesary here, since logic thinking
// tells us that the list is empty at
// this point. But, just to be safe...

if (CheckIfInList
(stField.iXcoordinate, 
stField.iYcoordinate) ==
false)
{
ConnectedList.Add(stField);
}
}

//Checks fields up and down from 
//the desired field.

if (stField.iXcoordinate > 0)
{
if (Field[stField.iXcoordinate - 1,
stField.iYcoordinate] == 
Field[stField.iXcoordinate, 
stField.iYcoordinate])
{
// Field above has the same value(color).
// We add it to the list.

stField.iXcoordinate = 
stField.iXcoordinate - 1;
if (CheckIfInList(stField.iXcoordinate,
stField.iYcoordinate) == false)
{
ConnectedList.Add(stField);
}
stField.iXcoordinate = 
stField.iXcoordinate + 1;
}
}

if (stField.iXcoordinate < iHeight - 1)
{
if (Field[stField.iXcoordinate + 1,
stField.iYcoordinate] == 
Field[stField.iXcoordinate, 
stField.iYcoordinate])
{
// Field below has the same value(color).
// We add it to the list.

stField.iXcoordinate = 
stField.iXcoordinate + 1;
if (CheckIfInList(stField.iXcoordinate,
stField.iYcoordinate) == false)
{
ConnectedList.Add(stField);
}
stField.iXcoordinate = 
stField.iXcoordinate - 1;
}
}

//Checks fields left and right
//from the desired field.

if (stField.iYcoordinate > 0)
{
if (Field[stField.iXcoordinate,
stField.iYcoordinate - 1] ==
Field[stField.iXcoordinate,
stField.iYcoordinate])
{
// Field to the left has the same
// value(color). We add it to the list.

stField.iYcoordinate = 
stField.iYcoordinate - 1;
if (CheckIfInList(stField.iXcoordinate, 
stField.iYcoordinate) == false)
{
ConnectedList.Add(stField);
}
stField.iYcoordinate = 
stField.iYcoordinate + 1;
}
}

if (stField.iYcoordinate < iWidth - 1)
{
if (Field[stField.iXcoordinate, 
stField.iYcoordinate + 1] ==
Field[stField.iXcoordinate,
stField.iYcoordinate])
{
// Field to the right has the same 
// value(color). We add it to the list.

stField.iYcoordinate = 
stField.iYcoordinate + 1;
if (CheckIfInList(stField.iXcoordinate, 
stField.iYcoordinate) == false)
{
ConnectedList.Add(stField);
}
stField.iYcoordinate = 
stField.iYcoordinate - 1;
}
}
}

private void CheckAll()
{
// This method goes trough the list,
// and re-checks connections for
// every field in it.

if (ConnectedList.Count > 1)
{
for (int l = 0; l < 
ConnectedList.Count; l++)
{
CheckConnected
(ConnectedList[l].iXcoordinate,
ConnectedList[l].iYcoordinate, 
false);
}
}
}

private bool CheckIfInList
(int PXpos, int PYpos)
{
// This function checks if the
// field is in the list or not.
// If the field is in the list,
// the function returns boolean
// 'TRUE'. If not, it returns
// boolean 'FALSE'.


for (int l = 0; 
l < ConnectedList.Count; l++)
{
if (ConnectedList[l].iXcoordinate 
== PXpos && ConnectedList[l].iYcoordinate
== PYpos)
{
// The field is in the list:
return true;
}
}
// The field is not in the list:
return false;
}


Right. Hope this works… So, now we know what the user clicked. And if there are more than one blocks connected, we should destroy them. That's going to be easy. After destroying the blocks, we'll have to make the gravity. So we don't wind up with floating blocks… Moving on…

13. Chasing the mouse

In our game, we'll use the mouse as an input device. Player will be able to click anywhere in the game field, and we'll have to figure out if he clicked a block, or an empty field. If the player clicks on the block, we'll have to check if it's connected with any other block of the same color, and we'll have to destroy the blocks if so. And to add a little feature, we'll take away one point for every mouse click. (Wich reminds me… We'll have to make a score counter, real soon.) So, how the hell can we find out where the user clicked? Lucky for us, the Picture Box in wich we draw our game field, has a MouseClick event. So, we'll use it to see if the user clicked anywhere on the game field. But how to find out on what block the user clicked? A little basic math will help us solve this problem. We already have defined that the block field is 32 pixels in width/height. And lucky for us, VS.net can give us the coordinates of the mouse pointer on the screen, and in relation to the clicked object. That means, that VS will give us the distance from the top and left borders of the picture box, measured in pixels. So, those are the ingreedients. Let's mix them all together and see how they work. First of all, go to your design window, select the Picture Box, and then, go to your Properties window. Just above the properties list ther is a little icon of lightning. Click on it, and you'll see the events list. Find the MouseClick event, and double-click on it's name. This should give you the code editor window with the method already in place. Here's the code for it:

// We find the X and the Y coordinate of 
// the mouse using the mouse event arguments
// (called 'e'). We'll store them into some 
// variables. Note, how we switched X and Y's 
// place – that's because we declared our game
// field in the opposite way – X for height 
// and Y for width. I know… Goofy…

int mx = e.Location.Y;
int my = e.Location.X;

// The next step is to divide the mouse 
// coordinates with the block/field size,
// so we'll get the coordinates of our field.

decimal x = mx / iFieldSize;
decimal y = my / iFieldSize;

/ And to round them up (since they came 
// back as numbers with decimals) we 
// convert them right back into intigers.
// Not to mention that we need them as 
// integers, to define our fields.

int ix = (int)x;
int iy = (int)y;

This code will give you exact coordinates of the block player clicked. Ok, what's next? Obviously, we'll have to see if the block player clicked, is actualy connected to other blocks of the same color. And we'll do just that – in the next chapter.

12. NOOOOO! Game Over!?

This chapter will be a short one. When the game detects that conditions for GameOver are met, we basicaly have to stop the game play, and let the user know it's over. This would be a good time to process the score, and see if the player made it to the hall of fame… I know, I know… We don't have a High Score list. Not yet! We'll come to it somewere near the end of this tutorial. So, I'll just put the code for the GameOver() method here, so we could move on to another fun part of the tutorial – Chasing the mouse over the field.

// First, we stop the game play
// by stopping the Game timer.

Game.Enabled = false;

// Then we display the Game Over
// message.

lblDisplay.Visible = true;


I hope you didn't try to run your program yet. I forgot to tell you: You need another label on your form. So, back to the design view, add a label, and adjust it to meet these specifications:

Label

  • (name): lblDisplay
  • Autosize: False
  • BackColor: Web > Transparent
  • Font: Arial Black; 27,75pt; style=Bold
  • Forecolor: Web > Red
  • Location: 12; 388
  • Size: 600; 52
  • Text: GAME OVER!
  • TextAlign: TopCenter
  • Visible: False

Right. Now we're ready to test our game. It should show the 'Game Over' message when the game field fills with columns. Here's a screenshot of how the game should look at this stage: (Huh, notice that I forgot to select the 'Show Grid' check box)

Next:
Heeeeereeee mousey! Heeere mousey… I'll catch you this time… Just wait and see… ;o) 

11. Move it! Mooove it!

This is the fun part. We have to move every column to the right. So, the idea is this: Player starts every new level with an empty game field. Before we give him a new column, we check if there's any space on the game field. If there's no space – it's Game Over! We try to push all of the columns one space to the right. We don't move empty columns. Oh, well, let me draw it:

So, this picture shows 15 columns. The white ones are empty. Colored ones contain at least one block. So, in this case, before we create and insert a new column, we have to move the green columns one space to the right. The blue and yellow columns will not be affected this time. Ok, one more:

The red column is the one we created after we moved the green columns to the right. In this example, before we could create a new column, we would have to moove all six columns to the right (I mean, blue ones, green ones, and the red one). And the finall product would look something like this (note, that the yellow columns were, once again, not moved):

I hope you get the idea now. To do this in our game, we'll have to look for the left-most empty column, and them move all preceeding columns one space right. To check if a column is empty, we'll just check the bottom block, since we'll add some gravity to the game at a later stage – meaning, no block could 'fly'. Ok, onto the code:

// Declare an integer that will hold
// the empty column number. We set it's
// value to –1, wich means there is NO
// empty columns. If we find an empty 
// column, we'll change this value. We
// didn't use 0 to show that there's no 
// empty columns, because 0 actualy refers 
// to the FIRST column in our game field.

int iEmptyColumn = -1;

// Using a FOR loop to go trough all 
// columns looking for an empty block.

for (int s = 0; s < iWidth; s++)
  // Checking if the block is empty:
  if (Field[iHeight - 1, s] == 0)
  {

    // We found the empty block. Write
    // the column number into our
    // integer variable.
   
iEmptyColumn = s;
    // Exit the loop, we don't need to
    // look any longer, since we already
    // found an empty column:
    break;
  }
}

if (iEmptyColumn == -1)
{

  // So, if there's no empty columns,
  // we can't create any new ones, so
  // we'll call the game over method.
  GameOver();
}
else
{

  // If we found an empty column, move all
  // preeceding columns for one space to the
  // right. We use two loops in this code
  // because we have to move all blocks in
  // the column (height wise), and all the
  // collumns preeceding the empty one).
  for (int x = iEmptyColumn; x > 0; x--)
  {
    for (int v = 0; v <>
    {
      Field[v, x] = Field[v, x - 1];
      Field[v, x - 1] = 0;
    }
  }
  // So, we moved our field, we can now
  // create a new column...

  CreateNewColumn();
  // ...and add a random block
  // (you'll see...) :)
  DropBlock();
  return;
}

What a progress! One of the last things is to put this stuff into our Timer's Tick event. Find the code for the game_tick event, and put this line there:

MoveRight();

Oh, yea, remove the line that we placed there earlier. (The one that called CreateNewColumn() method.) We don't need it, because now, we call the CreateNewColumn() method from our new MoveRight() method. In the next chapter we'll create the GameOver() method. And after that, we'll move to do some user (player) interaction stuff. I guess we'll be chasing the mouse all over the field… ;-P LOL, that's funny.

Try it out! You should see something like this:

10. Timing is crutial

We've made it to a break-point in our game's development. In this chapter we'll automate our game, so it will create new columns every second. And after that, we'll make our existing colums move to the right. We'll also check, if the conditions for Game Over, or New Level are met. The first step in this part is to add a timer to the form. You can find it in your ToolBox, under the 'Components' section. And when you double-click it, it won't be placed to the form. It will be placed in a new toolbar under your Form Designer window. Here's a screenshot:

So, click the timer in the components toolbar, and set it's properties like shown in the next table:

Timer

  • (name): Game
  • Interval: 1000

Obviously, the timer has a 'Interval' property. That tells the timer the 'lenght' of the pauses between repeating all of the commands writen in it's Tick method. The interval is defined in miliseconds. That means, if you want your timer to repeat it's code every second, you'll have to enter '1000' in it's interval property. And if you want it to repeat it's code every two and a half seconds – enter 2500. And so on, and so on, and … ;o)

So, now, we have the timer set – let's try it out. Double click on it in your components toolbar, and you'll see the code for it's Tick method. Add next lines of code in it's method:

// Call to our function responsible
// for creating new columns:

CreateNewColumn();
// Call our two 'draw' functions...
// So we can see when the new
// columns are created.

DrawField();
DrawGrid();

Ok, that'll do the trick. But, we have to tell our timer when to start 'ticking', and we'll do this with our 'New Game' button. So, go to the code for your button, and add this line of code after the existing lines:

// Telling our game timer to
// start ticking:

Game.Start();

Oh, and before moving on, remove, or comment out (check your C# toolbar for a button that does that) the code wich we used to test our field:
 
Field[0,0] = 1;
Field[4,8] = 2;
Field[2,12] = 3;
Field[9,14] = 4;

Don't worry, we don't need that code any more. Our blocks will be filled automaticaly, frow now on. Cool, heh? But wait untill you see this stuff in action! :o) Run your game, click on the button and enjoy the fireworks! Here's what you should see after 15 seconds (and after 15 column changes):

Moooooving on! As promised, we'll move all existing colums to the right. But that's the story from our next chapter.

9. Our first gameplay stuff

One of the rules of our gameplay is the one saying that the game sends in new columns of blocks from the left. And it does so until the player runs out of empty columns… We'll divide this into three basic steps. And later on, we'll add a timer to our game. A timer will make sure that a new column will be created every time at a specified interval. These are the steps for our basic gameplay:

  1. Create new column with random colors
  2. Move existing columns to the right to make some room for the new column
  3. If we can't move any columns – Game Over!
  4. If the player cleared a certain ammount of columns – move him to a new level

And to make this work we'll declare some more variables – like the number of different colors allowed in the new column. By increasing this number, the game becomes more difficult to play. And one other way to make the game more difficult to play is by shortening the time interval between new column creation. The third way to make our game harder is to increase the number of columns needed to be cleared in a level. Later on, we'll incorporate all this stuff in our game. So, our game will become more and more difficult – from level to level.

Back to the code – here's what we need to add to our declarations:

// Declare the number of different colors
// that are used in the current level.
// We'll set it to 4 - for now:

int iColor = 4;
// Declare the counter that we'll use
// for changing colors every X levels.

int iColors;

// Declare the  integer that will hold
// the number of columns created  in
// the current level:

int iColumn;// Declare the integer that will hold
// the total number of columns in
// the current level.

int iColumns;

Add these lines of code right under the Game Field Height, Width, and Field Size declarations. Before moving on, we have to add a label to our form. So, add a label to the form, and then set it's properties like shown in the next list:

Label

  • (name): lblColumn
  • BackgroundColor: Web > Transparent
  • Location: 555; 97
  • Font: Microsoft Sans Serif; 9,75pt; style=Bold
  • Text: 0/0

Finally, the code that will create our new column. Put it in your CreateNewColumn() function.

if (iColumn < iColumns)
{
 
// Initializing the random function.
 
// It will come up with random  
  // numbers every time we call it.

 
Random Rnd = new Random();

 
// We have to create 10 new fields.
  // (Our column is 10 fields high.)

  for
(int p = 0; p < iHeight; p++)
  {
   
// We set the random function in
    // a way, so it couldn't return
    // a value larger than we declared
    // it in the beginning, and it
    // couldn't return 0 (wich means –
    // empty field).
    Field[p, 0] = Rnd.Next(1, iColor + 1);
  }

 
// Increase the number of columns created
  iColumn++;
  // Display the column count in the new
  // label on our form.

  lblColumn.Text = iColumn.ToString() +
  "/" + iColumns.ToString();
}
else
{
  // The level is over when the number
  // of columns created in the current

  // level is equal to the total number
  // of columns predicted for that level.
  // When the level is over, we call our
  // methods for counting bonus points
  // and switching to a new level.

  LevelScore();
  NewLevel();
}


That's it for this chapter. In the next one, we'll add a timer to our game, and add some code to make it create new colums every second. We'll also start talking about moving all existing colums to the right.

Downloads

Downloads
Finished Bubble Splash Game

Followers

Translate

Blog Directories

Programming Blogs - BlogCatalog Blog Directory
blog directory
Software Computers Business Directory - BTS Local
Top Blogs GoLedy.com
TopOfBlogs DigNow.net
Blog Directory blog search directory
Top Computers blogs Add to Technorati Favorites
Computers Blogs Blog Directory
blogsbycategory.com Blog Directory & Search engine
Blog Flux Directory Programming Blog Directory
Join My Community at MyBloglog! BlogRankers.com
Technology Blogs - Blog Rankings Blog Directory
C# Game programming tutorial Blogs lists and reviews
Bloglisting.net - The internets fastest growing blog directory Blog Directory - photarium
blogarama - the blog directory Blog Toplist
Blog directory Computers (Linux) - TOP.ORG
Blog Ratings si.blogs
Blogz game, development, programming, c#, visual studio, tutorial, source code
On our way to 1,000,000 rss feeds - millionrss.com
RSSMountain
TopBlogLists.com - Blog Search