< In the previous tutorial i didn't made use of part of the features that come with C++ : classes, so it's time to use them to define and store data about our hero and the map, into the player class i want to define the player creation process, finally i want to create a Main Menu for the game...>
I think I'm very ambitious with that post, but the objectives are:
- Create at least two classes: cplayer and cmap
- Define a Player creation process
- Create a Main Menu..
First let's start creating two classes: cplayer and cmap, to do that code::blocks has an assistant to design classes, so resuming from the code in the previous post we should select "File" > "New" > "Class":
In the class name , write "cplayer", and then mark "Header and implementation shall be in the same folder", then press "Create":
Select "Yes" to add the files to the project and...
Press ok, so we will use files both to debug and compile the release project, we need to create a second class "cmap", so just repeat the steps,and save the project.
Now let's start modifying the cmap class, we have two files cmap.h (header) and cmap.cpp (implementation), in the header we are going to define the variables and functions , so we are going to move the Uint8 Map[x][y][layer] to the class, we need too a pair of functions to get and set the values in the map array, so our cmap header will finally be:
#ifndef CMAP_H #define CMAP_H #include//SDL library class cmap { public: cmap(); virtual ~cmap(); Uint8 GetTile(int x, int y, int layer); //Get tile value void SetTile(int x, int y, int layer, Uint8 Tile);//Set tile Value protected: private: Uint8 Map[50][50][3]; //The map, now it has three layers int x,y; }; #endif // CMAP_H
Now we have to implement the functions in cmap.cpp:
<cmap::cmap(creator)>
cmap::cmap() { //ctor for (x=0;x<50;x++){ // Map size 50x50 tiles: 5000 x 5000 pixels for (y=0;y<50;y++){ Map[x][y][0]=0; //clean the map layer 1 so everything is "0" >> "sand" Map[x][y][1]=63; //clean the map layer 2 so everything is "63" >> nothing Map[x][y][2]=63; //clean the map layer 3 so everything is "63" >> nothing };//end y for };//end x for for (x=2;x<5;x++){ for (y=2;y<7;y++){ Map[x][y][0]=2; //A lake Map[x+4][y][0]=1; //Grass.. };//end y for };//end x for for (x=1;x<5;x++){ Map[x][2][1]=8; //Trees Map[x][3][1]=10; //A road }; // end for x Map[5][3][1]=12; //A road Map[5][2][1]=14; //A road Map[6][2][1]=10; //A road Map[6][3][1]=9; //A volcano Map[3][3][2]=25; //Coins Map[4][3][2]=25; //More coins for (x=0;x<50;x++){ Map[x][0][0]=2; Map[x][49][0]=2; Map[0][x][0]=2; Map[49][x][0]=2; }; }
<cmap::SetTile>
void cmap::SetTile(int x, int y, int layer, Uint8 Tile) //Set tile value { Map[x][y][layer]=Tile; }
<cmap::GetTile>
Uint8 cmap::GetTile(int x, int y, int layer) //Get tile value { return Map[x][y][layer]; }
That's it! Now we have a simple class that will store the map data, notice that i've inserted into the creator the code to define a map.. it's not the better way to do that , but i wanted to show how we can separate code into classes , now we need to change a few things in the main program to use the new class, first we have to insert into rpg.cpp:
#include "cmap.h" // The Map class
So we actually use the class, now let's create a variable to use the map:
cmap mymap; // Our map class
Then i will erase the old Uint8 Map definition and the old map initialization, now everything is inside mymap, finally we have to update the map blitting functions to draw the map:
myengine.BlitTileset(x *myengine.TileSize-Camera.x,y *myengine.TileSize-Camera.y, mymap.GetTile(x,y,0)); //Display map, layer 1 myengine.BlitTileset(x *myengine.TileSize-Camera.x,y *myengine.TileSize-Camera.y, mymap.GetTile(x,y,1));//Display map, layer 2 myengine.BlitTileset(x *myengine.TileSize-Camera.x,y *myengine.TileSize-Camera.y, mymap.GetTile(x,y,2));//Display map, layer 3
Notice before i used Map[x][y][layer], now mymap.GetTile(x,y,layer), time to "Build and Run" the project to see what happens, if you have followed all the steps, you should get the same results than in the previous post, it's ok because we have just changed a variable with a class.
We have to create the player class too, so let's move the PcX,PcY and PcSpeed to the cplayer class:
<cplayer.h>
#ifndef CPLAYER_H #define CPLAYER_H class cplayer { public: cplayer(); //Creator virtual ~cplayer(); //Destructor void SetX(int x);// Set player x position void SetY(int y);//Set player y position void SetSpeed(int speed);//Set Player speed void SetName(const char* name);//Set Player's name int GetX(); // Get player x position int GetY(); // Get player y position int GetSpeed();// Get player speed const char* GetName(); //Get player name protected: private: int X,Y,Speed; //X and y position, player speed const char* Name; // Player's name }; #endif // CPLAYER_H
I've added too the player's name variable, and the functions to get/set the values:
<cplayer.cpp>
cplayer::cplayer() { //ctor X=0; Y=0; Speed=0; Name="No Name"; } cplayer::~cplayer() { //dtor } void cplayer::SetX(int x) { X=x; } void cplayer::SetY(int y) { Y=y; } void cplayer::SetSpeed(int speed) { Speed=speed; } int cplayer::GetX() { return X; } int cplayer::GetY() { return Y; } int cplayer::GetSpeed() { return Speed; } void cplayer::SetName(const char* name) { Name = name; } const char* cplayer::GetName() { return Name; }
Now we return again to rpg.cpp, we have to add:
#include "cplayer.h" // The player class
So we actually use the class, now let's create a variable to use the player:
cplayer Hero; // Our player class
And initialize the values:
Hero.SetX(110); //starting player's x position Hero.SetY(310); //starting player's y position Hero.SetSpeed(5); //starting player's speed Hero.SetName("The Karbarian"); //Player's name
Keyboard input changes, to use the player's class:
if (keys[SDLK_UP])Hero.SetY(Hero.GetY() - Hero.GetSpeed()); if (Hero.GetY()<1)Hero.SetY(1); while (Hero.GetY() <= (Camera.y )) Camera.y-=1; if (keys[SDLK_DOWN] ) Hero.SetY(Hero.GetY() + Hero.GetSpeed()); if (Hero.GetY()>4900)Hero.SetY(4900); while (Hero.GetY() +100 >= (Camera.y + Camera.h ) )Camera.y+=1; if (keys[SDLK_LEFT] ) Hero.SetX(Hero.GetX() - Hero.GetSpeed()); if (Hero.GetX()<1)Hero.SetX(1); while (Hero.GetX() <= (Camera.x )) Camera.x-=1; if (keys[SDLK_RIGHT] ) Hero.SetX(Hero.GetX() + Hero.GetSpeed()); if (Hero.GetX()>4900)Hero.SetX(4900); while (Hero.GetX() +100 >= (Camera.x + Camera.w ) )Camera.x+=1;
And finally the blitting functions need to be adapted too so they use the player class:
for (x=Camera.x/100 ;x<=Camera.x/100 + (Camera.w/100);x++){//Process map for (y=Camera.y/100 ;y<=Camera.y/100 + (Camera.h/100);y++){ myengine.BlitTileset(x *myengine.TileSize-Camera.x,y *myengine.TileSize-Camera.y,
mymap.GetTile(x,y,0)); //Display map, layer 1 myengine.BlitTileset(x *myengine.TileSize-Camera.x,y *myengine.TileSize-Camera.y,
mymap.GetTile(x,y,1));//Display map, layer 2 myengine.BlitTileset(x *myengine.TileSize-Camera.x,y *myengine.TileSize-Camera.y,
mymap.GetTile(x,y,2));//Display map, layer 3 }; }; myengine.BlitTileset(Hero.GetX() - Camera.x ,Hero.GetY() -Camera.y ,16); //Display player
Well, our player has a name and we want to show it, so that's what i'm going to make here:
mycolor = {0, 0, 0 }; myengine.SetTextColor( mycolor); myengine.TextOut(Hero.GetX() - Camera.x +50 ,Hero.GetY() -Camera.y ,Hero.GetName());
We display player's name at his right side, it can be easily modified so the name moves to another side...
<update>
Post is getting way too big, I'm going to split it so it's going to be easier to follow..
See you