Monday, January 20, 2014

BGI Space Invader - A Game

This is college C++ project ( Done in two member team).

The game is well know game - Space Invader. We implemented during our second semester of Bachelor of Engineering (Computer Science). We used simple BGI graphics library.

#include <stdio.h>
#include <iostream.h>
#include <conio.h>
#include <graphics.h>
#include <dos.h>                //for delay()
#include <stdlib.h>  //for malloc()
#include <ctype.h>  //for tolower()
#include <bios.h>
#include <string.h>
#include <iomanip.h>

#define SPACE 0x3920
#define ESC 0x11b
#define LEFT 0x4b00
#define RIGHT 0x4d00


#define DELAYSHOT 15
#define DELAYSHOTBYALIENS 10
//int gameLevel = 1;
int gameSpeed = 1;
int score;


class Alien;

class shot
{
 private:
  int centerX, centerY; //coordinate positions of shots

  //for the capture of bulletImage
  unsigned int shotSize;
  void *shotBuffer;

  int shotsLife;     //to determine if bullet exists or not

 public:
  shot(){};
  shot(int , int );
  void drawAndCapture();
  inline int deadAlive();       //returns 0 if bullet is destroyed else returns 1
  void deleteShots();
  void move();
  void checkForHit(Alien &);      //didn't work when passed by value
};


class ship
{
 private:

  int x;
  void *shipBuff;
  unsigned int shipSize;
  int shipLife;
 public:
  int left, top, right, bottom,length;

 public:
  ship(){}
  ship(int ,int ,int,int);
  void draw();
  void capture();
  void deleteShip();
  inline int getShipLife();
  void checkForCollisionWithAliens(Alien &);
  void move();

};


class shotByAliens
{
 private:
  int centerX, centerY; //position of the shotByAliens
  int shotByAliensLife; //shot exists if its value is 1

  //to capture image
  void *shotByAliensBuffer;
  unsigned int shotByAliensSize;

 public:
  shotByAliens();


  shotByAliens(Alien);
  void drawAndCapture();
  void deleteShotByAliens();
  inline int getShotByAliensLife();
  void move();
  void checkForHit(ship &);



};


class Alien
{
 private:
  int centerX,centerY; //center coordinates of each alien

  //for capturing image
  void *alienBuff;
  unsigned int imgSize;

  //for deleting aliens
  void *alienBuff2;
  unsigned int imgSize2;

  int toDelete;    //if its value is 1, allows to delete upward aliens
  int n;          //its value used to skip erasing of
    //upward aliens in very first movement towards right
  int count;     //determines how much has the aliens have moved
  int dir;       //dtermines in which direction should the aliens move

  int left,top;
  int aliensLife;   //determines whether the aliens are alive or killed

 public:
  Alien();
  void friend shot::checkForHit(Alien &);
  friend shotByAliens::shotByAliens(Alien);
  void friend ship::checkForCollisionWithAliens(Alien &);
  void assignCoordinate(int , int ); //assigns initial center coordinates to each aliens
  void resetDatas();
  void drawAlien(int , int , int );
  void capture();//capture the image of aliens
  void capture2();  //capture the blank space
  void move(); //move the aliens left and right
  void deleteAlien();
  inline int getAliensLife();
  inline int getCenterY(); //get xcoordinate of the alien
};


class checkForLevelClear
{
 public:
  int check(Alien aliens[4][4]);
};

class welcome
{
 public:
  void display();
};



class gameover
{
 public:
  void display();
};


class completionOfLevel
{
 public:
  void display();

};

class congratulations
{
 public:
  void display();
};


class drawGameField
{
 public:
  void draw();
};




///////////////////////////////////universal variables

shot *shots[10];
ship ship1(300,440,350,450);
shotByAliens *alienShot[40];
gameover gameOver;

//////////////////////////////FUNCTIONS DEFINITIONS FOR CLASS SHOT

shot::shot(int x, int y)
{
 centerX = x;
 centerY = y;
 shotsLife = 1;     //bullet comes to life
}

void shot::drawAndCapture()
{
 setcolor(4);
 setfillstyle(SOLID_FILL,6);
 fillellipse(centerX,centerY,3,3);

 //capture bullet image
 shotSize = imagesize(centerX - 5,centerY - 5, centerX + 5, centerY + 5);
 shotBuffer = malloc(shotSize);
 getimage((centerX - 4), (centerY - 4), (centerX + 4), (centerY + 4), shotBuffer);
}

int shot::deadAlive()       //returns 0 if bullet is destroyed else returns 1
{
 return shotsLife;
}

void shot::deleteShots()
{
 putimage(centerX-4, centerY-4, shotBuffer, XOR_PUT);   //to erase residue drawing of the bullet
 shotsLife = 0;       //indicates bullet is destroyed
}

void shot::move()
{
 if(shotsLife == 1)
 {
  if(centerY > 55)
  {
   putimage(centerX-4, centerY-4, shotBuffer, XOR_PUT);
   centerY-=5;
   putimage(centerX-4, centerY-4, shotBuffer, XOR_PUT);
  }

  if(centerY <= 55)
  {
   //putimage(centerX-4, centerY-4, shotBuffer, XOR_PUT);
   deleteShots();
  }
 }


}

void shot::checkForHit(Alien &alien)
{
 if(alien.aliensLife == 1)  //to hit alien, alien itself should be alive
 {
  if(centerX > alien.centerX-15 && centerX < alien.centerX+15 && centerY < alien.centerY+15 && centerY > alien.centerY-15)
  {
   this->deleteShots();
   alien.deleteAlien();
   score += 10*gameSpeed;
  }
 }
}



/////////////////////////////FUNCTIONS DEFINITIONS FOR CLASS SHIP


ship::ship(int leftX, int topY, int rightX, int bottomY)
{
 left = leftX;
 top = topY;
 right = rightX;
 bottom = bottomY;
 length = right - left;
 shipLife = 1;
}

void ship::draw()
{
 setcolor(14);
 rectangle(left,top,right,bottom);
 setfillstyle(SOLID_FILL,13);
 bar(left, top, right, bottom);

}

void ship::capture()
{
 shipSize = imagesize(left, top, right, bottom);
 shipBuff = malloc(shipSize);
 getimage(left, top, right, bottom, shipBuff);
}

void ship::deleteShip()
{
 putimage(left,top,shipBuff,XOR_PUT);
 shipLife = 0;
}

int ship::getShipLife()
{
 return shipLife;
}

void ship::checkForCollisionWithAliens(Alien &alien)
{
 if(shipLife == 1 && alien.aliensLife == 1)
 {
  if(alien.centerX+15 >= left && alien.centerX-15 <= right && alien.centerY +15 >= top)
  {
   ship1.deleteShip();
        //gameOver.display();
        //closegraph();
        //exit(0);
  }
 }
}

void ship::move()
{
 if(shipLife == 1)
 {
  static delayShot=DELAYSHOT;   //this value will be used to
      //delay the shot after a preceeding shot

  if(kbhit())
  {
   x =  _bios_keybrd(_KEYBRD_READ);


   if(x == RIGHT && left < (610 - length))
   {
    putimage(left,top, shipBuff, XOR_PUT);
    putimage(left+10, top, shipBuff, XOR_PUT);
    left+=10;
    right+=10;
   }

   else if(x == LEFT && left > 90)
   {
    putimage(left,top, shipBuff, XOR_PUT);
    putimage(left-10,top, shipBuff, XOR_PUT);
    left-=10;
    right-=10;
   }

   else if(tolower((char)x) == 'z')
   {

    if(delayShot == DELAYSHOT)    //shot only after delayShot
         //has gained value 20 from 0
    {
     static int recycleShots=0;      //
     shots[recycleShots] = new shot((left+(right-left)/2) , top-20);
     //cout<<"\a";
     shots[recycleShots]->drawAndCapture();
     recycleShots++;

     if(recycleShots == 9)     //recycleShots =9 means
          //all available shots are used up
      recycleShots=0;      //recycle the shots form beginning
     delayShot = 0;  //it will stop the shot for a
         //moment till it becomes 20
    }

   }

   if(x == ESC)
   {
    closegraph();
    exit (0);
   }

  } //end of if(kbhit())

  if(delayShot <DELAYSHOT)
   delayShot++;

 }     //end if(shipLife == 1)
}//end move()




//////////////////////////FUNCTIONS DEFINITIONS OF CLASS SHOTBYALIENS

shotByAliens::shotByAliens():centerX(getmaxx()),centerY(getmaxy()){}

shotByAliens::shotByAliens(Alien alien)
{
 centerX = alien.centerX; //assigns x coordinate
     //of alien to shot
 centerY = alien.centerY+20; //assigns y coordinate
     //of alien to shot
 shotByAliensLife = 1; //bring the shot to life
}

void shotByAliens::drawAndCapture()
{
 setcolor(4);
 setfillstyle(SOLID_FILL,11);
 fillellipse(centerX,centerY,3,3);

 //capture bullet image
 shotByAliensSize = imagesize(centerX - 5,centerY - 5, centerX + 5, centerY + 5);
 shotByAliensBuffer = malloc(shotByAliensSize);
 getimage((centerX - 4), (centerY - 4), (centerX + 4), (centerY + 4), shotByAliensBuffer);
}

void shotByAliens::deleteShotByAliens()
{
 putimage(centerX-4, centerY-4, shotByAliensBuffer, XOR_PUT);   //to erase residue drawing of the bullet
 shotByAliensLife = 0;       //indicates shot is destroyed
}

int shotByAliens::getShotByAliensLife()
{
 return shotByAliensLife;
}

void shotByAliens::move()
{
 if(shotByAliensLife == 1)
 {
  if(centerY < 445)
  {
   putimage(centerX-4, centerY-4, shotByAliensBuffer, XOR_PUT);
   centerY += 5;
   putimage(centerX-4, centerY-4, shotByAliensBuffer, XOR_PUT);
  }

  if(centerY >= 445)
  {
   //putimage(centerX-4, centerY-4, shotByAliensBuffer, XOR_PUT);
   deleteShotByAliens();
  }
 }


}

void shotByAliens::checkForHit(ship &ship1)
{
 if(centerX > ship1.left-3 && centerX < ship1.right+3 && centerY+3 >= ship1.top)
 {
  this->deleteShotByAliens();
  ship1.deleteShip();
 }
}




///////////////////////////////FUNCTIONS DEFINITIONS FOR CLASS ALIEN

Alien::Alien():toDelete(1),n(1),count(0),dir(1),aliensLife(1){}

void Alien::assignCoordinate(int x, int y) //assigns initial center coordinates to each aliens
{
 centerX = x;
 centerY = y;
 left = centerX -16;
 top = centerY -16;
}

void Alien::resetDatas()
{
 toDelete = 1;
 n = 1;
 count = 0;
 dir = 1;
 aliensLife = 1;
}

void Alien::drawAlien(int x, int y, int r)
{
 setcolor(14);
 setfillstyle(SOLID_FILL , BLUE);
 fillellipse(x, y, r, r);
 setfillstyle(SOLID_FILL , BLACK);
 fillellipse(x-5, y-5, 3, 2);
 setfillstyle(SOLID_FILL , BLACK);
 fillellipse(x+5, y-5, 3, 2);
 setfillstyle(SOLID_FILL , BLACK);
 fillellipse(x, y+5, 5, 2);
}

void Alien::capture()//capture the image of aliens
{
 imgSize = imagesize(centerX-16, centerY-16, centerX+16, centerY+16);
 alienBuff = malloc(imgSize);
 getimage(centerX-16, centerY-16, centerX+16, centerY+16, alienBuff);
}

void Alien::capture2()  //capture the blank space
{
 imgSize2 = imagesize(centerX-16, centerY-16, centerX+16, centerY+16);
 alienBuff2 = malloc(imgSize2);
 getimage(centerX-16, centerY-16, centerX+16, centerY+16, alienBuff2);
}

void Alien::move() //move the aliens left and right
{
 //if(aliensLife == 1)
 //{
  static int distance;
   if(gameSpeed == 1)
    distance=200;
   else if(gameSpeed == 2)
    distance = 100;
   else
    distance=66;


  if(dir == 1)        //move the aliens towards right
  {
   if(n > 1)      //will not be executed at first time because n =1
   {
    if(toDelete == 1)
    {
     if(aliensLife == 1)
      putimage(left, top-40, alienBuff, XOR_PUT);  //deletes upward aliens
     else
      putimage(left, top-40, alienBuff2, XOR_PUT);

     toDelete = 0;
     centerY += 40; //try
    }  //end of if(toDelete ==1)
   }    //end of if(n>1)

   left+= gameSpeed;

   if(aliensLife == 1)
   {
    putimage(left, top, alienBuff, XOR_PUT);      //creates new aliens  (may change)
    putimage(left-gameSpeed, top, alienBuff, XOR_PUT);    //deletes   (may change)
   }
   else
   {
    putimage(left, top, alienBuff2, XOR_PUT);
    putimage(left-gameSpeed, top, alienBuff2, XOR_PUT);
   }



   centerX+= gameSpeed;         //coordinate of each alien is changed
       //every time they move
   count++;
   if(count == distance)
   {
    dir =0;
    top+=40;
    //centerY+=40;      //change of coordinate of alien
    count = 0;
    toDelete = 1;
    if(aliensLife == 1)
     putimage(left, top, alienBuff, XOR_PUT);    //creates new aliens at down position
             //which will be erased by putimage() function
    else
     putimage(left, top, alienBuff2, XOR_PUT);



    if(n == 1)
     n++;      //to denote that first right movement is escaped

   }        //end of if(count == 200)

  }     //end of if(dir ==1)

  else   //move the aliens towards left
  {
   if(toDelete == 1)
   {
    if(aliensLife == 1)
     putimage(left, top-40, alienBuff, XOR_PUT);
    else
     putimage(left, top-40, alienBuff2, XOR_PUT);


    toDelete = 0;
    centerY+=40; //try
   }     //end of if(toDelete == 1)

   left-= gameSpeed;

   if(aliensLife == 1)
   {
    putimage(left , top , alienBuff, XOR_PUT);
    putimage(left+gameSpeed, top, alienBuff, XOR_PUT);
   }
   else
   {
    putimage(left, top, alienBuff2, XOR_PUT);
    putimage(left+gameSpeed, top, alienBuff2, XOR_PUT);
   }



   centerX-= gameSpeed;

   count++;
   if(count == distance)
   {
    dir =1;
    top += 40;
    //centerY += 40;
    count = 0;
    //n = 3;
    toDelete = 1;
    if(aliensLife == 1)
     putimage(left , top , alienBuff, XOR_PUT);       //creates new aliens at down position
           //which will be erased by putimage() function
    else
     putimage(left, top, alienBuff2, XOR_PUT);

   }     //end of if(count ==distance)
   }   //end of else
 //}     //end of if(aliensLife == 1)
}  // end of function move()


void Alien::deleteAlien()
{
 putimage(left , top , alienBuff, XOR_PUT);
 aliensLife = 0;
}

int Alien::getAliensLife()
{
 return aliensLife;
}

int Alien::getCenterY()
{
 return centerY;
}


/////////////////////FUNCTION DEFINITIONS FOR CLASS CHECKFORLEVELCLEAR

int checkForLevelClear::check(Alien aliens[4][4])
{
 int clear = 1;
 for(int j=0; j<4; j++)
 {
  for(int i=0; i<4; i++)
  {
   if(aliens[i][j].getAliensLife())
   {
    clear = 0;
    break;
   }
  }
  if(clear == 0)
   break;
 }
 return clear;
}


////////////////////////////////FUCNTION DEFINITIONS FOR CLASS WELCOME

void welcome::display()
{
 setcolor(11);
 delay(1500);
 settextstyle(0,0,2);outtextxy(40,60,"SABBIR KUMAR MANANDHAR");
 setcolor(10);outtextxy(410,60,"[062-BCT-537]");
 setcolor(11);
 settextstyle(0,0,2);outtextxy(105,120,"SUVASH SEDHAIN");
 setcolor(10);outtextxy(350,120,"[062-BCT-548]");
 delay(250);
 setcolor(12);
 settextstyle(0,0,3);outtextxy(230,200,"Presents");
 settextstyle(0,0,3);outtextxy(125,240,"A Project on C++");
 delay(250);

 while(!kbhit())
 {
  int i=rand();
  setcolor(i);
  settextstyle(0,0,8);outtextxy(160,300,"SPACE");
  settextstyle(0,0,8);outtextxy(100,370,"INVADER");
 }

 cleardevice();
 setcolor(13);

 settextstyle(0,0,2);
 int ch;
 while(ch != SPACE)
 {
  outtextxy(100,300,"Press SPACEBAR to START...");
  getch();
  ch = _bios_keybrd(_KEYBRD_READ);
 }
 cleardevice();
}



///////////////////////////////FUNCTION DEFINITIONS OF CLASS GAMEOVER

void gameover::display()
{
 cleardevice();
 setcolor(11);
 settextstyle(0,0,4);
 outtextxy(50,150,"You Lost the game!");

 char stringScore[5];
 itoa(score,stringScore,10);      //itoa() converts integer to string
 setcolor(13);
 settextstyle(0,0,2);
 outtextxy(130,300,"Your Total Score is");
 outtextxy(460,300,stringScore);


 setcolor(10);
 settextstyle(0,0,2);
 //outtextxy(120,400,"Want to play again? (y/n)");
 outtextxy(65,450,"press the ESC key to continue....");
 int ch;
 while(ch != ESC)
 {
  ch = _bios_keybrd(_KEYBRD_READ);
 }
 cleardevice();
}


/////////////////////FUNCTIONS DEFINITIONS FOR CLASS COMPLETIONOFLEVEL

void completionOfLevel::display()
{
 char levelOne[] = "Level 1 completed!";
 char levelTwo[] = "Level 2 completed!";
 cleardevice();
 setcolor(14);
 settextstyle(0,0,4);
 if(gameSpeed-1 == 1)
  outtextxy(60,150,levelOne);
 else
  outtextxy(60,150,levelTwo);

 char stringScore[5];
 itoa(score,stringScore,10);      //itoa() converts integer to string
 setcolor(13);
 settextstyle(0,0,2);
 outtextxy(115,300,"Your Score till now is");
 outtextxy(475,300,stringScore);

 setcolor(10);
 settextstyle(0,0,2);

 int ch;
 while(ch != SPACE)
 {
  outtextxy(20,450,"Press SPACEBAR to continue next level");
  ch = _bios_keybrd(_KEYBRD_READ);
 }
 cleardevice();
}



///////////////////////////FUCNTIONS DEFINITIONS FOR CLASS CONGRATULATIONS

void congratulations::display()
{
 cleardevice();
 setcolor(14);
 settextstyle(0,0,4);
 outtextxy(80,110,"CONGRATULATIONS!");
 setcolor(10);
 settextstyle(0,0,2);
 outtextxy(110,215,"You have completed the game!");


 char stringScore[5];
 itoa(score,stringScore,10);      //itoa() converts integer to string
 setcolor(13);
 settextstyle(0,0,2);
 outtextxy(130,300,"Your Total Score is");
 outtextxy(460,300,stringScore);

 setcolor(12);
 settextstyle(0,0,2);
 outtextxy(100,450,"press ESC to continue.......");

 int ch;
 while(ch != ESC)
 {
  ch = _bios_keybrd(_KEYBRD_READ);
 }

 cleardevice();
}


////////////////////////////FUNCTIONS DEFINITIONS FOR CLASS DRAWGAMEFIELD

void drawGameField::draw()
{
 setfillstyle(SOLID_FILL,4);
 bar(0, 0, getmaxx(), 50);
 bar(0, 452, getmaxx(), getmaxy());
 setfillstyle(SOLID_FILL,GREEN);
 bar(0, 0, 80,getmaxy());
 bar(620, 0, getmaxx(), getmaxy());
 setcolor(YELLOW);
 line_widths(3);
 rectangle(80, 0, 620, getmaxy());
 settextstyle(0,0,2);
 setcolor(14);
 outtextxy(200,20,"Press ESC to quit...");

 char level[6];
 settextstyle(0,1,3);
 setcolor(14);
 outtextxy(50,200,"LEVEL");
 if(gameSpeed == 1)
  strcpy(level,"ONE");
 else if(gameSpeed == 2)
  strcpy(level,"TWO");
 else
  strcpy(level,"THREE");
 outtextxy(50,70,level);

}



////////////////////////////////////////////////////////////////////////

void reassignLifeToAliens(Alien aliens[4][4])
{
 for(int j=0; j<4; j++)
 {
  for(int i=0; i<4; i++)
   aliens[i][j].resetDatas();
 }
}



void startGraph()
{
 int driver = DETECT, mode;
 initgraph( &driver , &mode , "c:\\tc\\bgi");
}

int main()
{
 startGraph();
 drawGameField gameField;
 completionOfLevel levelClear;
 congratulations congrats;
 checkForLevelClear clearOrNot;

 Alien aliens[4][4];

 welcome welCome;
 welCome.display();

 do
 {

  gameField.draw();

  ship1.draw();
  if(gameSpeed == 1)
   ship1.capture();

  for(int j=0 ; j<4 ; j++)
  {
   for(int i=0 ; i<4 ; i++)
   {
    aliens[i][j].assignCoordinate(100+100*i , 70+40*j);
   }
  }

  if(gameSpeed == 1)
  {
   for(j=0; j<4; j++)
   {
    for(int i=0; i<4; i++)
     aliens[i][j].capture2();
   }
  }


  for(j=0 ; j<4 ; j++)
  {
   for(int i=0 ; i<4 ; i++)
   {
    aliens[i][j].drawAlien(100+100*i , 70+40*j , 15);
   }
  }

  if(gameSpeed == 1)
  {
   for(j=0; j<4; j++)
   {
    for(int i=0; i<4; i++)
     aliens[i][j].capture();
   }
  }


  while(1)
  {
   ship1.move();     //move ship

   for(int j=0; j<4; j++)   //move aliens
   {
    for(int i=0; i<4; i++)
     aliens[i][j].move();
   }

   for(j =0; j<4; j++)   //check collision of ship and aliens
   {
    for(int i=0; i<4; i++)
     ship1.checkForCollisionWithAliens(aliens[i][j]);
   }

   for(int i=0; i<10 ; i++)     //move bullets and check for hit with aliens
   {
    if(shots[i]->deadAlive())
    {
     shots[i]->move();
     for(int j=0; j<4; j++)
     {
      for(int i2=0; i2<4; i2++)
       shots[i] -> checkForHit(aliens[i2][j]);
     }
    }
   }


   static int x,y;
   static int delayShotByAliens = DELAYSHOTBYALIENS;
   x = random(4);
   y = random(4);


   static int recycleAlienShots=0;

   if(recycleAlienShots == 39)     //recycleShots =9 means
       //all available shots are used up
    recycleAlienShots=0;      //recycle the shots form beginning

   if(delayShotByAliens == DELAYSHOTBYALIENS)
   {
    if(aliens[x][y].getAliensLife() && aliens[x][y].getCenterY()<430)   //aliens will shoot only
             //if aliens are alive and
             //aliens are above 330 vertically
    {
     alienShot[recycleAlienShots] = new shotByAliens(aliens[x][y]);
     alienShot[recycleAlienShots]->drawAndCapture();
     recycleAlienShots++;
    }
   }

   for(i=0; i<40 ; i++)    //move the shots by aliens
   {
    if(alienShot[i]->getShotByAliensLife())
     alienShot[i]->move();
   }


   if(delayShotByAliens == DELAYSHOTBYALIENS)
    delayShotByAliens = 0;

   delayShotByAliens++;

   for(i=0; i<40 ; i++) //check for hit with ship
   {
    if(alienShot[i]->getShotByAliensLife() && ship1.getShipLife())
     alienShot[i]->checkForHit(ship1);
   }

   for(i=0;i<4; i++)   //end the game if the alive aliens reach the bottom
   {
    for(int j=0; j<4; j++)
    {
     if(aliens[i][j].getAliensLife() && aliens[i][j].getCenterY()>430)
     {
      cout<<"\a";
      gameOver.display();
      exit(0);
     }
    }
   }


   if(!ship1.getShipLife())      //game is over when ship is destroyed by
       //alienshot or alien itself
   {
    cout<<"\a";
    gameOver.display();
    closegraph();
    exit(0);

   }

   if(clearOrNot.check(aliens))    //level clear or not
   {
    gameSpeed ++;
    reassignLifeToAliens(aliens);

    for(int i=0; i<40; i++)
     alienShot[i]->deleteShotByAliens();

    for(i=0; i<10; i++)
     shots[i]->deleteShots();

    if(gameSpeed-1 <= 2)
     levelClear.display();
    else
    {
     congrats.display();
     closegraph();
     exit(1);
    }

    clrscr();
    cleardevice();
    //closegraph();
    //startGraph();

    break; //breaks nested while loop

   }

  }//ends nested while loop

 }while(gameSpeed<4);



 return 0;
}








No comments:

Post a Comment