|
Design of the Objects and General Program Flow |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
The 'Lazer' header file is the entire collection of variables and methods that the laser beam needs to operate. This header file is self-contained so that it can be added to any other game, called, and used, just like anyone would call upon the use of a library. All the variables are stored privately, in order to help prevent errors such as accidentally changing the position variables or it's kill count. |
|
class lazer //lazer class |
| Here we have the lighting that the laser beam uses. It has everything defined here, and uses the x,y,z positioning of the laser beam to position the light source directly where the laser is located. This number's can be altered freely to achieve different lighting effects and colours |
|
/* initLight
****************************************************** *\ |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| The other objects such as the enemy header file, and the photon header file are kept in the same fashion as the laser header file. |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| The following is a generic header file that stores some most-common functions that I've found myself using over the past year. This header file is something I attach to any of my programs that need random numbers. This header file is constantly growing as I find more everyday-use functions. |
| /*
************************************ *\ Author: Corrado Coia Email: year7C0@gmail.com Date: December 19, 2005 Title: Generic Method Storage Type: Header File \* ************************************ */ |
|
/* random
********************************************************* *\ |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| The following is the main cpp file of the project. First off, all the header files I've composed were added, along with some standard libraries, such as gl.h and glut.h. |
| #if !defined(Linux) // if anything
but Linux #include <windows.h> // include the windows libraries #else // else #include <stdlib.h> // include this other library #endif // end include if /* libraries */ /* project header files */ |
|
Following the includes and defines, all the variables that help define the aspects of the game, such as life, the stars, flags used, and text used, are all defined within structures. All structures are initialized with the beginning numbers in the game (current life = 100, energy level = 2, etc) |
| /* global structure to hold star
variables */ struct globalStar { star *list; // global list to hold stars int next; // declare time 'til next star appears int start; // declare the start time of the counter int speed; // declare the speed of the stars int maxCount; // maximum amount of stars in the screen }; // end global struct /* global structure to hold enemy variables */ struct globalEnemy { enemy *list; // global list to hold enemies int next; // iterations 'til next enemy int start; // global counter int speed; // speed of the enemy int interval; // interval of arrival }; // end global struct /* global structure to hold lazer variables */ struct globalLazer { lazer *list; // global list to hold lazer beam int maxEnergy; // max number of lazer's at once int curEnergy; // current energy level int increment; // energy drain/gain int speed; // speed of the lazer beam }; // end global struct /* global structure to hold photon */ struct globalPhoton { photon *list; // global list float speed; // speed of the photon int interval; // interval of photons int current; // current kills }; // end global struct /* global structure to hold text */ struct globalText { char life[5]; // "Life" char energy[7]; // "Energy" char shots[7]; // "Shots:" char hits[6]; // "Hits:" char score[7]; // "Score:" char paused[12]; // "-Paused-" char gameOver[14]; // "-Game Over-" char energyUp[13]; // "Energy Up!" char title[19]; // "~Super Space Wars~" char damage[14]; // "Damage Taken" char photon[14]; // "Photon Ready!" }; // end global struct /* global structure to hold player stats */ struct globalStats { int maxLife; // maximum life int curLife; // current life int increment; // life drain int totalShots; // total shots fired int totalHits; // total hits scored int counter; // global counter int score; // the players score }; // end global struct /* global flags */ struct globalFlags { bool pause; // pauses the game bool gameOver; // game over flag bool lightswitch; // lightswitch bool energy1; // energy level 1 bool energy2; // energy level 2 bool energy3; // energy level 3 bool photon; // photon death }; // end global struct /* global structure to hold crosshair variables */ struct pointer { int x, y, z; // global positions }; // end pointer struct // initialize the structures struct globalStar gs = { NULL, 0, 0, 1, 50 }; struct globalEnemy ge = { NULL, 500, 0, 3, 400 }; struct globalLazer gl = { NULL, 20, 20, 10, 8 }; struct globalPhoton gp = { NULL, 0, 50 }; struct globalText gt = { "Life", "Energy", "Shots:", "Hits:", "Score:", "-PAUSED-", "-GAME OVER-", "Energy Up!", "-Super Space Wars-", "Damage Taken!", "Photon Ready!" }; struct globalStats gst = { 100, 100, 10, 0, 0, 0, 0 }; struct globalFlags gf = { false, false, false, false, false, false, false }; struct pointer aim = { 0, -worldSize+100, 0 }; |
| Most importantly, the game uses the glutIdleFunc() to control the game. Everything that happens automatically (which is everything expect moving the cursor and firing the weapons) happens in the idle method. The idle method calls every appropriate method such as drawing the world, drawing and moving the stars, enemies, laser beams, calculating and updating scores, life etc etc. |
| /* idle
*********************************************************** *\ This method calls all the methods that need to be run at each frame \* **************************************************************** */ void idle() { maintainGame(); // maintain the game stats if (gf.pause) // if paused { glutSwapBuffers(); // swap buffers for smooth movement glFlush(); // flush to refresh the swapped buffer return; // if paused, do nothing } // end if glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); // define the matrix mode to handle models drawWorld(); // draw the world drawStars(); // move and draw the stars drawEnemy(); // move and draw the enemies drawLazer(); // move and draw the lazer beams drawPhoton(); // move and draw the photon deleteStars(); // checks stars and deletes them deleteEnemy(); // checks enemies and deletes them deleteLazer(); // checks for off screen lazers and deletes them crosshair(aim.x, aim.y, aim.z); // draw the crosshair at the mouse position maintainStars(); // maintain the stars maintainEnemy(); // maintain the enemies |
|
Every pass though the idle function is one complete iteration in the game. Also, at the end of the idle function, the swapping of the back buffer to the front and the clearing of the new back buffer occurs. This is the only time this happens, as each of the above the methods all write to the back buffer, which has been flushed at the end of the prior iteration. |
| glutSwapBuffers(); // swap buffers
for smooth movement glFlush(); // flush to refresh the swapped buffer } // end idle |
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
Lastly, we have the main function which initiates the program and starts the glut functions. Also note that this is running for the 2D version. To run it with the 3D version, the glOrtho should be commented out, and the gluPerspective and gluLookAt should be uncommented. |
| int main(int argc, char **argv) { srand( (unsigned)time( NULL ) ); // generate number seed based on system clock glutInit(&argc, argv); // use the agruments glutInitWindowSize(worldSize,worldSize); glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE | GLUT_DOUBLE ); glutCreateWindow("Super Space Wars"); glMatrixMode(GL_PROJECTION); // adjust the camera glLoadIdentity(); // reset the camera glEnable(GL_DEPTH_TEST); // test the depth (enable it) glOrtho(-worldSize,worldSize,-worldSize, worldSize,-worldSize,worldSize); // gluPerspective(60, 1, 0.1, 100000); // define the distance to see // gluLookAt(0,0,worldSize*2,0,0,0,0,1,0); glMatrixMode(GL_MODELVIEW); // switch to adjusting models glClearColor(0.0, 0.0, 0.0, 1.0); // set the background to black glPushMatrix(); // add this matrix to the stack glutDisplayFunc(drawWorld); // define the initial draw glutIdleFunc(idle); // call the idle function glutKeyboardFunc(keyboard); // define the keyboard function glutSpecialFunc(special); // define special keyboard function glutMouseFunc(mouse); // define the mouse state function glutPassiveMotionFunc(mouse); // define the mouse movement function glutMainLoop(); // start the main loop return 0; // return 0 errors } // end main |
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| The following code is the keyboard command for the 'special keys' (non-character keys), as well as the function for the character keys. Note that pressing L (turning on and off the light), is all handled using flags. Those flags are read each step of the idle function. |
| /* special
******************************************************** *\ This function accepts keyboard commands and produces the desired outcome via a simple swtich statement \* **************************************************************** */ void special(int key, int x, int y) { if (gf.pause) return; // if paused, do nothing switch(key) { case GLUT_KEY_LEFT: // move left aim.x -= 20; break; case GLUT_KEY_RIGHT: // move right aim.x += 20; break; case GLUT_KEY_UP: // fire lazer makeLazer(x); break; case GLUT_KEY_DOWN: // fire photon makePhoton(x); break; } // end switch } // end special
/* keyboard *******************************************************
*\ |
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| And here we have the two mice functions. The passive mouse function which just updates the cursor position's each time the mouse is moved without any actions (such as clicking), then we have the regular mouse function which is action-based (left and right clicking). The two functions have the same name as they are overloaded. I love to overload similar functions. |
| /* mouse
********************************************************** *\ This function accepts mouse commands and produces the desired outcome \* **************************************************************** */ void mouse(int x, int y) { if (gf.pause) return; // if paused, do nothing aim.x = x*2-worldSize; // else return coordinates } // end mouse /* mouse ********************************************************** *\ This function accepts mouse commands and produces the desired outcome \* **************************************************************** */ void mouse(int button, int state, int x, int y) { if (gf.pause) return; // if paused, do nothing if (state == GLUT_DOWN) // mouse click if (button==GLUT_LEFT_BUTTON) // fire lazer makeLazer(x); // make the lazer if (button==GLUT_RIGHT_BUTTON) // fire photon makePhoton(x); // make the photon } // end mouse |
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| Lastly, here is an example of what exactly happens when a laser beam is made. Note the sound, and note how easy it is. |
| /* makeLazer
****************************************************** *\ This method adds a lazer to the list of current lazers \* **************************************************************** */ void makeLazer(int x) { if (gl.curEnergy <= 0) return; // if no energy left, you can't fire else gl.curEnergy -= gl.increment; // else take away energy from the shot char* WAV = "laserfire3.wav"; // define what to play sndPlaySound(WAV, SND_ASYNC); // then play it gst.totalShots += 1; // increase total shots fired lazer *l = gl.list; // assign pointer to the head of the list if (l == NULL) // if the list is empty { lazer *newLazer = new lazer(aim.x, aim.y, aim.z, 1); gl.list = newLazer; // point the list to a new lazer } // end if else // else the list has at least one lazer { while (l->next) // while i have a next l = l->next; // advance the pointer int ID = l->getID() + 1; // increase the ID value lazer *newLazer = new lazer(aim.x, aim.y, aim.z, ID); l->next = newLazer; // set the next (null) to the new lazer } // end else } // end makeLazer |
| Well, I hope that gives an insight into my code. If you have any future questions or comments or suggestions, feel free to email me. |