C++ Programming Series: What’s next?

You wanted to get into game programming.

You found out that C++ is the real deal.

You came here and started reading the first post of the series.

You practiced and moved on till the end.

Now, you are confused what to do next?

(By the way, it applies to all the enthusiastic people who learned programming for the sake of making games.)

What you need to do now, is to google some simple C++ 2D Game Development Libraries.

Back in the days, SDL2 was my choice (I still use it a lot). SDL2 is pretty neat and it just clicked with me. But it does have drawbacks (for example, no easy-peasy shaders). If SDL2 is your choice, Lazy Foo’s SDL2 Tutorial Series is probably the best place for learning it. I also learned SDL2 from there.

People recommend SFML a lot. Even though I don’t use it, it won’t hurt you to try different libraries in the start and just go with what feels right.

Less features won’t hurt. But less personal compatibility will…

That is why I use SDL2. Even if there is not that something you need, you can craft your own hack to go through it.

Why not OpenGL library or just any library to make 3D games (like Call Of Duty and GTA)?

DON’T!

It’s impractical unless you got a thousand experienced people of all kinds working on it.

-_-

Why not a game engine like Unity for making 2D games?

Yeah, you can. In fact, it is awesome go and do it.

But you may consider this. They have a GUI, an editor and all fancy stuff that eases game development. And that makes your brain lazy and kinda limits your creativity.

I am not saying to built a game development career upon some C++ 2D Game Development Library (which honestly, won’t hurt). I am trying to imply the fact that doing code by hand and visualizing the game in the head will give you a much deeper understanding of what a video game is and how video game actually works.

And when you are satisfied with that experience, you can go with Unity like me.

How this deeper understanding thing works on a higher level?

It works. But you may not be able to see it working. Unconscious, maybe.

To see it in effect, just compare yourself with the one who went directly into Unity and you will realize yourself. You will be able to pick things faster than he would.

And please, take my words with a grain of salt.

So, that means I, as an individual, am stuck with 2D forever?

Hell no!

I recently started learning Blender (free, open-source 3D modelling and rigging software) and it seems like 3D is a viable option for any solo developer.

But yeah, as a solo game developer, no Call Of Duty or GTA forever. But awesome games like Gone Home and Inside are always a good option for any experienced artist and game developer.

In the end, I would like to say to make as many complete games as possible. With every completed game, your experience gets higher exponentially as compare to half-baked games.

Here is the summary:

Programming -> 2D in Game Library -> 2D in Game Engine -> 3D in Game Engine

What if I learned C++ for some other purpose?

Well, I don’t know the specifics but you can go for that purpose as hard as you can.

Sorry, I don’t have much advise on that, other than the fact that you shouldn’t go big on what ever the purpose is. Always try small and then, step towards bigger things.

Advertisements

C++ Programming Series: Dynamic Arrays (Part 2, Last)

Dynamic arrays can be used with functions in exactly the same way as I have told in this post. Just keep in mind that we have to pass the size of array into the function.

void printIntegerArray(int* pArr, int totalElements)
{
  for(int i = 0; i < totalElements; i++)
  {
    cout << pArr[i] << endl;
  }
}

int main()
{
  int* array = new int[5] { 3, 4, 7, 8, 12 };

  printIntegerArray(array, 5);

  return 0;
}

Note how I allocated the memory and also, set the value of all the elements in the dynamic array in the highlighted line.

That initialization of dynamic array is what the real purpose of this small post is. Why? Because dah! I learned that very late. Very very late.

At least, I am able to save others from this.

array[0] = 3;
array[1] = 4;
//...till the end :p

Also, there is another purpose of this post.

Tell me my mistake in the code.

If you already knew it before reaching this part, you must be a keen observer. There is no delete[] array; at the end of the code.

Damn those memory bees. (By the way, it is a genuine mistake)

This ends my C++ Programming Series. Now, to ease your path, there will be another post in this series. Keep coming back and you will always find bunch of useful stuff here.

C++ Programming Series: Dynamic Arrays (Part 1)

Before we get into the dynamic arrays, it is important to understand why we use them and when to use them.

Here’s the simplified concept of memory types.

The program that we execute stores and works with the data, information and variables (collectively called memory) in the RAM (Random Access Memory). Upon closing the program, it no longer remains there. Memory that remain saved even after a program is closed, is present in ROM (Read Only Memory). For example, the photos, text files and the program itself stored in the hard-drive.

Now, here’s the important bit. RAM is generally divided into two parts: Stack and Heap. Stack is the tiny amount of RAM that can be used by the program for quickly accessing the memory. When we make variables, the way we did in this series, we are saving this in it.

On the other hand, heap is the remaining big chuck of RAM that can be used by the program to work on large and uncertain amount of data.

The question that why this division exists? It is pretty straightforward. As stack is much smaller than heap, it is much faster to access the memory in stack than in heap. But stack has its limits as it is tiny in size which means that it is not supposed to have uncertain size of data and is not supposed to be holding onto something for indefinite period of time. Here comes into action, heap. Heap is there for that purpose: uncertain size of data and no time constraints.

There are multiple ways to store variables in heap. One of them is to simply define a variable above and outside the main function.

int iAmInHeap = 95;

int main()
{
  int iAmInStack = 5;

  return 0;
}

Functions outside the main function can be called global variables and they can be manipulated during execution from outside i.e they are not secure and it is not a good habit to make global variables.

At the ending curly bracket (i.e at the end of a block), the stack memory is destroyed and can not be used anymore. This is perhaps, what we call the scope of a variable. The very first post of this series might remind you what I meant here.

On the other hand, heap memory is destroyed only when you destroy it. But the variable it is stored in, is no longer accessible after the end of a block.

Alright, I have said so much. Now, let us get into the practical heap situation. To make a typical heap variable (that is not global variable), following is the code.

int main()
{
  int* typicalHeapVar = new int;
  *typicalHeapVar = 10;  

  delete typicalHeapVar;

  return 0;
}

Time to introduce a pair of keywords: new and delete. Before using dynamic arrays, always keep in mind that:

Where there is new, there is delete as well.

I have to use this kinda dramatic quote to remind myself of this very important thing. And that is because new allocates the memory and delete de-allocates the memory.

new without delete means memory leaks in the program. delete without new is not as bad because delete checks whether the pointer is NULL or not. So make a habit to set the pointer to NULL after deleting it.

But what about the practical heap situation? Lets say that we are making a program that blurs all the images in a folder. All the images! That is what uncertain size of data means.

We know that when we make an array, we can not use a variable to set the size of an array. Sure that we can have a limit to it like what I did below.

const int MAX_IMAGES = 100; //That is the limit of our program!

//Suppose that Image is a user defined structure.
Image images[MAX_IMAGES];

//We get the images from a folder with a function called getImagesFromFolder that gets all the images and saves them into the array of Image objects.
//It also returns the number of images present in that folder.
int noOfImages = getImagesFromFolder(images);

//Blur them all...
for(int i = 0; i < noOfImages; i++)
{
  //Suppose that... alright you get it already!
  blurImage(images[i]);
}

//Then, save them back...

You can point out 3 flaws with the program.

  • First one is that an image can be of any resolution and any size. Stack is used here to possibly store MB’s of image data. Not a good thing.
  • Second is again, the limit. What if the images are more than 100.
  • Third is the unnecessary use of memory. If the folder contains 10 images, there are still 90 useless array elements. It won’t effect the performance of the program but it will definitely shorten our already tiny stack.

Okay, maybe I am exaggerating. But it is to explain the benefits of using heap at such situations.

This is how it will look when we use dynamic arrays.

//No more limit variable

Image* images;

//First, we simply throw in a NULL pointer and get the total number of images in the folder.
int noOfImages = getImagesFromFolder(NULL);

//Then, we use this variable to tell us the amount of elements our array will have.
images = new Image[noOfImages];

//Then. we get the images from folder.
getImagesFromFolder(images);

//Blur them all...
for(int i = 0; i < noOfImages; i++)
{
  //Suppose that... alright you get it already!
  blurImage(images[i]);
}

//Then, save them back...

//WE MUST DESTROY WHAT IS CREATED...
delete[] images;

Now, you also know how to make dynamic arrays (not just typical heap variables).

My explanation maybe inaccurate and could have faults so, I suggest you to look around as well. As for the practical heap situation, I hope you got my point. The series is almost coming to an end.

Usually, people know all that. But they don’t know what is the right place to use them. I learned it the hard way. And I am still learning and prone to errors.

C++ Programming Series: Structures and Data Types

During that non-blogging time, I learned one thing: Always finish what you have started.

And so, here I am continuing my C++ Programming Series.

C++ got primitive data types like integers, floats and doubles. They are called primitive for a reason.

We can create our own data types by combining other data types. We can also include an array/pointer. For example:

struct Vehicle
{
  int tires;
  string color;
  int horsePower;
  float weight;
};

We have created a structure/data type called Vehicle. Note that string is not a primitive data type.

Now, using it is pretty simple.

First, you need to create an object out of it.

Vehicle car;
car.tires = 4;
car.color = "black";
car.horsePower = 1200;
car.weight = 804.6; //in kilograms

As you can tell, we created a definition and then, set the value of each component variable within our own defined type variable.

To access the components in our variable, we used full stop(dot) immediately after the name of it.

Why use structures when we can simply make variables and use them? When we make structures out of variables, it makes our code cleaner and easily to read. The more we make abstractions out of our variables, the more easier it is to work with the code and the more our code will have a high-level paradigm.

We can create functions to easily manipulate the structures. We don’t need to pass all components of the structure variable. Instead, we can simply pass the variable itself and then, open it inside the function. Example below:

void setVehicle( Vehicle& vehicle, int t, string c, int hp, float w )
{
  vehicle.tires = t;
  vehicle.color = c;
  vehicle.horsePower = hp;
  vehicle.weight = w;
}

When you look at our Vehicle data type, it is pretty basic and there is no practical use to it. But what if it is something like this:

struct Vehicle
{
  const int MAX_TIRES = 20;
  Tire tires[MAX_TIRES];
  Exterior exterior;
  Engine engine;
};

…where the Tire, Exterior and Engine are also some complex user-defined data types. Maybe, those are also simplified just like Vehicle and contain some other user-defined data types.

My point is that, things can get very simple if data structures are made and used within each other and they have separate functions for their manipulation as well.

I hope this is good enough to push you ahead into using structures efficiently.

C++ Programming Series: Pointers (Part 4, Last)

Too busy! Too busy! Don’t expect regular and weekly posts from me. I am studying medicine.

In the previous post, we discussed that pointers are actually arrays! This post is to discuss more about pointers, arrays and the arithmetic that can be done with them.

We can do addition and subtraction with pointers. Multiplication and division is not possible! Here is the code giving an example of pointer arithmetic (try to understand it deeply):

int array[] = {20, 30, 40, 50, 60};
int* pArray = array;

pArray++;
cout << *pArray << endl; //Prints 30, same as array[1]

pArray++;
cout << *pArray << endl; //Prints 40, same as array[2]

cout << pArray[2] << endl; //Prints 60, same as array[4]
//pArray[4] will give error or garbage value!

pArray -= 2;
cout << *pArray << endl; //Prints 20, same as array[0]

cout << pArray[4] << endl; //Prints 60. same as array[4]

When we increment a pointer of type int, the address is actually shifted by the number of bytes that an integer consists of. Similarly, when we increment a pointer of type string, the address is shifted 4 bytes forward. The opposite happens when we decrements a pointer.

Consider the code below:

string words[] = { "First", "Second", "Third", "Fourth", "Fifth" };

string* pWords = words;

Now, pWords is pointing towards the memory address of words[0] or “First”. If we add one into it:

pWords++; //or pWords += 1;

…then it will be shifted 4 bytes forwards to reach the next string of the array, words. Or in other words, pWords is now, equivalent to &words[1]. Now, if we subtract one from it, it will get to the same address as before.

C++ is a very flexible language. We can add the numbers into the pointer temporarily like pWords + 3. Now, if pWords is equivalent to &words[0], then pWords + 3 would give us the address equal to &words[3]. If we dereference this memory address, we will get the proper string value, “Fourth” like this:

string words[] = { "First", "Second", "Third", "Fourth", "Fifth" };
string* pWords = words;

//Adding temporarily for getting the memory address of the
//fourth element of array and dereferencing that memory
//address to get the value from there
cout << *(pWords + 3) << endl; //Prints "Fourth"

Isn’t that similar to that?

cout << pWords[3] << endl; //Prints "Fourth"

Yes, they are completely the same! What is happening with pWords[3] is the same as what is happening with *(pWords + 3).

That’s it! Your exercise is to find out what is the output of the code below (without checking it out in the compiler):

int array[] = { 1,2,3,4,5,6,7,8,9,10 };
int* pArray = array;

pArray += 5;
cout << pArray[3] << endl; //Output 1
pArray -= 3;
cout << pArray[4] << endl; //Output 2
pArray--;
cout << *pArray << endl; //Output 3
pArray + 2;
cout << *pArray << endl; //Output 4
pArray += 1;
cout << *(pArray + 1) << endl; //Output 5

That is all pointers for you. Congratulations! You learned the pointers! Time to step ahead…

C++ Programming Series: Pointers (Part 3)

Pointers and Arrays are same things!

This statement might confuse you. How is this possible that pointers and arrays are same? They never looks to be same!

This post will clear this point to you. Lets get started with the code below.

int array[5] = { 3, 4, 7, 8, 12 };

//Look! We have not put square brackets
//with a number after the name of array
cout << array << endl;

What will it print? Will it print the first member of the array? No, it will print the memory address of the first member of the array.

Now, you see that there is no ampersand(&) needed for getting the memory address of the array. Don’t you think that it is something that is similar to pointers? Yeah, but this is not all!

int array[5] = { 3, 4, 7, 8, 12 };

//'pArray' is now pointed to the first member of the 'array'
int* pArray = array;

//Now, we can use 'pArray' similar to that of 'array'
cout << pArray[2] << endl; //Prints 7; same as 'array[2]'

The above code explains that pointers are actually arrays! We can have square brackets with pointers and just use it exactly as an array.

Another point to tell you that when we use a pair of empty square brackets([]) after a pointer or an array, it will still give us the memory address of the array. But when we mention the number in it, pointer or array will give us that particular value under the index.

Pointers and arrays are same things but there is only one difference between them.

An array knows that how many elements it has. If we use sizeof() method for an array, we will get right number of bytes that it occupy.

int array[5] = { 3, 4, 7, 8, 12 };

//We can use empty square brackets as well
cout << sizeof(array[]) << endl; //Prints (sizeof(int) * 5)

Note: Size of integer may be different for your device. Mine is 4 so, it will result in 20. It may result 10 as well.

A pointer never knows that how many elements it has. It may or may not be an array as well. If we use sizeof() with pointer. we will not get the right number of bytes that it occupy. A pointer do know about the size of type that it is of.

int array[5] = { 3, 4, 7, 8, 12 };
int* pArray = array;

cout << sizeof(pArray[]) << endl; //Prints 2, 4 or 8 (not true in any case)

What if we want to pass array to a function? We have never discussed that topic before. Now, there is something that I have to tell! We can’t pass array to a function! So, there you go. The topic ends.

Of course, there is a solution to this problem. We can’t pass arrays but we can pass pointers to a function. Unfortunately, we can’t get the size of array that is passed as a pointer. Therefore, we have to pass the total number of elements to the function as well.

void printIntegerArray(int* pArr, int totalElements)
{
  for(int i = 0; i < totalElements; i++)
  {
    cout << pArr[i] << endl;
  }
}

int main()
{
  int array[5] = { 3, 4, 7, 8, 12 };

  //We don't need to make any pointer
  //Pointer is just a memory address
  //So, we can pass array directly
  printIntegerArray(array, 5);

  return 0;
}

Just keep in mind, the concept that pointers are arrays but they don’t keep track of their number of elements. There are few things that are not clear. We still don’t know what happens behind that pair of square brackets with a number in it. We will discuss pointer arithmetic in the next post along with the working behind square brackets.

Exercise: Make a function that takes an integer array and prints only even numbers.

C++ Programming Series: Pointers (Part 2)

In the previous post, we learned how to get the memory address of a variable and how to define a variable that holds the memory address i.e pointer.

Suppose that there is a variable of type int called number. We initialize it with value equals to 10. Now, suppose that it has a memory address 091 (Sounds ridiculous but it’s just a supposition). This memory address is present somewhere in our device’s memory.

Some of the memory addresses are shown in the table below, along with the values present in each.

Address 090 091 092 093 094 095
Value Garbage number number number number Garbage

Now, we know that number has a memory address 091. Then, why 092, 093 and 094 are also filled with value, number? Well, just think a little on why not 095? 095 is just a garbage value!

Okay, okay! Let me clear this confusion. number is of type int and the size of int is 4 bytes. Each memory address carries 1 byte. Therefore, to fit a variable of type int, it requires 4 neighboring memory addresses.

So, number is having memory addresses, 091, 092, 093 and 094. But the only memory address that is useful to us, is the first one i.e 091. Every variable only knows its first memory address and its size. When we know the first memory address of a variable, we can easily get the value of that variable.

Now, suppose that we have a pointer of type int called pNumber. We initialize it with the memory address of the number (How to get memory address of a variable? By putting ampersand(&) behind it).

Now, the pNumber is also 091. We dereference it (i.e we put an asterisk(*) behind the pNumber) to get the value 10.

Actually, when we dereference the pointer, we are actually, looking up the memory address which in this case, is 091. Pointer of type int will suggest that whatever is present in this memory address will be the starting byte of the variable which is of type int.

Please read the above statement twice! It is a bit tricky!

To make it easy, here’s the same table:

Address 090 091 092 093 094 095
Value Garbage number —–> pNumber number number number Garbage

After looking up the memory address, pointer takes the value which in this case, is 10.

If you try sizeof() for pointer of any type, it will tell you that the size of pointer is 8 bytes (or may be different depending on your device). This is because a pointer consists memory address and memory address is a hexadecimal value. Hexadecimal values are big values! Therefore, every pointer resembles to type long int which is also 8 bytes in size.

We can manipulate with the pointers as well. We will discuss it in the upcoming posts in detail. For now, just get along with pointers and the concept described above. It should not be hard now! There is still a huge ground to cover regarding pointers…