In this chapter we will learn about Object Oriented Programming (OOP) through C++ classes. Using Classes we will then build a primitive Strategy game that will lead to a far superior one.
Currently our college professors say that the best type of programming is object oriented programming. So far we have only done proceduralprogramming, which used to be considered the best. That was before OOP was invented. C is strictly procedural, but C++ allows OOP. Many people say that the millennium bug would be much easier to fix if the programmers had been using an OOP language.
The struct
was the C version of the class. A struct is a grouping of
variables. Here is an example:
struct
SBox
{
char Color[20];
int Height;
int Width;
int Length;
};
The most annoying thing
about classes and struct can be the semicolon that must follow
the closing brace. Now lets look at how to access a struct:
struct
SBox
{
char Color[20];
int Height;
int Width;
int Length;
};
int main()
{
SBox BoomBox;
BoomBox.Height = 10;
BoomBox.Width = 50;
BoomBox.Length = 20;
BoomBox.Color = "Neon Yellow"
}
Then
there was class. Classes allow us privacy. Privacy
what do I mean privacy? structs only had public
members. This meant that any code could directly access the
members of the struct. Classes allow us to decide the
access privileges of the other functions and classes in our
programs. Consider the following:
class
CFood
{
private:
int Weight;
int Calories;
char Name[20];
public:
int Age;
};
If we
have an object with the above class only class members could
access the private members. So say somewhere in my main
function I declared a CFood object called Carrot. In the
main function I couldn't say Carrot.Weight = 12. To access
the class members we will create public functions. Let's
add to CFood:
class
CFood
{
private:
int Weight;
int Calories;
char Name[20];
int Age;
public:
void GiveValues()
{
cout<<"What is the name of your food?
"<<endl;
cin>>Name;
cout<<"How many calories does a
"<<Name<<" have? ";
cin>>Calories;
cout<<"How many ounces is your
"<<Name<<"? ";
cin>>Weight;
cout<<"How old is your
"<<Name<<"? ";
cin>>Age;
}
};
Now in our main function we can access the members by typing Carrot.GiveValues() . Two important class functions that you can create are called the constructor and the destructor. We will only go over the constructor in this chapter.
Say you want to give the class members default values or have the user enter values for the members when ever objects are created. That is what the constructor is for. Every time a class is created, after the memory is allocated, if a constructor is defined it is executed. Review the following:
class
CMonster
{
private:
int HitPoints;
int Armor;
char Name[20];
int Age;
public:
CMonster()
{
cout<<"What is the name of your Monster?
"<<endl;
cin>>Name;
cout<<"How many hit points does a
"<<Name<<" have? ";
cin>>HitPoints;
cout<<"How much armor does your
"<<Name<<" have? ";
cin>>Armor;
Age = 1;
}
void GiveValues()
{
cout<<"What is the name of your Monster?
"<<endl;
cin>>Name;
cout<<"How many hit points does a
"<<Name<<" have? ";
cin>>HitPoints;
cout<<"How much armor does your
"<<Name<<" have? ";
cin>>Armor;
cout<<"How old is your
"<<Name<<"? ";
cin>>Age;
}
};
Note that constructors, as well as destructors, do not have return types because they aren't allowed to return anything. Constructors must have the same name as the class.
Classes can have classes
within themselves. Sometimes we want to allow certain
functions or classes access to the private members of a
class. This is why we have friends. Let's say we have
a void Function() that we want to have access to. Using our
CMonster example we would do the following:
class
CMonster
{
friend void function();
private:
int HitPoints;
int Armor;
char Name[20];
int Age;
public:
CMonster()
{
cout<<"What is the name of your Monster?
"<<endl;
cin>>Name;
cout<<"How many hit points does a
"<<Name<<" have? ";
cin>>HitPoints;
cout<<"How much armor does your
"<<Name<<" have? ";
cin>>Armor;
Age = 1;
}
void GiveValues()
{
cout<<"What is the name of your Monster?
"<<endl;
cin>>Name;
cout<<"How many hit points does a
"<<Name<<" have? ";
cin>>HitPoints;
cout<<"How much armor does your
"<<Name<<" have? ";
cin>>Armor;
cout<<"How old is your
"<<Name<<"? ";
cin>>Age;
}
};
If we wanted our CFood
function to have access to the private members of another class
we would write the following in the class's definition:
friend CFood;
You may be wondering why I have been using C in front of the name for classes and S in front of the name for structs. Many C and C++ writers always use an H. I feel that the C or S are more meaningful so I use them instead.
The :? operator.
This is a simple version of true and false. Consider the
following:
cout<<"Your pig" << (Size>1 :
"s need" ? " needs")<< "
food."<<endl;
If Size is bigger than 1
then one the output is:
Your pigs need food.
If Size is less than 1
the output would be:
Your pig needs food.
Since I now own a copy of Visual C++ 6.0 , you will see bool types in this and many other future programs. bool is the smallest a data structure can be. It's only values can be 0 or 1. I usually use 1 for Yes and True, while using 0 for False or No, but we can use it for other things. If your compiler can't use bool, you can use int instead.
The last
thing we need to cover before the game is three preprocessor
statements. cpp files compile into obj files. The obj
or object files are then linked together. Compilers will
not allow headers or classes to be defined more than once.
Consider the following:
#ifndef
County5a_h
#define
Country5a_h
struct
Square
{
int Width;
int Height;
};
#endif
If the above code is written in a header included by multiple cpp files it will only be included in one obj file per program. These statements don't accept periods so use underscores instead.
Now here is Two Player Conquest:
< main > < header > < program >
country5a.h:
//
country5a.h
//
This will hold the class definitions for countries
//
Copyright (c) 1998 Forest J. Handford
/////////////////////////////////////////////////////
#ifndef
Country5a_h
#define
Country5a_h
#define
MAX_PLAYERS 2
#define
TRUE 1
#define
FALSE 0
class
CCountries
{
private:
class
CPlayer
{
friend CCountries; // Give CCountries access
int Armies;
int Money;
int Territory;
int Technology;
int UpgradeCost;
char Name[15];
CPlayer()
{
Armies = 5;
Money = 5;
Territory = 5;
Technology = 1;
UpgradeCost = 5;
}
public:
// This will sell land
void Grow()
{
char YorN = 'y'; // For Yes or No answers
// Loop as long as they want to grow
for(int Count=0; tolower(YorN) == 'y'; Count++)
{
// They most have at least one army for every territory
if (Armies <= Territory)
{
cout<<"You need more armies for more
land."<<endl;
break;
}
// Sell the land and tell the players
else if(Money > 0)
{
Money -= 1;
Territory += 1;
cout<<"You now have "<<Territory
<<" States and "<<Money<<"
money."<<endl;
// Don't stay here if they are out of land or money
if((Armies <= Territory) || (Money <= 0))
{
break;
}
cout<<"Would you like to buy another (Yes or
No)?";
cin>>YorN;
}
// If they are out of money tell them and exit
else
{
cout<<"You are out of money!"<<endl;
break;
}
}
}
// This will check for to many territories
void CountryLoss()
{
if(Armies < Territory)
{
cout<<"Sorry "<<Name<<", you
don't have enough armies to keep "
<<"your territories! They are"
<<endl<<"reduced to
"<<Armies<<"."
<<endl;
Territory = Armies;
}
}
};
public:
CPlayer
Players[MAX_PLAYERS];
void
Upgrade(bool Player)
{
char YorN = 'y';
// Loop till the user is out of money or is bored
while(tolower(YorN) == 'y')
{
// Take their money if they have any
if(Players[Player].Money >= Players[Player].UpgradeCost)
{
Players[Player].Money -= Players[Player].UpgradeCost;
Players[Player].UpgradeCost *= 2;
Players[Player].Technology += 1;
cout<<"You now have
"<<Players[Player].Technology
<<" Upgrades and
"<<Players[Player].Money<<"
money."<<endl;
cout<<"Upgrades now cost you :
"<<Players[Player].UpgradeCost<<"."<<endl;
}
else // Scold them for having no money
{
cout<<"You don't have enough money. You need
"<<Players[Player].UpgradeCost<<"."
<<endl;
}
// break if they run out of money
if(Players[Player].Money <= Players[Player].UpgradeCost)
{
break;
}
// ask if they want more
cout<<"Would you like to upgrade again (Yes or No)?
";
cin>>YorN;
}
}
void
Shrink(bool Player)
{
char YorN = 'y';
while(tolower(YorN) == 'y')
{
if(Players[Player].Territory > 0)
{
Players[Player].Money += 1;
Players[Player].Territory -= 1;
cout<<"You now have
"<<Players[Player].Territory
<<" States and
"<<Players[Player].Money<<"
money."<<endl;
cout<<"Would you like to buy another (YorN)?";
cin>>YorN;
}
else
{
cout<<"You are out of money!"<<endl;
break;
}
}
}
void
AddStuff(bool Player)
{
Players[Player].Armies += Players[Player].Territory;
Players[Player].Money += Players[Player].Territory;
WriteName(Player);
cout<<" now has "<<Players[Player].Armies
<<" armies and
"<<Players[Player].Money<<" money from
";
WriteName(Player);
cout<<"'s states."<<endl<<endl;
}
void
WriteName(bool C)
{
cout<<Players[C].Name;
}
void
Dead(bool Victim)
{
WriteName(Victim);
cout<<" you are dead!"<<endl;
WriteName(Victim == 0 ? 1 : 0);
cout<<" you have won!"<<endl<<endl;
}
public:
CCountries()
{
for(int Count = 0; Count < 2; Count ++)
{
cout<<"Player "<<Count + 1<<"
What is your name? ";
cin>>Players[Count].Name;
cout<<endl;
}
}
bool
Attack(bool Attacker, bool Victim)
{
int AttackerArmies; //This will hold the attacker's # of armies
int VictimArmies; //This will hold the Victim's # of armies
char YorN = 'Y';
while(toupper(YorN) == 'Y')
{
AttackerArmies = Players[Attacker].Armies -
(Players[Victim].Armies * Players[Victim].Technology /
Players[Attacker].Armies * Players[Attacker].Technology);
VictimArmies = Players[Victim].Armies - (Players[Attacker].Armies
* Players[Attacker].Technology / Players[Victim].Armies *
Players[Victim].Technology);
Players[Attacker].Armies = AttackerArmies;
Players[Victim].Armies = VictimArmies;
if(Players[Victim].Armies < 1)
{
Dead(Victim);
}
if(Players[Attacker].Armies < 1)
{
Dead(Attacker);
return FALSE; // Flag end of Game
}
if(Players[Victim].Armies < 1)
{
return FALSE; // Flag end of Game
}
Players[Victim].CountryLoss();
Players[Attacker].CountryLoss();
WriteName(Attacker);
cout<<" now has
"<<Players[Attacker].Armies<<"
armies."<<endl;
WriteName(Victim);
cout<<" now has
"<<Players[Victim].Armies<<"
armies."<<endl;
WriteName(Attacker);
cout<<", Would you like to attack again (Yes or No)?
";
cin>>YorN;
}
return TRUE; // Flag success
}
};
#endif
main5a.cpp:
//
main5a.cpp
//
This holds the main function for the first Conquest game of
//
the C++ Game Programmer's Tutorial.
//
Copyright (c) Forest J. Handford 1998
//////////////////////////////////////////////////////////////
#include
<iostream.h>
#include
<ctype.h>
#include
"Country5a.h"
void
main()
{
char
Answer; // This will hold a Y or N
cout<<endl<<"\tWelcome
to Conquest"<<endl
<<"\t\tBy Forest J. Handford"<<endl
<<"\t\tCopyright (c)
1998"<<endl<<endl;
CCountries Countries; // Create Countries
//
Loop till the Continue is false
for(bool
Player = 0,Continue = TRUE; Continue == TRUE; Player = (Player ==
1 ? 0 : 1))
{
Answer = 'l'; // set answer to not = 'p'
Countries.WriteName(Player); // Ask the player to sit
cout<<" take your seat."<<endl;
// Loop till player passes
while (tolower(Answer) != 'p' && Continue == TRUE)
{
cout<<"Would you like to Upgrade, Grow, Shrink, Attack
or Pass? ";
cin>>Answer;
if ( tolower(Answer) == 'a')
{
Continue = Countries.Attack(Player, Player == 1 ? 0 : 1);
if(Continue == TRUE)
{
cout<<"Would you like to Upgrade, Grow, Shrink or
Pass? ";
cin>>Answer;
if (tolower(Answer) == 'u')
{
Countries.Upgrade(Player);
cout<<"Would you like to Grow, Shrink or Pass? ";
cin>>Answer;
if(tolower(Answer) == 'g')
{
Countries.Players[Player].Grow();
}
else if(tolower(Answer) == 's')
{
Countries.Shrink(Player);
}
}
else if(tolower(Answer) == 'g')
{
Countries.Players[Player].Grow();
cout<<"Would you like to Upgrade or Pass? ";
cin>>Answer;
if(tolower(Answer) == 'u')
{
Countries.Upgrade(Player);
}
}
else if(tolower(Answer) == 's')
{
Countries.Shrink(Player);
cout<<"Would you like to Upgrade or Pass? ";
cin>>Answer;
if(tolower(Answer) == 'u')
{
Countries.Upgrade(Player);
}
}
Answer = 'p';
}
}
else if(tolower(Answer) == 'u')
{
Countries.Upgrade(Player);
cout<<"Would you like to Grow, Shrink or Pass? ";
cin>>Answer;
if(tolower(Answer) == 'g')
{
Countries.Players[Player].Grow();
}
else if(tolower(Answer) == 's')
{
Countries.Shrink(Player);
}
Answer = 'p';
}
else if(tolower(Answer) == 'g')
{
Countries.Players[Player].Grow();
cout<<"Would you like to Upgrade or Pass? ";
cin>>Answer;
if(tolower(Answer) == 'u')
{
Countries.Upgrade(Player);
}
Answer = 'p';
}
else if(tolower(Answer) == 's')
{
Countries.Shrink(Player);
cout<<"Would you like to Upgrade or Pass? ";
cin>>Answer;
if(tolower(Answer) == 'u')
{
Countries.Upgrade(Player);
}
Answer = 'p';
}
else if(tolower(Answer) == 'p')
{
Answer = 'p';
}
else
{
cout<<"Sorry, bad input . . . try
again"<<endl;
}
}
if(Continue == FALSE)
{
break;
}
Countries.AddStuff(Player);
}
//
Say Good bye.
cout<<"Thanks
for Playing and Good Bye."<<endl;
}
2 Player Conquest - I think that we have done enough for this chapter. In the next chapter you'll learn about pointers, queues, and destructors as we make a more advanced conquest game.