65
C++ Basic Lessons Why C++? C++ is a simple yet powerful Object Oriented programming language. It has almost all the same uses as C, but brings a few new features to the table, along with simpler code. One of the new features is a data type called class, which is used to create objects. Objects will allow you to write your code in a more organized fashion, instead of having data scattered about. This makes it much easier for the different functions throughout your program to access the data they need in order to get the job done. This way the amount of code you have to write is reduced significantly, thus making your program easier to maintain. Where to start First thing you will need is a compiler. A compiler basically takes the code you write and translates it into a form the computer will understand so that it can be executed. I used Dev-C++ for the examples you will find throughout this site, although the code should work with most compilers. Dev-C++ can be found on Bloodshed's site . Lets Begin Now that you have your compiler, lets move on to actually learning how to code C++. If you are using Dev-C++, the first thing you are going to want to do once you open it is select "File" > "New" > "Project. Then select "Console Application" and name your project. Once finished you will be presented with a small program, simply erase this so we can begin! Our first program will simply send "Hello World!" to the screen, here is the code: //My first program #include <iostream> using namespace std; int main(){ cout << "Hello World!\n";

Game Programing (C++) unknown aouther

Embed Size (px)

Citation preview

Page 1: Game Programing (C++) unknown aouther

C++ Basic Lessons Why C++?

C++ is a simple yet powerful Object Oriented programming language. It has almost all the same uses as C, but brings a few new features to the table, along with simpler code. One of the new features is a data type called class, which is used to create objects. Objects will allow you to write your code in a more organized fashion, instead of having data scattered about. This makes it much easier for the different functions throughout your program to access the data they need in order to get the job done. This way the amount of code you have to write is reduced significantly, thus making your program easier to maintain.

Where to start First thing you will need is a compiler. A compiler basically takes the code you write and translates it into a form the computer will understand so that it can be executed. I used Dev-C++ for the examples you will find throughout this site, although the code should work with most compilers. Dev-C++ can be found on Bloodshed's site.

Lets Begin Now that you have your compiler, lets move on to actually learning how to code C++. If you are using Dev-C++, the first thing you are going to want to do once you open it is select "File" > "New" > "Project. Then select "Console Application" and name your project. Once finished you will be presented with a small program, simply erase this so we can begin! Our first program will simply send "Hello World!" to the screen, here is the code:

//My first program

#include <iostream>

using namespace std;

int main(){

cout << "Hello World!\n";

system("Pause");

}

Now lets break this down. The first line "//My first program" is a comment, the compiler will ignore this line completely. To add comments to your program, simply begin the line with "//" and anything after that will be ignored.

The first line of actuall code tells the compiler that we want to include "iostream" in our program. iostream is part of the standard library, all C++ compilers will understand any command included in any part of the standard library. iostream contains the basic I/O functions used to write to the screen and recieve input from the user.

Page 2: Game Programing (C++) unknown aouther

The next line "using namespace std;" defines what namespace we will be using, in this case std. A namespace is basically a list of variable and function names, in order to not get standard library names mixed with others, the standard library creates the namespace std, so any time you want to use a command from the standard library you must include this line. The semicolon at the end of the line is needed for almost every line in C++, this tells the compiler that it has reached the end of that line.

"int main(){" this is a function decleration. A function is a block of code which begins and ends with a pair of curly brackets " { } ". This way we have a way of referencing this block of code in case if we want the program to run the same code multipule times. Functions also help keep the code looking clean. "int" is the data type the function returns, we will discuss data types later. "main" is the name of this function, every C++ program must have a main() function, this is where the program will begin to execute. If you want to pass a variable to a function, you would place the type of variable and specify a name for it between the parenthesis, for example "int myFunction( int number)". The curly braket shows where the function begins.

"cout << "Hello World!\n";" This line displays the text "Hello World!" on the screen. cout takes the text using "<<" which is known as an insertion operator. Think of it as a funnel, we want the data, in this case "Hello World!", to be "funneled" into cout. The "\n" means new line, its like pressing the enter key while typing in a text editor.

"system("Pause");" system() is used to send commands to the operating system, in this case we are sending "pause" which is a DOS command which pauses the screen until the user presses any key. I included this because once the program runs out of code to execute, it will close the window and you will not get a chance to see the results.

Ok now lets see it in action, type the code into Dev-C++, do not copy and paste it. You can copy and paste if you want, it will work just fine, but it will help you memorize the code quicker if you type it yourself. Once done, save it and press the compile button, once it finished press the run button. You should be presented with a DOS prompt which will give you this output:

Hello World! Press any key to continue...

Too easy isn't it? Lets move on to data types.

Data types So far you've seen how to display whatever you put into your program, now lets see how to get input from the user. Before doing this we need somewhere to store the data the user gives us, this is where the different data types come in. Here is a list of the basics data types:

int: used to store integers (whole numbers, no decimals/fractions)long: used to store larger integersdouble: used to store numbers with two decimal places

Page 3: Game Programing (C++) unknown aouther

float: used to store numbers with multiple decimal placeschar: used to store a single character

Ok now lets see these in action:

#include <iostream>

using namespace std;

int a;

int main(){

int b;int c;

cout << "Enter a number: ";cin >> a;

cout << "Enter a second number: ";cin >> b;

c = a+b;

cout << "The sum is: " << c << "\n";

system("pause");

}

Here I declared three integers, a, b, and c. Notice how "a" is outside of main()? In this case, a would be known as a global variable, all functions can access it freely, but since b and c were declared inside of main() it is only accessible to main().

The next new line would be "cin << a+b;". Here we see the insertion operator again, except this time its pointing in the other direction. Since cin is the command for input, we want to "funnel" the data from the function to the variable.

After collecting the information from the user we use it to give c a value. "c = a+b;" give c the value of the sum of a and b, you can also use - for subtraction, * for multiplication, and / for division.

Finally we display the value of c, notice how there are two insertion operators in the final output? This allows us to display text and variables in one line instead of having to write "cout" several times. Notice how text is written in between quotes and variables are without quotes. If you wanted to assign a variable a number you would not use quotes either ( int a = 10; ).

Arrays In the last lesson we saw how to create simple variables and store user input in them. Now we will look into arrays. An array is simply a list of variables of the same type. Lets say your program required you to keep track of 100 integers, in which case you would

Page 4: Game Programing (C++) unknown aouther

have to create 100 integers by typing up each one, one by one... Needless to say that would take quite a while, but with arrays you can cut the typing down to one single line! Lets see how it works:

#include <iostream>

using namespace std;

int main(){

int myArray[3];

cout << "Enter a number: ";cin >> myArray[0];

cout << "Enter a second number: ";cin >> myArray[1];

myArray[2] = myArray[0]+myArray[1];

cout << "The sum is: " << myArray[2];

system("pause");

}

Here we have the same sample program from the previous lesson, except I replaced the three integers with a single array made up of three integers. "int myArray[3];" creates an array of three integers. Each integer inside this array will have a corresponding number, starting at 0. So in this case the three integers are myArray[0], myArray[1], and myArray[2]. Since 0 counts, there is not myArray[3]! Everything else is exactly the same.

You can also use arrays to store a string of text by creating an array of characters. Here you would make the array the max size of characters you want plus one, since strings must end the null character (null mean nothing, not 0, just nothing). We will look more into strings in a latter lesson though.

Two Dimensional Arrays 2D arrays work just like normal arrays except they have two numbers per variable. In order to declare one you would add an extra pair of brackets (int my2dArray[3][3]). Here is a graphical representation of a 2D array:

XXXXXXXXX

These will come in handy when you are programming graphics and animations, lets see an example program:

#include <iostream>

using namespace std;

Page 5: Game Programing (C++) unknown aouther

int main(){

int myArray[10][10];for (int i = 0; i <= 9; ++i){

for (int t = 0; t <=9; ++t){

myArray[i][t] = i+t; //This will give each element a value

}

}

for (int i = 0; i <= 9; ++i){

for (int t = 0; t <=9; ++t){

cout << myArray[i][t];

}

}

system("pause");

}

Ignore the for loops for now, we will look into those in the loops lesson. This program simply assigns a value to each element in myArray and then displays each one. As you can see there is not much difference between using normal arrays and 2d arrays.

If-Then-Else Now we will look into how to get our programs to compare values. A conditional statement checks to see if the conditions you are looking for are met or not, if they are they will execute a certain block of code, if not they will keep on. Here is an example:

#include <iostream>

using namespace std;

int main(){

int a;int b;

cout << "Enter a value for a: ";cin >> a;

cout << "Enter a value for b: ";cin >> b;

if (a > b){

Page 6: Game Programing (C++) unknown aouther

cout << a << "Is greater than" << b;

} else if(a < b){

cout << a << "Is less than" << b;

} else {

cout << a << "Is equal to" << b;

}

}

Here we see what is known as an if-then-else statemnt. I basically reads "If a is greater than b execute this code" if it is not greater it will move on, if it is true it will execute what ever you place in between its curly brackets and continue ignoring any line that begins with else after it. If it is false, the program will check the next condition "else if(a < b){" which basically reads "If the condition above is false and a is less than b execute this code". Finally, if that one proves false as well the program will go to the final "else" which has no conditions so will always be executed if the above conditions were false. Here are a list of the condition you can chck for:

== : equality, must use two equal signs< : less than> : greater than<=: less than or equal to>= : greater than or equal to!= : not equal

You can also check for more than one condition with a single if by using && (for and) and || (for or). For example:

if( a == 1 && b != 2) // will return true if a has a value of 1 and b does not have a value of 2

if( a == 1 || b != 2) // will return true if a has a value of 1 or if b does not equal 2

Switch Case The switch case works much like a lot of if-then-else statements put together. It takes one value and compares it against many others. Here is an examle:

#include <iostream>

using namespace std;

int main(){

Page 7: Game Programing (C++) unknown aouther

int a;

cout << "What time of day is it?\n";cout << "1) Morning\n";cout << "2) Afternoon\n";cout << "3) Evening\n";cout << "Enter a choice: ";cin >> a;

switch (a){

case 1:cout << "Good Morning!";break;

case 2:cout << "Good Afternoon!";break;

case 3:cout << "Good Evening!";break;

default:cout << "Not a valid entry...";break;

}

}

Notice how after each case, there is a colon not a semicolon. The last command in each case must be "break;" if not it will continue to execute any code following it. "break;" can be used to break out of any conditional statement or loop. "default" is included incase the user eneters an invalid entry, when ever the variable doesnt match any case, the default block is executed.

Strings A string is an array of characters. In order to get text from a user you must use a string. Strings work a bit different from other arrays though, here we will look into the different funcitons used for strings. Here is an example:

#include <iostream>

using namespace std;

int main(){

char myArray[50];

cout << "Whats the password? ";

cin.getline( myArray, 50, '\n');

if( !strcmp( myArray, "cheesecake")){

Page 8: Game Programing (C++) unknown aouther

strcat( myArray, " is correct! Access granted!\n");

} else {

strcpy( myArray, "Invalid password!\n");

}

cout << myArray;

system("pause");

}

Here we begin by declaring a string of 50 characters. The first line with a new function would be "cin.getline( myArray, 50, '\n');", the first parameter getline() takes is the string you want to store the data in, next is the max amount of characters allowed, and finally what you want the string to be terminated with.

"if( !strcmp( myArray, "cheesecake")){" will check if myArray is equal to cheesecake. Notice how I used the Not operator here, this is because strcmp returns false if the condition is met. Also remember strcmp() is case sensitive!

"strcat( myArray, " is correct! Access granted!\n");" This will add " is correct! Access granted!\n" to the end of myArray, you can also place another string in place of the text in order to join two strings.

"strcpy( myArray, "Invalid password!\n");" This will replace myArray with "Invalid password!\n". Whatever was in myArray will be wiped out and replaced by the text.

While Loop Loops are used to loop back and execute the same block of code over and over again until a certain condition is met. Heres an example using the while loop:

#include <iostream>

using namespace std;

int main(){

int a;

cout << "How many times do you want the loop to run? ";cin >> a;

while (a){cout << a << "\n";--a;

}

Page 9: Game Programing (C++) unknown aouther

return 0;

}

This code takes a value from the user and runs a while loop that many times. The conditions used for the while loop are the same as the if-then-else statements, same goes for every loop. Here since I only put "a" the program will read "While a is true execute this block" and as long as a is a positive integer it is considered to be 'true'.

For Loop The for loop works a little bit differently. Instead of taking just one parameter, it takes three. The first is the variable you want to use, you can either use an existing one, or declare one within the for loop. The second parameter is the condition, and the third is used to change the value of the variable chosen in the first parameter. Lets look at the code from the Arrays lesson:

#include <iostream>

using namespace std;

int main(){

int myArray[10][10];for (int i = 0; i <= 9; ++i){

for (int t = 0; t <=9; ++t){

myArray[i][t] = i+t; //This will give each element a value

}

}

for (int i = 0; i <= 9; ++i){

for (int t = 0; t <=9; ++t){

cout << myArray[i][t];

}

}

system("pause");

}

Here the first for loop defines i as an integer with a value of 0. Since the array is 10x10 and 0 counts when counting the elements of an array, we will run the loop until i is equal or greater than 9. "++i" means "add 1 to i", it can be used with any numeric data type. Since the array is two dimensional we will need a second for loop to get the second index number. This is setup the exact same way, except I used a t instead of an i. So now every time the first for loop runs, the second will run 10 times, and then return to the first until the first has been run 10 times thus covering every element in the array.

Page 10: Game Programing (C++) unknown aouther

Functions Functions are used to define a block of code, unlike the loops we discussed earlier, functions can be called from any place in your program so that you do not have to repeat the same code over and over again. Here is a basic function at work:

#include <iostream>

using namespace std;

int addNumbers( int a, int b){

return a+b;

}

int main(){

int a;int b;

cout << "Enter a number: ";cin >> a;

cout << "Enter an other number: ";cin >> b;

cout << "Sum of the two numbers is: " << addNumbers( a, b) << "\n";

system("pause");

return 0;

}

Here we create a function called addNumbers, which returns an integer. main() collects the data from the user and then sends it to addNumbers(), notice how I declared the integers in both main() and addNumbers. This is because the ones in main() are local variables which cannot be touched by other functions. The parameters for addNumbers() does not have to be the same as the variables containing the values being sent to addNumbers(). Once addNumbers() is called, it takes the values given to it by main() and returns the sum of them to the function that called it, which in this case is main(). Also notice how addNumbers() goes before main(). If you flip them around it will error out. If a function is being called by a function that apears before it in your source file, it must be declared at before it is called. Here is an example of this:

#include <iostream>

using namespace std;

int addNumbers( int a, int b);

int main(){

int a;

Page 11: Game Programing (C++) unknown aouther

int b;

cout << "Enter a number: ";cin >> a;

cout << "Enter an other number: ";cin >> b;

cout << "Sum of the two numbers is: " << addNumbers( a, b);

system("pause");

return 0;

}

int addNumbers( int a, int b){

return a+b;

}

File I/O File input and output is extremely simple in C++ compared to C. It works just like reading and writting to standard I/O. In order to use the C++ functions needed to accomplish file I/O you must include the header file . Here is an example:

#include <iostream>#include <fstream>

using namespace std;

int main(){

ofstream outputFile("file.txt"); //ofstream will create the file if it doesn't exist, ifstream will not

ifstream inputFile;

char myString[50];

cout << "Enter a string: ";cin.getline( myString, 50, '\n');

cout << "Writting string to file...\n";

outputFile << myString;

outputFile.close();

inputFile.open("file.txt");

cout << "Reading string from file...\n";

inputFile.getline(myString, 50, '\n');

Page 12: Game Programing (C++) unknown aouther

cout << myString;

system("pause");

return 0;

}

Here are two new data types, ofstream and ifstream. When a program open a file it asigns it a number called a handle in order to keep track of it, this is what is assigned to the ofstream and ifstream type variables every time you open a file. As you see there are two was of opening a file, at the declaration, "ofstream outputFile("file.txt");", and anywhere else by using open(), "inputFile.open("test.txt");".

Output works just like cout, and input works exactly like cin! Notice how I used getline() with inputFile and it worked exactly like it would with cin.

If a file is opened from an ifstream and the file does not exist, it will not create the file. Ofstream will create a non-existant file, but will also wipe out its contents. What if you wanted ifstream to create the file, and ofstream not to? Or have ofstream add to a file rather than delete it? Heres how:

#include <iostream>#include <fstream>

using namespace std;

int main(){

ofstream outputFile("file.txt", ios::app); //ofstream will append to file

ifstream inputFile;

char myString[50];

cout << "Enter a string: ";cin.getline( myString, 50, '\n');

cout << "Writting string to file...\n";

outputFile << myString;

outputFile.close();

inputFile.open("file.txt");

cout << "Reading string from file...\n";

inputFile.getline(myString, 50, '\n');

Page 13: Game Programing (C++) unknown aouther

cout << myString;

system("pause");

return 0;

}

Here we have the same program from before, except we are now adding on to file.txt. Here are other options for files:

ios::app - Apendios::trunc - wipe out fileios::ate - Set position at end of file

Classes Now for the object oriented programming. Classes are used to create object which can be given different properties and functions just like real life objects making them easier to work with than just a bunch of lose variables. Heres an example:

#include <iostream>

using namespace std;

class dog{

public:

dog();~dog();int getAge();void setAge(int a);

protected:int age;

};

dog::dog(){

}

dog::~dog(){

}

int dog::getAge(){

return age;

Page 14: Game Programing (C++) unknown aouther

}

void dog::setAge(int a){

age = a;}

int main(){

dog myDog;

myDog.setAge(5);

cout << "The dog is " << myDog.getAge() << " years old!\n";

system("pause");

return 0;

}

Here I started by creating a class called "dog". After the class declaration I definded some variables and functions as public and others protected. Public means any function can access them, protected ones can only be called from inside the class. Classes have two special functions called the constructor ( dog() ) and the deconstructor (~dog() ) which are called when an instance of the class is created and destroyed respectively.

"dog myDog" creates an instance of dog called myDog, myDog would be the actuall object modelled after the dog class. In order to run a function inside a class you must use the name of the instance followed by a "." and the name of the function (myDog.setAge()). The same goes for any public variables you may have declared.

Array of Classes A class by itself, such as the Dog class from the "Classes" tutorial, is quite useless. To make good use of such a class for video game programming purposes we need to be able to group several of them, this way we can minimize code when it comes to controling several objects at a time. This can be done by creating an Array of the object just like you would with any other data type. I will be splitting this programming up into several files as well, this will help keep things organized once your programs get bigger. Heres the example code:

//Dog.h#ifndef DOG_H#define DOG_H 1

class Dog{

public:

Dog();int getAge();

Page 15: Game Programing (C++) unknown aouther

void setAge(int newValue);

protected:int age;

};

#endif

This is the header file for the Dog class, it simply holds the prototype for the class, the actual code will be in a seperate file, Dog.cpp. The "#ifndef DOG_H" line is used to make sure Dog isnt declared twice.

//Dog.cpp#include "Dog.h"

Dog::Dog(){

}

int Dog::getAge(){

return age;

}

void Dog::setAge(int newValue){

age = newValue;

}

Dog.cpp first includes its header file in order to have the prototype for the class, the code here should be familiar from the last lesson. //main.cpp#include <iostream>#include "Dog.h"

using namespace std;

int main(){ Dog myDogs[5]; for (int i = 0; i <= 4; i++) myDogs[i].setAge( i * 2); for (int i = 0; i <= 4; i++) cout << "Dog number " << i << " is " << myDogs[i].getAge() << " years old!\n"; delete [] myDogs; return 0;

Page 16: Game Programing (C++) unknown aouther

}

main.cpp holds the code for the actual program. It only needs to include the header file for the class, not the actuall code file (Dog.cpp). Dog myDogs[5]; simply creates an array of 5 Dogs, just like using any other built in data type.

In order to access each individual Dog, simply include its index number in the brackets, and use it as you would any normal class. This example simply sets their age and displays it.

Multi-threading So far we've seen how to make games using a while loop that gives each process its own turn, lets look into getting the game to run all these steps at once. Here is some example code:

#include <iostream>#include <process.h>

using namespace std;

void myFunction( void* number){ int myNumber = *(int*)number;

cout << "This is prcosses number: " << myNumber << "\n"; _endthread();

}

int main(int argc, char *argv[]){ int tempNum[10];

for( int i = 0; i <= 9; i++){ tempNum[i] = i; _beginthread( myFunction, 0, (void*)&tempNum[i]); } system("PAUSE"); return 0;}

The new commands introduced here are _beginthread() and _endthread(), both included in process.h. _beginthread() takes 3 parameters, first is the function you want to run, in this case myFuntion, second is the size of the stack (just set this to 0), and third, any parameter you want to send. If no parameters are to be sent, the function still must accept a void* parameter, when actually calling _beginthread() set the last parameter to 0. For example: void myFunction( void* dummy){

.... code here

Page 17: Game Programing (C++) unknown aouther

....

}

_beginthread( myFunction, 0, 0);

Notice the way the parameter is sent, its converted from what ever type it orginally was to void*, this allows any data type to be sent using this function. Also make sure to place the '&' infront of the variable, this will pass the memory address the variable points to instead of the value.

In the function being called by _beginthread() you need to convert any parameters (unless if there are none) back to their original data type. Just replace the int in "*(int*)number;" to whatever datatype you need, and you can continue using the information as usual.

_endthread() will terminate the thread, its not necessary to use it since it will automatically be called once the function called by _beginthread() ends.

Each thread doesn't actually run at the exact same time, processor time will be divided up between the functions, since it happens so fast, it just seems as if they were all running at the same time. When running this code, if the output is not in order, dont worry. Its simply because one or more of the processes were not able to get their output written to screen before the next process starting writting its own.

Page 18: Game Programing (C++) unknown aouther

Allegro LessonsAllegro Basics

Here I will show you the very basics of programming with the Allegro Game Library. First of all, you will need to download and install Allegro. This can be a bit of a pain on Windows. Luckily, if you are using Dev-C++, you will be able to find a link to a file which will install allegro for Dev-C++ with a few clicks of the mouse! You can find it at the bottom of the download section in the Allegro website. If you are not using Dev-C++, please refer to the documentation provided on the Allegro site for installation instructions. Also be sure to install Allegro version 4.1.18, even though it is still 'Developmental', it is required for some of the examples on this site.

Now that that's out the way, lets get down to business! Open a new project in Dev-C++, be sure to pick "Windows Application". Now click on "Project" in the menu bar then "Project Options". Choose "Parameters" then click "Add Library or Object", set this to "C:\Dev-Cpp\lib\liballeg.a". This will let the compiler know where to find the Allegro functions. Here a simple Allegro program:

#include <allegro.h>

int main(){ allegro_init(); install_keyboard(); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); readkey(); return 0; } END_OF_MAIN();

This program will change the screen resolution to 640x480 and then wait for the user to press a key and then exit. Lets break down the code.

The first difference you will notice from the basic C++ lessons and these is that we no longer need to include iostream, allegro includes all the functions we will need for now. In order to startup Allegro we have to run the allegro_init() function, it does not require any information on your part, just remember to have this line before you start using any Allegro functions in your program!

install_keyboard() prepares Allegro to take user input from the keyboard, I will get more in depth with the Allegro input functions in a later lesson. set_gfx_mode() changes the screen resolution, it takes five parameters. The first should always be set to "GFX_AUTODETECT". The next two will be the size of the viewable screen. The last two are used for programs that require even more space, but that is a whole other lesson.

Page 19: Game Programing (C++) unknown aouther

Allegro Input/Output The last lesson's example was pretty useless, but important, lets add on to that now. Here is some example code:

#include <allegro.h>

int x = 10;int y = 10;

int main(){ allegro_init(); install_keyboard(); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); while ( !key[KEY_ESC] ){ clear_keybuf(); acquire_screen(); textout_ex( screen, font, " ", x, y, makecol( 0, 0, 0), makecol( 0, 0, 0) ); if (key[KEY_UP]) --y; else if (key[KEY_DOWN]) ++y; else if (key[KEY_RIGHT]) ++x; else if (key[KEY_LEFT]) --x;

textout_ex( screen, font, "@", x, y, makecol( 255, 0, 0), makecol( 0, 0, 0) ); release_screen(); rest(50);

} return 0; } END_OF_MAIN();

This program will write a "@" to the screen and move it around when the user presses the up, down, left, or right arrows. The first new line here, while( !key[KEY_ESC] ){. key[] is an array of flags which are set to true when a specific key is pressed. In order to test for a certain key just place one of the following codes within the brackets. KEY_A - KEY_Z, KEY_0 - KEY_9, KEY_0_PAD - KEY_9_PAD, KEY_F1 - KEY_F12,

KEY_ESC, KEY_TILDE, KEY_MINUS, KEY_EQUALS, KEY_BACKSPACE, KEY_TAB, KEY_OPENBRACE, KEY_CLOSEBRACE, KEY_ENTER, KEY_COLON, KEY_QUOTE, KEY_BACKSLASH,

Page 20: Game Programing (C++) unknown aouther

KEY_BACKSLASH2, KEY_COMMA, KEY_STOP, KEY_SLASH, KEY_SPACE,

KEY_INSERT, KEY_DEL, KEY_HOME, KEY_END, KEY_PGUP, KEY_PGDN, KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN,

KEY_SLASH_PAD, KEY_ASTERISK, KEY_MINUS_PAD, KEY_PLUS_PAD, KEY_DEL_PAD, KEY_ENTER_PAD,

KEY_PRTSCR, KEY_PAUSE,

KEY_ABNT_C1, KEY_YEN, KEY_KANA, KEY_CONVERT, KEY_NOCONVERT, KEY_AT, KEY_CIRCUMFLEX, KEY_COLON2, KEY_KANJI,

KEY_LSHIFT, KEY_RSHIFT, KEY_LCONTROL, KEY_RCONTROL, KEY_ALT, KEY_ALTGR, KEY_LWIN, KEY_RWIN, KEY_MENU, KEY_SCRLOCK, KEY_NUMLOCK, KEY_CAPSLOCK

KEY_EQUALS_PAD, KEY_BACKQUOTE, KEY_SEMICOLON, KEY_COMMAND

clear_keybuf() clears the key buffer. The key buffer is a block of memory where your program will keep a list of all the buttons pressed, you should run clear_keybuf() before every input just incase if there is some unwanted data left in the buffer.

acquire_screen() is used to get Allegro ready to draw to the screen, always be sure to include this before using any functions that draw to the screen and include release_screen() once you are finished.

textout_ex() will draw text to the screen. It takes seven parameters. The first is where you want it to write to, Allegro creates a variable called screen which represents the actuall screen, just use this for now. The second parameter is the type of font to be used, if you do not want to create your own font style, just use font which is the basic font included with Allegro. The next parameter is the text to be drawn to the screen.

The next two are the x and y coordinates which point to where you want the text to be drawn to. When positioning something, remember that coordinates 0, 0 would be the top left of the screen. Adding to x will move the position to the right, while adding to y will move it further down.

Next goes the color of the text. makecol() takes three parameters, the first the intensity of red, the second of green, and then blue. makecol() will then return a value which represents the mix of color made from the three parameters.

The final parameter is the background color.

rest() is used to pause the program for a set amount of milliseconds, just put how long you want to wait in milliseconds between the parenthesis.

Page 21: Game Programing (C++) unknown aouther

Drawing Primitives Now lets look into drawing basic shapes. Here is some example code:

#include <allegro.h>

int main(){ allegro_init(); install_keyboard(); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); acquire_screen();

clear_to_color( screen, makecol( 255, 255, 255));

putpixel( screen, 5, 5, makecol( 128, 200, 23));

circle( screen, 20, 20, 10, makecol( 255, 0, 0)); circlefill( screen, 50, 50, 25, makecol( 0,255, 0));

rect( screen, 70, 70, 90, 90, makecol( 0, 0, 255)); rectfill( screen, 100, 100, 120, 120, makecol( 12, 34, 200));

line( screen, 130, 130, 150, 150, makecol( 255, 0, 0)); line( screen, 130, 130, 170, 130, makecol( 255, 0, 0)); line( screen, 170, 130, 150, 150, makecol( 255, 0, 0)); floodfill( screen, 140, 135, makecol( 255, 255, 0));

triangle( screen, 200, 200, 200, 220, 220, 210, makecol( 213, 79, 40));

release_screen();

readkey(); return 0; } END_OF_MAIN();

This program will change the background color to white and draw several shapes on the screen. Lets break down the code.

"clear_to_color( screen, makecol( 255, 255, 255));" is used to clear any bitmap specified in the first parameter to the color in the second. We will get more into bitmaps in a later lesson, just use screen for now.

All the functions used to draw here take the bitmap to draw to as the first parameter. putpixel() takes four parameters, the second and third define the x and y coordinates. The fourth the color of the pixel. A pixel is the smallest component in an image, what you see on your monitor is a bunch of different color pixels, the size of the pixel depends on the resolution you set with set_gfx_mode().

Page 22: Game Programing (C++) unknown aouther

circle() and circlefill() both draw circles, the difference is that circlefill() will fill in the circle with the color specified in the last parameter while circle() simply draws the outline. The second and third parameters specify the position. The fourth defins the radius of the circle.

rect() and rectfill() draw rectangles which start at the point defined by the second and third parameters and end at the point defined by the fourth and fith parameters. The difference between rect() and rectfill() is the same as the two circle functions.

line() draws a line of the color specified in the last parameter starting at the point defined by the second and third parameter and ending at the point defined by the fourth and fith.

floodfill() works like the "Paint Bucket" tool found in most image editing software. It will fill an area starting at the point defined by the second and third pixel with the color specified in the fourth.

triangle() draws a colored in triangle, there is no trianglefill(). The three points of the triangle are defined by second through sixth parameters. The color is defined by the last parameter.

Drawing From Files Now that you've learned how to draw the basic shapes, lets look into drawing files created by image editing software to screen, afterall it would take quite a bit of time to draw video game characters using the primitive shaps. Lets start with something simple, Tic-Tac-Toe. Here is the X and O. Here is the code:

#include <allegro.h>

BITMAP *xSprite;BITMAP *oSprite;

int main(){ allegro_init(); install_keyboard(); set_color_depth(16); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); xSprite = load_bitmap( "x.bmp", NULL); oSprite = load_bitmap( "o.bmp", NULL);

acquire_screen(); line( screen, 200, 0, 200, 480, makecol( 255, 255, 255)); line( screen, 400, 0, 400, 480, makecol( 255, 255, 255));

Page 23: Game Programing (C++) unknown aouther

line( screen, 0, 150, 680, 150, makecol( 255, 255, 255)); line( screen, 0, 300, 680, 300, makecol( 255, 255, 255)); draw_sprite( screen, xSprite, 0, 0); draw_sprite( screen, oSprite, 200, 0); draw_sprite( screen, xSprite, 400, 0); draw_sprite( screen, oSprite, 0, 150); draw_sprite( screen, xSprite, 200, 150); draw_sprite( screen, oSprite, 400, 150);

draw_sprite( screen, oSprite, 0, 300); draw_sprite( screen, xSprite, 200, 300); draw_sprite( screen, oSprite, 400, 300); release_screen();

readkey(); return 0; } END_OF_MAIN();

This program will draw a filled in Tic-Tac-Toe board to screen. Lets break it down.

The first new line would be "BITMAP *xSprite;", this line introduces a new data type, BITMAP. The * before the name of the variable means its a "pointer" so instead of containing a value like normal variables it holds a place in memory that points to some value. Don't worry if your somewhat lost with pointers, they're not all that important just yet. A bitmap is basically a list of numbers which represent different colors which combined make an image.

set_color_depth() simply sets how many bits are to be used when making a pixel. In this case I set it to 16. This is important when it comes to choosing the transparent color in your drawings. At 16 bits and above the RGB (Red, Green, Blue) value would be 255, 0, 255 for the transparent pixel. 8 bit uses 0, 0, 0.

The next new line is "xSprite = load_bitmap( "x.bmp", NULL);". This line stores the place in memory where the image is located to "xSprite". If you don't understand that, don't worry, just remember to use what ever variable you load the memory address into (in this case xSprite) whenever you want to use this image.

The last new function in this program is draw_sprite(). This function will draw an image ( .bmp, .pcx, .lba, and .tgm are the file types supported by Allegro) to a bitmap, in this case the screen. The first parameter is where to draw the sprite, the second is a pointer to the sprite that you wish to draw, and the third and fourth parameter define the coordinates to where you want your sprite to be displayed.

Animation

Page 24: Game Programing (C++) unknown aouther

If you just finished reading the lessons listed before this one, you should check Tic-Tac-Toe in the "Example Games" section just to be sure you really understand whats going on. Now lets look more into making an object move across the screen. Here is some example code:

#include <allegro.h>#include <cstdlib>

int x = 100;int y = 100;

int tempX = 100;int tempY = 100;

int dir = 1; //This will keep track of the circles direction //1= up and left, 2 = down and left, 3 = up and right, 4 = down and right

void moveCircle(){

tempX = x; tempY = y;

if (dir == 1 && x != 20 && y != 20){ --x; --y; } else if (dir == 2 && x != 20 && y != 460){

--x; ++y;

} else if (dir == 3 && x != 620 && y != 20){

++x; --y;

} else if (dir == 4 && x != 620 && y != 460){

++x; ++y;

} else {

dir = rand() % 4 + 1;

} acquire_screen(); circlefill ( screen, tempX, tempY, 20, makecol( 0, 0, 0)); circlefill ( screen, x, y, 20, makecol( 128, 255, 0)); release_screen(); rest(10);

Page 25: Game Programing (C++) unknown aouther

}

int main(){

allegro_init(); install_keyboard(); set_color_depth(16); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); while( !key[KEY_ESC]){ moveCircle(); } return 0;

}END_OF_MAIN();

Most of the code should look familliar aside from the new header file and the rand() function.

cstdlib contains the rand() function which is used to generate random numbers. In this case, it is used to change the direction of the circle.

Lets break down the code. main() get Allegro ready for action and then goes into a while loop which doesnt stop until the player presses ESC.

moveCircle() will add or subtract to x and y depending on the direction the circle is going in (which is stored in dir). If the circle has hit the top, bottom, or side of the screen, it will change direction.

dir = rand() % 4 +1; gives dir a random value between 1 and 4. rand() % 4 would return a random number between 0 and 3 ( 1 - 4) so we add 1 so we get a number between 1 and 4. If you wanted a number between 3 and 4 the code would be rand() % 2 + 3, since rand() % 2 would return either 0 or 1 so we would have to add 3. There will be more on the rand() function later. Afterwards, a black circle is drawn in order to cover up the old one, and then a green circle is drawn in the new position.

Fairly simple isn't it? But there is one problem with the example, which is the flickering! Needless to say a flickering video game would be quite annoying... Lets fix this.

Double Buffering The answer to all the flickering? Double buffering. What this means is that instead of drawing straight to the screen, we will draw to a temporary bitmap and then have one call to a function which will draw it to the screen. Since this will reduce the amount of times the screen is being accessed, the animation should run smoother. Here is how its done: #include #include

Page 26: Game Programing (C++) unknown aouther

int x = 100;int y = 100;

int tempX = 100;int tempY = 100;

int dir = 1; //This will keep track of the circles direction //1= up and left, 2 = down and left, 3 = up and right, 4 = down and right

BITMAP *buffer; //This will be our temporary bitmap for double buffering

void moveCircle(){

tempX = x; tempY = y;

if (dir == 1 && x != 20 && y != 20){ --x; --y; } else if (dir == 2 && x != 20 && y != 460){

--x; ++y;

} else if (dir == 3 && x != 620 && y != 20){

++x; --y;

} else if (dir == 4 && x != 620 && y != 460){

++x; ++y;

} else {

dir = rand() % 4 + 1;

} acquire_screen(); circlefill ( buffer, tempX, tempY, 20, makecol( 0, 0, 0)); circlefill ( buffer, x, y, 20, makecol( 128, 255, 0)); draw_sprite( screen, buffer, 0, 0); release_screen(); rest(10);

}

int main(){

allegro_init();

Page 27: Game Programing (C++) unknown aouther

install_keyboard(); set_color_depth(16); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); buffer = create_bitmap( 640, 480); while( !key[KEY_ESC]){ moveCircle(); } return 0;

}END_OF_MAIN();

There you have it, the flickering is no more! Here we create a bitmap called buffer and using create_bitmap() we make it the same size as the screen. After this, anywhere you would have normally used screen, use buffer instead ( circlefill ( buffer, tempX, tempY, 20, makecol( 0, 0, 0)); ). Once everything has been drawn, copy the buffer onto the screen and there you have it!

Backgrounds Now that we've got basic animations out the way, lets look into adding a background to our game. In the Pong example, every time the ball or a paddle moved, a black circle or rectangle took the place of the objects last position so that the player would not see a trace of it. What if we have a multicolored background though? Easy, using a technique known as "dirty rectangles" we can easily replace the background with the right color/image. For this we create two 2-dimensional arrays. One will be the background, and the other will contain the objects that will be moving around. This way we can check an objects last position and know what color/image to fill that portion of the screen with. It might sound some what confusing, hopefully an example will help answer any questions.

Here is an example for a tile based game using dirty rectangles. You will need the box image.

#include <allegro.h>

BITMAP* box;BITMAP* buffer;

//These will hold the player's position//instead of using pixels, we will use the position within the 2d arrayint x = 15;int y = 11;

int tempX = 15;int tempY = 11;

Page 28: Game Programing (C++) unknown aouther

//This will hold the value of how many boxes are left outside of the holes.int boxes;

//This will be our background, 1 = clouds, 2 = brick, 3 = floor, 4 = holeint map[24][32] = {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,2,3,3,3,3,3,3,3,3,3,2,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,2,3,3,3,3,4,3,3,3,3,2,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,2,3,3,3,3,3,3,3,3,3,2,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,2,3,3,3,3,3,3,3,3,3,2,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,2,3,3,3,3,3,3,3,3,3,2,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,2,3,3,3,3,3,3,3,3,3,2,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,2,3,3,3,3,3,3,3,3,3,2,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,2,3,3,3,3,3,3,3,3,3,2,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,2,3,3,3,3,3,3,3,3,3,2,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};

//This will contain all the objects, 100 = player, 101 = box

Page 29: Game Programing (C++) unknown aouther

int objMap[24][32] = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,101,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};

void setupGame(){ buffer = create_bitmap( 640, 480); box = load_bitmap( "box.bmp", NULL); boxes = 1; for (int i = 0; i <= 24; i++){

Page 30: Game Programing (C++) unknown aouther

for( int t = 0; t <= 32; t++){ if( map[i][t] == 1) rectfill( buffer, t * 20, i * 20, (t + 1) * 20, (i + 1) * 20, makecol( 128, 255, 255)); else if( map[i][t] == 2) rectfill( buffer, t * 20, i * 20, (t + 1) * 20, (i + 1) * 20, makecol( 255, 128, 0)); else if( map[i][t] == 3) rectfill( buffer, t * 20, i * 20, (t + 1) * 20, (i + 1) * 20, makecol( 255, 0, 0)); else if( map[i][t] == 4) rectfill( buffer, t * 20, i * 20, (t + 1) * 20, (i + 1) * 20, makecol( 0, 0, 0)); } } for (int i = 0; i <= 24; i++){ for( int t = 0; t <= 32; t++){ if( objMap[i][t] == 100) circlefill( buffer, (t * 20) + 10, (i * 20) + 10, 10, makecol( 255, 255, 0)); else if( objMap[i][t] == 101) draw_sprite( buffer, box, t * 20, i * 20); } } draw_sprite( screen, buffer, 0, 0); }

void movePlayer(){ tempX = x; tempY = y; if ( key[KEY_UP] && map[y - 1][x] == 3){ if( objMap[y - 1][x] != 101){ --y; } else if( objMap[y - 1][x] == 101 && map[y - 2][x] == 3 || objMap[y - 1][x] == 101 && map[y - 2][x] == 4){ if (map[y - 2][x] == 4) --boxes; objMap[y - 2][x] = 101; draw_sprite( buffer, box, x * 20, (y - 2) *20); --y; } } else if ( key[KEY_DOWN] && map[y + 1][x] == 3){ if( objMap[y + 1][x] != 101){ ++y; } else if( objMap[y + 1][x] == 101 && map[y + 2][x] == 3 || objMap[y + 1][x] == 101 && map[y + 2][x] == 4){

Page 31: Game Programing (C++) unknown aouther

if (map[y + 2][x] == 4) --boxes; objMap[y + 2][x] = 101; draw_sprite( buffer, box, x * 20, (y + 2) *20); ++y; } } else if ( key[KEY_RIGHT] && map[y][x + 1] == 3){ if( objMap[y][x + 1] != 101){ ++x; } else if( objMap[y][x + 1] == 101 && map[y][x + 2] == 3 || objMap[y][x + 1] == 101 && map[y][x + 2] == 4){ if (map[y][x + 2] == 4) --boxes; objMap[y][x + 2] = 101; draw_sprite( buffer, box, (x + 2) * 20, y * 20); ++x; } } else if ( key[KEY_LEFT] && map[y][x - 1] == 3){ if( objMap[y][x - 1] != 101){ --x; } else if( objMap[y][x - 1] == 101 && map[y][x - 2] == 3 || objMap[y][x - 1] == 101 && map[y][x - 2] == 4){ if (map[y][x - 2] == 4) --boxes; objMap[y][x - 2] = 101; draw_sprite( buffer, box, (x - 2) * 20, y * 20); --x; } } acquire_screen(); rectfill( buffer, tempX * 20, tempY * 20, (tempX + 1) * 20, (tempY + 1) * 20, makecol( 255, 0, 0)); circlefill( buffer, (x * 20) + 10, (y * 20) + 10, 10, makecol( 255, 255, 0)); draw_sprite( screen, buffer, 0, 0); release_screen(); objMap[tempY][tempX] = 0; objMap[y][x] = 101; if ( !boxes){ textout_ex( screen, font, "You Win!!!", 320, 240, makecol(0, 0, 255), makecol(0, 0, 0)); }

Page 32: Game Programing (C++) unknown aouther

rest(100);}

int main(){ allegro_init(); install_keyboard(); set_color_depth(16); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); setupGame(); while( !key[KEY_ESC]){ movePlayer(); } return 0;}END_OF_MAIN();

This is a simple version of sokoban, a game where the player tries to push all the boxes on the stage into the holes provided. It used 20x20 pixel tiles. Lets take a closer look at the code.

Here I am using two 2D arrays to keep track of what needs to be updated. We will look into creating a map editor later on so that we won't have to type out so many numbers in order to create a map. One thing you should notice about the map is that when checking a specific tile you must use arrayName[y][x], the x and y are inverted (unless if you want to declare the 2D array as arrayName[32][24], this would make editing a bit of a hassle).

main() has the usual setup. setupGame() draws the screen and sets how many boxes will be in the current level, since this is intended to show dirt rectangles, I only included one.

movePlayer() controls the player, moves the box when it is pushed by the player, and declares the player a winner if he succeeds.

When the player presses an arrow key, movePlayer() checks to see if there is anything in tile the player want to move to. If there is nothing, it will check for a box, if there isnt one, it will move the player. If there is a box, it will check the tile where the box will be pushed to. If that tile is empty, or a hole, it will move the box and subtract it from the total number of boxes left in the game.

Afterwards, it draws the player and box to screen, and covers up the location the player used to be in (We do not need to bother with the tile the box was in since it will be occupied by the player). After this it will update the players location on the object map and declare you a winner if there are no more boxes left.

Allegro Mouse

Page 33: Game Programing (C++) unknown aouther

Here we will look into how the mouse is used with Allegro. Here is some example code:

#include <allegro.h>

BITMAP* buffer;

int cursor_x = 20;int cursor_y = 20;

void getMouseInfo(){

if(mouse_b & 1){

cursor_x = mouse_x; cursor_y = mouse_y;

}

}

void updateScreen(){

circlefill ( buffer, cursor_x, cursor_y, 20, makecol( 0, 0, 255)); draw_sprite( screen, buffer, 0, 0);

}

int main(){ allegro_init(); install_mouse(); install_keyboard(); set_color_depth(16); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); buffer = create_bitmap( 640, 480); show_mouse(buffer); while( !key[KEY_ESC]){ getMouseInfo(); updateScreen(); }

return 0; }END_OF_MAIN();

This program will draw a blue circle at the current mouse position everytime the left mouse button is pressed.

Page 34: Game Programing (C++) unknown aouther

First of all, to get the mouse to appear, show_mouse(buffer) is used. As you might expect, function displays the mouse cursor on the bitmap specified. In order to make the mouse dissear once again, just do a show_mouse(NULL).

In order to check for the button states, Allegro defines a variable called mouse_b. It sets different bits in the variable to 1, depending on what button was pressed. Here is how to check for the different buttons:

Left button: mouse_b & 1Right button: mouse_b & 2Wheel: mouse_b & 3

Checking mouse position is much easier. Allegro stores them in mouse_x and mouse_y. The current wheel position is stored in mouse_z. All of these are plain old normal ints and can be treated like any other variable you've declared (no funny '&'s or anything like that needed).

You may have noticed a black rectangle on some of the circles with the last example. Mostly when you try to move the mouse fast. Wmz, one of the sites viewers, submited the following code which shows one way of eliminating this problem:

#include <allegro.h>

BITMAP* buffer;int cursor_x = 20;int cursor_y = 20;int getMouseInfo(){ if(mouse_b & 1){ cursor_x = mouse_x; cursor_y = mouse_y; return 1; } return 0;}void updateScreen(){ show_mouse(NULL); circlefill ( buffer, cursor_x, cursor_y, 5, makecol( 0, 0, 255)); draw_sprite( screen, buffer, 0, 0); }int main(){ allegro_init(); install_mouse(); install_keyboard(); set_color_depth(16); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); buffer = create_bitmap( 640, 480);

show_mouse(screen); while( !key[KEY_ESC])

Page 35: Game Programing (C++) unknown aouther

{ int switcher=1; while(getMouseInfo()) { updateScreen(); if(getMouseInfo()==0) switcher=0; } if(switcher==0) show_mouse(screen); } return 0; }END_OF_MAIN();

Here Wmz used a variable called switcher to determine wether or not the mouse cursor should be displayed. If something needs to be drawn to the screen, updateScreen() will first deactivate the mouse so that it does not interrupt the process, once the update is finished, the while loop will continue and redraw the mouse cursor directly to the screen.

Allegro Animation II Ok lets look into how to make a character move across the screen while swaying his arms and moving his legs. First you'll need to download the images for this tutorial located here. As always the images are not of the highest quality, but they serve their purpose :). Now on to the example code. The program is divided into 3 files, main.cpp, character.h, and character.cpp:

//main.cpp

#include <allegro.h>#include "Character.h"

using namespace std;

BITMAP* buffer;Character myChar;

void Setup(){

buffer= create_bitmap(640, 480); myChar.SetImagesLeft( "left1.bmp", "left2.bmp", "left3.bmp"); myChar.SetImagesRight( "right1.bmp", "right2.bmp", "right3.bmp"); myChar.SetImagesUp( "up1.bmp", "up2.bmp", "up3.bmp"); myChar.SetImagesDown( "down1.bmp", "down2.bmp", "down3.bmp"); myChar.Show( screen);

}

void movePlayer(){

if( key[KEY_LEFT]){ myChar.MoveOnX( LEFT, buffer, screen); } else if( key[KEY_RIGHT]){ myChar.MoveOnX( RIGHT, buffer, screen);

Page 36: Game Programing (C++) unknown aouther

} else if( key[KEY_UP]){ myChar.MoveOnY( UP, buffer, screen); } else if( key[KEY_DOWN]){ myChar.MoveOnY( DOWN, buffer, screen); }

}

int main(int argc, char *argv[]){ allegro_init(); install_mouse(); install_keyboard(); set_color_depth(16); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); Setup(); while( !key[KEY_ESC]){ movePlayer(); } return 0;}END_OF_MAIN();

//Character.h

#ifndef CHARACTER_H#define CHARACTER_H

#define LEFT 1#define RIGHT 2#define UP 3#define DOWN 4

#include <allegro.h>

class Character{

public: Character(); ~Character(); // The following 4 methods will be used to set the images for the different //stages of movement void SetImagesLeft( char image1[], char image2[], char image3[]); void SetImagesRight( char image1[], char image2[], char image3[]); void SetImagesUp( char image1[], char image2[], char image3[]); void SetImagesDown( char image1[], char image2[], char image3[]); //To keep the program from crashing, this function will be used before

Page 37: Game Programing (C++) unknown aouther

//calling any movement methods bool CheckImages(); int GetX(); void SetX( int newValue); void MoveOnX( int newValue, BITMAP* tempBitmap, BITMAP* mainBitmap); int GetY(); void SetY( int newValue); void MoveOnY( int newValue, BITMAP* tempBitmap, BITMAP* mainBitmap); void EraseOldSprite( BITMAP* tempBitmap); void DrawNewSprite( BITMAP* tempBitmap, BITMAP* spriteToDraw); void Show(BITMAP* mainBitmap); private: bool leftDone; bool rightDone; bool upDone; bool downDone; int direction; int x; int y; //This will contain all the images, [0][0-2] will be left movements, [1][0-2] right //[2][0-2] upwards, and [3][0-2] downwards BITMAP *images[4][3];

};

#endif

//Character.cpp#include "Character.h"

Character::Character(){

leftDone= false; rightDone= false; upDone= false; downDone= false; direction = DOWN; int x= 0; int y= 0;

}

Page 38: Game Programing (C++) unknown aouther

Character::~Character(){

delete [] images;

}

void Character::SetImagesLeft( char image1[], char image2[], char image3[]){ images[0][0]= load_bitmap(image1, NULL); images[0][1]= load_bitmap(image2, NULL); images[0][2]= load_bitmap(image3, NULL); leftDone= true; }

void Character::SetImagesRight(char image1[], char image2[], char image3[]){

images[1][0]= load_bitmap(image1, NULL); images[1][1]= load_bitmap(image2, NULL); images[1][2]= load_bitmap(image3, NULL); rightDone= true;

}

void Character::SetImagesUp(char image1[], char image2[], char image3[]){

images[2][0]= load_bitmap(image1, NULL); images[2][1]= load_bitmap(image2, NULL); images[2][2]= load_bitmap(image3, NULL); upDone= true;

} void Character::SetImagesDown(char image1[], char image2[], char image3[]){

images[3][0]= load_bitmap(image1, NULL); images[3][1]= load_bitmap(image2, NULL); images[3][2]= load_bitmap(image3, NULL); downDone= true;

}

bool Character::CheckImages(){

if( rightDone && leftDone && upDone && downDone) return true; return false;

Page 39: Game Programing (C++) unknown aouther

} int Character::GetX(){

return x;

} int Character::GetY(){

return y;

}

void Character::SetX( int newValue){ x = newValue;}

void Character::SetY( int newValue){ y = newValue;}

void Character::MoveOnX( int newDirection, BITMAP* tempBitmap, BITMAP* mainBitmap){

direction = newDirection;

if( CheckImages()){ if( direction == LEFT){ for( int i=0; i<=3; i++){ EraseOldSprite( tempBitmap); x -= 5; if (i == 1 || i == 3) DrawNewSprite( tempBitmap, images[0][0]); if (i == 0) DrawNewSprite( tempBitmap, images[0][1]); if (i == 2) DrawNewSprite( tempBitmap, images[0][2]); draw_sprite( mainBitmap, tempBitmap, 0, 0); rest(50); } } else { for( int i=0; i<=3; i++){ EraseOldSprite( tempBitmap); x += 5; if (i == 1 || i == 3)

Page 40: Game Programing (C++) unknown aouther

DrawNewSprite( tempBitmap, images[1][0]); if (i == 0) DrawNewSprite( tempBitmap, images[1][1]); if (i == 2) DrawNewSprite( tempBitmap, images[1][2]); draw_sprite( mainBitmap, tempBitmap, 0, 0); rest(50); } } }

}

void Character::MoveOnY( int newDirection, BITMAP* tempBitmap, BITMAP* mainBitmap){

direction = newDirection;

if( CheckImages()){ if( direction == UP){ for( int i=0; i<=3; i++){ EraseOldSprite( tempBitmap); y -= 5; if (i == 1 || i == 3) DrawNewSprite( tempBitmap, images[2][0]); if (i == 0) DrawNewSprite( tempBitmap, images[2][1]); if (i == 2) DrawNewSprite( tempBitmap, images[2][2]); draw_sprite( mainBitmap, tempBitmap, 0, 0); rest(50); } } else { for( int i=0; i<=3; i++){ EraseOldSprite( tempBitmap); y += 5; if (i == 1 || i == 3) DrawNewSprite( tempBitmap, images[3][0]); if (i == 0)

Page 41: Game Programing (C++) unknown aouther

DrawNewSprite( tempBitmap, images[3][1]); if (i == 2) DrawNewSprite( tempBitmap, images[3][2]); draw_sprite( mainBitmap, tempBitmap, 0, 0); rest(50); } } }}

void Character::EraseOldSprite( BITMAP* tempBitmap){

rectfill( tempBitmap, GetX(), GetY(), GetX() + 20, GetY() + 20, makecol ( 0, 0, 0));

}

void Character::DrawNewSprite( BITMAP* tempBitmap, BITMAP* spriteToDraw){

draw_sprite( tempBitmap, spriteToDraw, GetX(), GetY());

}

void Character::Show(BITMAP* mainBitmap){

if( CheckImages()) draw_sprite( screen, images[3][0], 0, 0);

}

In this program most of the work is done by the Character class. Here the object is drawing itself and replacing the background as it goes. When the user presses an arrow key, either MoveOnX() or MoveOnY() will be called. Each of these methods will move the character 20 pixels in the desired direction, but only 5 pixels at a time. This gives the program time to change out the drawings so that each part of the animation (defined with SetImagesLeft, Right, Up, and Down) can be seen. Each time the for loop in these functions runs, it will have the old sprite drawn over by the background (in this case a black rectangle is all that is needed) and then the next step in the animation will be drawn 5 pixels past the old one. If you decide to use a more complex background, simply modify the DrawNewSprite() method so that I redraws 2 tiles from the background (the one the character is currently on, and the one he is moving to). By now you should be able to understand the rest, if not, feel free to drop by the forums and ask any questions you may have!

Examples of games

Page 42: Game Programing (C++) unknown aouther

Tic-Tac-Toe Here is the source code to the game, you will also need the X and O images. This is a very simple version of the game, nothing fancy, no menus, no nothing, just the actuall game was coded in hopes of making it easier for beginners.

#include <allegro.h>

BITMAP *xSprite;BITMAP *oSprite;

int board[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0}; //This will be used to keep //track of the Xs and Osint curSquare = 0; //This will keep track of the current square //the selector is on int turn = 1; //This will keep track of whose turn it is //1 Will be for X and 2 for O int x = 0; //X and Y position of selectorint y = 0;

int tempX = 0; //holds temporary values used to clear selectorint tempY = 0;

void setupBoard(){ //This function will draw in the grid

acquire_screen(); line( screen, 200, 0, 200, 480, makecol( 255, 255, 255)); line( screen, 400, 0, 400, 480, makecol( 255, 255, 255)); line( screen, 0, 150, 680, 150, makecol( 255, 255, 255)); line( screen, 0, 300, 680, 300, makecol( 255, 255, 255)); rect( screen, x+1, y+1, x + 199, y + 149, makecol( 255, 255, 0)); release_screen(); }

void updateBoard(){ //draws in selector

rect( screen, tempX+1, tempY+1, tempX + 199, tempY + 149, makecol( 0, 0, 0)); rect( screen, x+1, y+1, x + 199, y + 149, makecol( 255, 255, 0)); rest(100);}

void announceWinner(){ //Announces the winner

if( turn == 1){ textout_ex( screen, font, "X Wins!!!!", 300, 240, makecol( 255, 0, 0), makecol(0, 0, 0)); } else { textout_ex( screen, font, "O Wins!!!!", 300, 240, makecol( 255, 0, 0), makecol(0, 0, 0));

Page 43: Game Programing (C++) unknown aouther

}

}

void checkWin(){ //checks for a winner if( board[0] == turn && board[1] == turn && board[2] == turn){ announceWinner(); } else if( board[0] == turn && board[3] == turn && board[6] == turn){ announceWinner(); } else if( board[0] == turn && board[4] == turn && board[8] == turn){ announceWinner(); } else if( board[1] == turn && board[4] == turn && board[7] == turn){ announceWinner(); } else if( board[2] == turn && board[4] == turn && board[6] == turn){ announceWinner(); } else if( board[2] == turn && board[5] == turn && board[8] == turn){ announceWinner(); } else if( board[3] == turn && board[4] == turn && board[5] == turn){ announceWinner(); } else if( board[6] == turn && board[7] == turn && board[8] == turn){ announceWinner(); } }

void drawXO(){ //draws in the X and O acquire_screen(); if(turn == 1){ draw_sprite( screen, xSprite, x, y); board[curSquare] = 1; checkWin(); ++turn; } else if( turn == 2){ draw_sprite( screen, oSprite, x, y); board[curSquare] = 2; checkWin(); --turn; } release_screen(); rest(100); }

Page 44: Game Programing (C++) unknown aouther

void moveBox(){ //takes input clear_keybuf(); tempX = x; tempY = y; if( key[KEY_UP] && y != 0){ y -= 150; curSquare -=3; updateBoard(); } else if( key[KEY_DOWN] && y != 300){ y += 150; curSquare +=3; updateBoard(); } else if( key[KEY_RIGHT] && x != 400){ x += 200; ++curSquare; updateBoard(); } else if( key[KEY_LEFT] && x != 0){ x -= 200; --curSquare; updateBoard(); } else if( key[KEY_ENTER] && board[curSquare] == 0){ drawXO(); } }

int main(){ allegro_init(); install_keyboard(); set_color_depth(16); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); xSprite = load_bitmap( "x.bmp", NULL); oSprite = load_bitmap( "o.bmp", NULL);

setupBoard(); while( !key[KEY_ESC]){ moveBox(); }

Page 45: Game Programing (C++) unknown aouther

destroy_bitmap( xSprite); destroy_bitmap( oSprite); return 0; } END_OF_MAIN();

Lets break the code down function by function.

main() runs the normal functions used to setup Allegro and the screen. It includes a call to setupBoard() which will simply draw lines to for the grid and draw in a box so the player knows what square is currently selected.

while ( !key[KEY_ESC]) is the main loop, this keeps the game running until ESC is pressed.

moveBox() takes input from the player and calls different functions depending on the key pressed. If an arrow key is pressed the x or y variable will be adjusted to get the selector to the next square and curSquare is updated so that we can easily find which part of board[] corresponds to the square the player is currently in. updateBoard() is called to simply clear out the old selector and draw in the new one.

If enter is pressed and the current square is not occupied, drawXO() is called. This function will check whose turn it is and draw in the corresponding shape ( X or O ). It then updates board[] so that the current square will be marked as being occupied by either a X or an O. Then it calls checkWin() which checks to see if someone has won, and then changes the turn variable so that the next player can go ( 1 = X's turn, 2 = O's turn).

checkWin() checks for a winner. Since drawXO() changes board[curSquare] so that it equals the current users turn, board will have 1's to represent X's and 2's to represent O's. checkWin() will check to see if there are three 1's or 2's in a row, depending on whose turn it is and call announceWinner() if there are.

announceWinner() simply checks whose turn it is (who should be the winner since the turn has not been modified by drawXO() yet) and prints out who the winner is to screen.

Pong Pong requires a little bit more skill to code than the last example, Tic-Tac-Toe. Here we have three objects moving about, we need to know when the ball hits a player's paddle or someone scores, plus we need to calculate a random number for the direction of the ball. Here is the code:

#include <allegro.h>#include <cstdlib>

Page 46: Game Programing (C++) unknown aouther

#include <time.h>

int ball_x = 320;int ball_y = 240;

int ball_tempX = 320;int ball_tempY = 240;

int p1_x = 20;int p1_y = 210;

int p1_tempX = 20;int p1_tempY = 210;

int p2_x = 620;int p2_y = 210;

int p2_tempX = 620;int p2_tempY = 210;

time_t secs; //The seconds on the system clock will be stored here //this will be used as the seed for srand()

int dir; //This will keep track of the circles direction //1= up and left, 2 = down and left, 3 = up and right, 4 = down and right

BITMAP *buffer; //This will be our temporary bitmap for double buffering

void moveBall(){

ball_tempX = ball_x; ball_tempY = ball_y;

if (dir == 1 && ball_x > 5 && ball_y > 5){ if( ball_x == p1_x + 15 && ball_y >= p1_y && ball_y <= p1_y + 60){ dir = rand()% 2 + 3; }else{ --ball_x; --ball_y; } } else if (dir == 2 && ball_x > 5 && ball_y < 475){

if( ball_x == p1_x + 15 && ball_y >= p1_y && ball_y <= p1_y + 60){ dir = rand()% 2 + 3; }else{ --ball_x; ++ball_y; }

} else if (dir == 3 && ball_x < 635 && ball_y > 5){

Page 47: Game Programing (C++) unknown aouther

if( ball_x + 5 == p2_x && ball_y >= p2_y && ball_y <= p2_y + 60){ dir = rand()% 2 + 1; }else{ ++ball_x; --ball_y; }

} else if (dir == 4 && ball_x < 635 && ball_y < 475){

if( ball_x + 5 == p2_x && ball_y >= p2_y && ball_y <= p2_y + 60){ dir = rand()% 2 + 1; }else{ ++ball_x; ++ball_y; }

} else {

if (dir == 1 || dir == 3) ++dir; else if (dir == 2 || dir == 4) --dir;

} acquire_screen(); circlefill ( buffer, ball_tempX, ball_tempY, 5, makecol( 0, 0, 0)); circlefill ( buffer, ball_x, ball_y, 5, makecol( 128, 255, 0)); draw_sprite( screen, buffer, 0, 0); release_screen(); rest(5);

}

void p1Move(){ p1_tempY = p1_y; if( key[KEY_W] && p1_y > 0){ --p1_y; } else if( key[KEY_S] && p1_y < 420){ ++p1_y; } acquire_screen(); rectfill( buffer, p1_tempX, p1_tempY, p1_tempX + 10, p1_tempY + 60, makecol ( 0, 0, 0)); rectfill( buffer, p1_x, p1_y, p1_x + 10, p1_y + 60, makecol ( 0, 0, 255)); release_screen(); }

Page 48: Game Programing (C++) unknown aouther

void p2Move(){ p2_tempY = p2_y; if( key[KEY_UP] && p2_y > 0){ --p2_y; } else if( key[KEY_DOWN] && p2_y < 420){ ++p2_y; } acquire_screen(); rectfill( buffer, p2_tempX, p2_tempY, p2_tempX + 10, p2_tempY + 60, makecol ( 0, 0, 0)); rectfill( buffer, p2_x, p2_y, p2_x + 10, p2_y + 60, makecol ( 0, 0, 255)); release_screen(); }

void startNew(){

clear_keybuf(); readkey(); clear_to_color( buffer, makecol( 0, 0, 0)); ball_x = 320; ball_y = 240;

p1_x = 20; p1_y = 210;

p2_x = 620; p2_y = 210;

}

void checkWin(){

if ( ball_x < p1_x){ textout_ex( screen, font, "Player 2 Wins!", 320, 240, makecol( 255, 0, 0), makecol( 0, 0, 0)); startNew(); } else if ( ball_x > p2_x){ textout_ex( screen, font, "Player 1 Wins!", 320, 240, makecol( 255, 0, 0), makecol( 0, 0, 0)); startNew(); } }

void setupGame(){ acquire_screen();

Page 49: Game Programing (C++) unknown aouther

rectfill( buffer, p1_x, p1_y, p1_x + 10, p1_y + 60, makecol ( 0, 0, 255)); rectfill( buffer, p2_x, p2_y, p2_x + 10, p2_y + 60, makecol ( 0, 0, 255)); circlefill ( buffer, ball_x, ball_y, 5, makecol( 128, 255, 0)); draw_sprite( screen, buffer, 0, 0); release_screen(); time(&secs); srand( (unsigned int)secs); dir = rand() % 4 + 1; }

int main(){

allegro_init(); install_keyboard(); set_color_depth(16); set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0); buffer = create_bitmap( 640, 480); setupGame(); while( !key[KEY_ESC]){

p1Move(); p2Move(); moveBall(); checkWin(); } return 0;

}END_OF_MAIN();

Lets break this down. There is a new header file not covered in the lessons so far, time.h. This contains the functions used to get the current time from the system clock, this will be used to calculate the random numbers.

main() runs through the usuall setup for the game and then calls setupGame(). This function draws the screen and calls time() to get the current time. srand() is a function that changes the "seed" that rand() will use to make random numbers, the seed is the initial value rand() will begin with. In this case the seed is set to the current amount of seconds the system clock is displaying, this way there will always be a new seed everytime the program runs so there will never be a repetetive pattern.

dir = rand() % 4 + 1; will give dir a value between 1 and 4. rand() % x will return a random number between 0 and x-1, in this case 0 to 3. Since we want a number from 1 to 4, we simply add 1 to the result.

Page 50: Game Programing (C++) unknown aouther

Once the setup is complete, the main loop begins. p1Move() will move the paddle on the left side of the screen when W and S are pressed, and p2Move() will do the same for the other paddle when up and down are pressed. moveBall() checks to see if it is about to go off the screen, or hit a paddle and change its course accordingly.

checkWin() will see if the ball has passed a paddle and declare a winner if it has. startNew() will simply clear the screen and reset the values for the ball's and players' positions.