Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //This example program is created by thecplusplusuy for demonstration purposes. It's a simple mario like side-scroller game:
- //http://www.youtube.com/user/thecplusplusguy
- //Free source, modify if you want, LGPL licence (I guess), I would be happy, if you would not delete the link
- //so other people can see the tutorial
- //this file is game.cpp it's the 'main file', this put all of the files together
- #include "game.h"
- SDL_Rect baseclass::coord; //we have to actually reserve memory for the static SDL_Rect from the baseclass
- void game::showmessage(const char* c) //shows the message to the screen for a frame
- {
- SDL_Color color = {255,0,0}; //red color
- SDL_Surface* text=TTF_RenderText_Solid(font,c,color); //just create the text
- SDL_Rect tmprect={screen->w/2 - text->w/2,20}; //to the center in the x axis and 20 in the y
- SDL_BlitSurface(text,NULL,screen,&tmprect); //put it into the screen
- SDL_FreeSurface(text); //we don't need it anymore, so free it
- SDL_Flip(screen); //flip the screen, else we can't see it.
- }
- int game::showmenu(SDL_Surface* screen) //shows he menu
- {
- int x,y;
- bool run=true; //bool variable for the menu's for loop
- const int NUMMENU=2;//we have 2 menu item
- const char* array[NUMMENU] = {"Continue","Exit"}; //the label of these are these
- SDL_Surface* menu[NUMMENU];//we need surface for them
- bool selected[NUMMENU] = {0,0};//a boolean array for each menu item, true if it is selected
- SDL_Color colors[2] = {{255,255,255},{255,0,0}}; //white and red color
- for(int i=0;i<NUMMENU;i++)
- menu[i]=TTF_RenderText_Solid(font,array[i],colors[0]); //make all of the white menus
- SDL_Rect pos[NUMMENU]; //we store the position in here
- for(int i=0;i<NUMMENU;i++)
- {
- pos[i].x=screen->clip_rect.w/2-menu[i]->clip_rect.w/2; //put it approxemately to the center of the screen
- pos[i].y=screen->clip_rect.h/2+i*(menu[i]->clip_rect.h);
- }
- SDL_Event menuevent; //event
- SDL_Surface* alpha=SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,screen->w,screen->h,32,screen->format->Rmask,screen->format->Gmask,screen->format->Bmask,screen->format->Amask); //create a new layer
- SDL_FillRect(alpha,&screen->clip_rect,SDL_MapRGB(screen->format,0x00,0x00,0x00)); //which we fill with black
- SDL_SetAlpha(alpha,SDL_SRCALPHA,129); //and use it for alpha blending, because it's a cool effect
- SDL_BlitSurface(alpha,NULL,screen,NULL); //then show it
- SDL_FreeSurface(alpha); //we don't need it anymore
- while(run)
- {
- SDL_WaitEvent(&menuevent); //OK, I think, that's new, we'll wait until an event happened, if there is no event
- //the program will sleep in this function, so less CPU power is needed, we don't need
- //to regulate the FPS
- switch(menuevent.type)
- {
- case SDL_QUIT: //if we're exiting, than free the surfaces and exit
- for(int i=0;i<NUMMENU;i++)
- SDL_FreeSurface(menu[i]);
- return 1;
- case SDL_MOUSEMOTION: //if the mouse is moved
- x=menuevent.motion.x; //then get the coordinates
- y=menuevent.motion.y;
- for(int i=0;i<NUMMENU;i++) //we go throught all of the element
- { //and check if we are inside one of them
- if(x>=pos[i].x && x <= (pos[i].x + menu[i]->clip_rect.w) && y>=pos[i].y && y <= (pos[i].y + menu[i]->clip_rect.h))
- {
- if(!selected[i]) //if so, then we check that is it already selected
- {
- SDL_FreeSurface(menu[i]); //if not, then free the surface and make a red one
- menu[i]=TTF_RenderText_Solid(font,array[i],colors[1]);
- selected[i]=1; //and select the surface
- }
- }else{ //if we're not selecting one
- if(selected[i]) //we check, that is it selected
- {
- SDL_FreeSurface(menu[i]); //if so, then we delete and create a white one.
- menu[i]=TTF_RenderText_Solid(font,array[i],colors[0]);
- selected[i]=0; //and unselect it
- }
- }
- }
- break;
- case SDL_MOUSEBUTTONDOWN: //if the mouse button was pressed
- x=menuevent.button.x; //get the coordinates
- y=menuevent.button.y;
- for(int i=0;i<NUMMENU;i++) //do the same check
- {
- if(x>=pos[i].x && x <= (pos[i].x + menu[i]->clip_rect.w) && y>=pos[i].y && y <= (pos[i].y + menu[i]->clip_rect.h))
- {
- for(int j=0;j<NUMMENU;j++) //if we clicked one menuitem, we free the menus and return the number
- SDL_FreeSurface(menu[j]); //of the clicked menu
- return i;
- }
- }
- break;
- case SDL_KEYDOWN: //if we press a key
- if(menuevent.key.keysym.sym==SDLK_ESCAPE) //which escape
- {
- for(int i=0;i<NUMMENU;i++)
- SDL_FreeSurface(menu[i]);
- return 0; //than return to the game
- }
- break;
- }
- for(int i=0;i<NUMMENU;i++)
- SDL_BlitSurface(menu[i],NULL,screen,&pos[i]); //show the menu
- SDL_Flip(screen); //and actually show it in the screen
- }
- }
- game::game() //constructor
- {
- SDL_Init(SDL_INIT_EVERYTHING); //don't forget that, we have to initialize the SDL
- screen=SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,32,SDL_SWSURFACE); //init the screen, if you want fullscreen game, put
- // SDL_SWSURFACE|SDL_FULLSCREEN to the place of flags (4. parameter)
- //load the needed images
- block=load_image("blocks.bmp");
- background=load_image("endless.bmp");
- bul=load_image("bullet.bmp");
- ene=load_image("enemy.bmp");
- TTF_Init(); //Initialize the font
- font=TTF_OpenFont("air.ttf",20); //and load it
- //set the screen and the camera initialize position
- baseclass::coord.x=baseclass::coord.y=camera.x=camera.y=0;
- baseclass::coord.w=camera.w=SCREEN_WIDTH;
- baseclass::coord.h=camera.h=SCREEN_HEIGHT;
- direction[0]=direction[1]=0; //we don't go any direction when we start the game
- running=true; //bool for the main loop
- player1=new player(load_image("player.bmp")); //we create a new player
- //we set the initialize position of the finish, don't forget, if it's remain 0,0,50,50 after the loadmap than change it to the last block of the game
- //we haven't done that in the tutorial, but it's easy
- finish.x=0;
- finish.y=0;
- finish.w=50;
- finish.h=50;
- }
- game::~game() //destructor
- {
- //free the images
- SDL_FreeSurface(block);
- SDL_FreeSurface(background);
- SDL_FreeSurface(bul);
- delete player1; //delete the player
- for(int i=0;i<bullets.size();i++) //and the bullets
- delete bullets[i];
- for(int i=0;i<enemies.size();i++)//and the enemies
- delete enemies[i];
- //deinitialze things
- TTF_CloseFont(font);
- TTF_Quit();
- SDL_Quit();
- }
- SDL_Surface* game::load_image(const char* filename) //it will load an image
- {
- SDL_Surface* tmp=SDL_LoadBMP(filename); //load the BMP to a tmp variable
- SDL_Surface* tmp2=SDL_DisplayFormat(tmp); //change it to the format of the screen
- SDL_SetColorKey(tmp2,SDL_SRCCOLORKEY,SDL_MapRGB(screen->format,0x00,0xff,0xff)); //set the colorkey, so the 00ffff color is transparent
- SDL_FreeSurface(tmp); //free the tmp, we don't need it anymore
- return tmp2; //return
- }
- void game::handleEvents() //it will handle all of the event that occure
- {
- SDL_Event event;
- while(SDL_PollEvent(&event)) //while there are event in the queue, we get one, and delete it from the queue
- {
- switch(event.type)
- {
- case SDL_QUIT: //if quit, then we quit
- running=false;
- return;
- case SDL_KEYDOWN: //if a key is pressed
- switch(event.key.keysym.sym)
- {
- case SDLK_LEFT: //if it's the left key
- direction[0]=1; //then move left (now just set the boolean value)
- player1->setMoving(1); //and set the player to move
- break;
- case SDLK_RIGHT: //we do the same with the right key
- direction[1]=1;
- player1->setMoving(1);
- break;
- case SDLK_SPACE: //if space, than set the player to jump
- player1->setJump();
- break;
- case SDLK_f: //if f than shoot
- if(player1->getDirection()=='r') //if we face to the right, than we shoot the bullet from the right of the
- //surface (the player) with positive xvel
- bullets.push_back(new bullet(bul,player1->getRect()->x+player1->getRect()->w,player1->getRect()->y+15,5,0));
- else //else we do the opposite
- bullets.push_back(new bullet(bul,player1->getRect()->x,player1->getRect()->y+15,-5,0));
- break;
- case SDLK_ESCAPE: //if the escape is pressed
- int h=showmenu(screen); //than we show the menu
- if(h==1) //if we exited
- running=false; //than exit
- break;
- }
- break;
- case SDL_KEYUP: //if we relased a key
- switch(event.key.keysym.sym)
- {
- case SDLK_LEFT: //than we do the opposite then when we press a key
- direction[0]=0;
- player1->setMoving(0);
- break;
- case SDLK_RIGHT:
- direction[1]=0;
- player1->setMoving(0);
- break;
- }
- break;
- }
- }
- }
- //it is load the map from the file, in the file every number is corresponds to a 50x50 tile (image)
- void game::loadmap(const char* filename)
- {
- std::ifstream in(filename); //open the file
- if(!in.is_open()) //if we are not succeded
- {
- std::cout << "Problem with loading the file" << std::endl; //write out end exit
- return;
- }
- //read the width and the height from the file
- int width,height;
- in >> width;
- in >> height;
- int current;
- for(int i=0;i<height;i++) //with two for loops go throught the file
- {
- std::vector<int> vec; //every time we create a vector, and later we push that vector to the end of another vector
- //so it's like a 2D array (matrix)
- for(int j=0;j<width;j++)
- {
- if(in.eof()) //if we reached the file before we end with the read in
- {
- std::cout << "File end reached too soon" << std::endl; //write out and exit
- return;
- }
- in >> current; //read the current number
- if(current==-1) //if it's -1 than we put a new enemy to the position
- {
- enemies.push_back(new enemy(ene,j*TILE_SIZE,i*TILE_SIZE,1,0)); //because every tile is TILE_SIZE width and height, we can calculate
- //where they start by multiplying it with the i or j
- vec.push_back(0); //and we push back 0 to the vector (so nothing will be visible there)
- }else{
- if(current>=0 && current<=7) //if the current is greater or equal then 0 (so nothing) and less or equal than the max number of tiles
- //change the 7 to a bigger number, if you want to add more tile to the tiles.bmp image, don't forget 50x50 tiles
- {
- if(current==3) //if the current is 3
- {
- finish.x=j*50; //set the finish coordinate
- finish.y=i*50;
- }
- vec.push_back(current); //put the current into our matrix which represent the map in the game
- }else{
- vec.push_back(0); //if the tile number is not known than just push 0 (so nothing) in the current position
- }
- }
- }
- map.push_back(vec); //finally we push the vector to the end of the vector (dynamically allocated matrix :D)
- }
- in.close(); //close the file
- }
- void game::showmap() //this shows the map on the screen
- {
- //first of all calculate the first visible tile's coordinate, it's help, if you think throught with a few number, it's a bit harder to explain
- //but basically we just round down to the nearest number which can be divided by 50 and than divide it by 50 because we get the coordinate in
- //pixels, but we want the coordinate in 'tiles'
- int start=(baseclass::coord.x-(baseclass::coord.x%baseclass::TILE_SIZE))/baseclass::TILE_SIZE;
- //than the last visible coordinate (round up to the nearest 50)
- int end=(baseclass::coord.x+baseclass::coord.w+(baseclass::TILE_SIZE-(baseclass::coord.x+baseclass::coord.w)%baseclass::TILE_SIZE))/TILE_SIZE;
- if(start<0) //if the start tile is smaller than 0 just set it 0
- start=0;
- if(end>map[0].size()) //if the end tile is greater then the size of the map, just set back
- end=map[0].size();
- for(int i=0;i<map.size();i++) //we go throught all of the tiles
- for(int j=start;j<end;j++)
- if(map[i][j]!=0) //if it's not nothing
- {
- //we calculate the position in the blocks.bmp image
- SDL_Rect blockrect={(map[i][j]-1)*baseclass::TILE_SIZE,0,baseclass::TILE_SIZE, baseclass::TILE_SIZE};
- //and in the screen (so for example if the camera at 100px position and the tile is at 120px position, we show the tile at 20px position
- SDL_Rect destrect = {j*baseclass::TILE_SIZE-baseclass::coord.x,i*50};
- SDL_BlitSurface(block,&blockrect,screen,&destrect); //then blit it to the screen
- }
- }
- void game::start() //start the game
- {
- Uint32 start; //start time for the FPS regulation
- loadmap("map.map"); //load the map
- while(running)//while we not exited
- {
- start=SDL_GetTicks(); //get the start time
- handleEvents(); //handle the events
- if(direction[0]) //if we are pressing the left arrow key
- {
- player1->setDirection('l'); //set the direction of the player to left
- if(player1->getRect()->x > 0) //if it's greater than zero
- player1->setXvel(-1); //we move the player
- else{
- player1->setXvel(0); //else we move the camera instead and the player is unmoved
- camera.x--;
- baseclass::coord.x--;
- }
- if(camera.x<0) //we scroll the background and if it's less then 0
- camera.x=2000-SCREEN_WIDTH; //then we set it to background width-screen width
- //that's why it seems endless
- }else if(direction[1]) //if the right key is pressed
- {
- player1->setDirection('r'); //than we basically do the same things
- if(player1->getRect()->x < 80)
- player1->setXvel(1);
- else
- {
- player1->setXvel(0);
- camera.x++;
- baseclass::coord.x++;
- }
- if(camera.x>=2000-SCREEN_WIDTH)
- camera.x=0;
- }else
- player1->setXvel(0); //if none of the key is pressed, we are not moving
- //calculate the start and the end coordinate (see a little bit above)
- int str=(baseclass::coord.x-(baseclass::coord.x%baseclass::TILE_SIZE))/baseclass::TILE_SIZE;
- int end=(baseclass::coord.x+baseclass::coord.w+(baseclass::TILE_SIZE-(baseclass::coord.x+baseclass::coord.w)%baseclass::TILE_SIZE))/50;
- if(start<0)
- start=0;
- if(end>map[0].size())
- end=map[0].size();
- for(int i=0;i<map.size();i++) //go throuh the map
- for(int j=str;j<end;j++)
- {
- if(map[i][j]==0) //if it's nothing, we don't have to check collision
- continue;
- SDL_Rect destrect={j*50-baseclass::coord.x,i*50,50,50}; //calculate the relative coordinate to the screen (see above)
- for(int g=0;g<bullets.size();g++) //go throuht the bullets
- if(collision(bullets[g]->getRect(),&destrect)) //if the bullet collide with a tile
- {
- delete bullets[g]; //than delete it
- bullets.erase(bullets.begin()+g); //and delete from the vector as well
- }
- }
- for(int i=0;i<bullets.size();i++) //go through the bullets
- if(bullets[i]->getRect()->x >= screen->w || bullets[i]->getRect()->x <= 0) //and if it's outside of the screen
- {
- delete bullets[i]; //delete them
- bullets.erase(bullets.begin()+i);
- }
- for(int i=0;i<bullets.size();i++) //go through both enemies and bullets
- for(int j=0;j<enemies.size();j++)
- {
- SDL_Rect tmprect={enemies[j]->getRect()->x-baseclass::coord.x,enemies[j]->getRect()->y,40,40}; //calculate relative coordinates see above
- if(collision(&tmprect,bullets[i]->getRect())) //if one bullet collide with and enemy
- {
- delete enemies[j]; //delete the bullet and the enemy
- delete bullets[i];
- enemies.erase(enemies.begin()+j);
- bullets.erase(bullets.begin()+i);
- }
- }
- for(int j=0;j<enemies.size();j++) //go through the enemies
- {
- SDL_Rect tmprect={enemies[j]->getRect()->x-baseclass::coord.x,enemies[j]->getRect()->y,40,40}; //calculate relative coordinates see above
- if(collision(&baseclass::coord,enemies[j]->getRect())) //if the enemy is on the screen, (change thanks for TheAngelbrothers to point out a bug :D)
- {
- if(collision(&tmprect,player1->getRect())) //if we collide with an enemy
- {
- if(player1->getRect()->y+player1->getRect()->h>=enemies[j]->getRect()->y && player1->getRect()->y+player1->getRect()->h<=enemies[j]->getRect()->y+10) //if we are on the 'head' of the enemy
- {
- delete enemies[j]; //kill the enemy
- enemies.erase(enemies.begin()+j);
- }else{
- player1->setHealth(player1->getHealth()-1); //else decrease the health of the player with 1
- }
- }
- enemies[j]->move(map); //only move, when the enemy is on the screen. (change)
- }
- }
- //move everything
- player1->move(map);
- for(int i=0;i<bullets.size();i++)
- bullets[i]->move();
- //show everything
- SDL_BlitSurface(background,&camera,screen,NULL);
- showmap();
- player1->show(screen);
- for(int i=0;i<bullets.size();i++)
- bullets[i]->show(screen);
- for(int i=0;i<enemies.size();i++)
- enemies[i]->show(screen);
- SDL_Flip(screen); //put it the the actual screen
- if(player1->getHealth()<=0 || player1->getRect()->y >=screen->h) //if the health of the player is 0 or it's under the screen
- {
- running=false; //kill it
- //if you want things like reload the map, than just set back every variable to the initialize state, and don't set the running=false
- showmessage("game over");
- SDL_Delay(1000); //we delay, so we can see the message
- }
- SDL_Rect tmprect = {finish.x-coord.x,finish.y,50,50}; //we have to calculate relative coordinates to the screen (see above)
- if(collision(player1->getRect(),&tmprect)) //if we collide with the communist flag
- {
- running=false;
- showmessage("You Win"); //if you want to load the next map, I recommend you, to read the maps in the constructor from game.dat
- //to an array of strings and make a current value, which contain the current map, and here check, that the max maps number is greater than
- //the current, if so, increase the current and set back the values to the initialize state, and call the load map with the current string
- SDL_Delay(1000);
- }
- if(1000/30>(SDL_GetTicks()-start)) //if we are achive this point too early
- SDL_Delay(1000/30-(SDL_GetTicks()-start)); //than we delay a little bit
- }
- }
- //that's all :D
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement