//Space Invaders.cpp // Fun with Space Invaders sprites // //This code was written with much help from NeHe's tutorials (http://nehe.gamedev.net) // and is not intended for commercial use. // // -Jason Blatt #include #include #include #include #include #include #include #include #include #include const int WINX = 1280, WINY = 1024; //Window Dimensions const int numTextures = 6; //Texture Maps GLuint texture[numTextures]; int frame=0,currTime,timeBase=0; //Timing float fps=0; typedef struct { int active; int face; int path; int killed; float x; float y; float z; float size; float stats[10]; //0 = Rotation //1 = Y-offset } Alien ; const int numAliens = 32; Alien aliens[numAliens]; typedef struct { int check; int x, y; } Shot ; Shot nextShot; const int numStars = 1000; float Starfield[7][numStars]; float starRot = 0, cameraRot = 0, starSpeed = 4.0, spinSpeed = 0; int colored = 0, cameraMove = 1; typedef struct { int life, active, trigger; float xyz[3]; float dXYZ[3]; float colorRGB[3]; float alpha; float size; float rot; } Particle; const int partsPerAlien = 50 , numParticles = numAliens * partsPerAlien; Particle particles[numParticles]; //Number of explosion particles per alien typedef struct { int paths; int numAliens[3]; float startX[3]; float startY[3]; float startZ[3]; int pathFunc[3]; float stats[10]; } Wave; Wave waveOne; //// //Alien Drawing //// void drawAlien(int id) { glTranslatef(aliens[id].x,aliens[id].y,aliens[id].z); glColor4f(1,1,1,1); glBindTexture(GL_TEXTURE_2D, texture[aliens[id].face]); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-aliens[id].size, -aliens[id].size, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( aliens[id].size , -aliens[id].size, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( aliens[id].size, aliens[id].size, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-aliens[id].size, aliens[id].size, 0.0f); glEnd(); glTranslatef(-aliens[id].x,-aliens[id].y,-aliens[id].z); } void updateLocation(int id) { if(aliens[id].path == 0) { aliens[id].x += .15; aliens[id].y = sin(aliens[id].stats[0]); aliens[id].stats[0] += .10; if(aliens[id].x >= 12) aliens[id].x = -12; } else if(aliens[id].path == 1) { aliens[id].x -= .15; aliens[id].y = aliens[id].stats[1] + (sin(aliens[id].stats[0])); aliens[id].stats[0] += .10; if(aliens[id].x <= -20) aliens[id].x = 20; } } //// //Collision Detection //// void checkShot(void) { nextShot.check = 0; float newX; float newY; for(int a = 0 ; a < numAliens ; a++) { if(aliens[a].active == 1) { newX = (float)nextShot.x - WINX/2; newY = (float)-nextShot.y + WINY/2; if(aliens[a].path == 0) { newX = (newX*12.80)/(float)(WINX/2); newY = (newY*10.24)/(float)(WINY/2); } else if(aliens[a].path == 1) { newX = (newX*20)/(float)(WINX/2); newY = (newY*16)/(float)(WINY/2); } if(aliens[a].x - 1 <= newX && newX <= aliens[a].x + 1) { if(aliens[a].y - 1 <= newY && newY <= aliens[a].y + 1) { aliens[a].killed = 1; aliens[a].active = 0; } } } if(aliens[a].killed == 1) { aliens[a].killed = 0; int count = partsPerAlien; for(int b = 0 ; b < numParticles ; b++) { if(count > 0 && particles[b].active != 1) { particles[b].trigger = 1; particles[b].xyz[0] = newX; particles[b].xyz[1] = newY; particles[b].xyz[2] = aliens[a].z; count--; } } } } } //// //Particle Drawing //// void drawParticles(void) { for(int c = 0 ; c < numParticles ; c++) { if(particles[c].trigger == 1) { particles[c].trigger = 0; particles[c].active = 1; particles[c].life = (int)(rand())/10; particles[c].alpha = .8; particles[c].size = 2*(rand() / (float)RAND_MAX); particles[c].rot = 3.14*(rand() / (float)RAND_MAX); particles[c].colorRGB[0] = rand() / (float)RAND_MAX; particles[c].colorRGB[1] = rand() / (float)RAND_MAX; particles[c].colorRGB[2] = rand() / (float)RAND_MAX; particles[c].dXYZ[0] = 2*(rand() / (float)RAND_MAX) - (rand() / (float)RAND_MAX); particles[c].dXYZ[1] = 2*(rand() / (float)RAND_MAX) - (rand() / (float)RAND_MAX); particles[c].dXYZ[2] = 3*(rand() / (float)RAND_MAX) - 1.5*(rand() / (float)RAND_MAX); } if(particles[c].active == 1) { glTranslatef(particles[c].xyz[0], particles[c].xyz[1], particles[c].xyz[2]); glColor4f(particles[c].colorRGB[0], particles[c].colorRGB[1], particles[c].colorRGB[2], particles[c].alpha); glRotatef(particles[c].rot,0,0,1); glBindTexture(GL_TEXTURE_2D, texture[5]); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-particles[c].size, -particles[c].size, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( particles[c].size, -particles[c].size, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( particles[c].size, particles[c].size, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-particles[c].size, particles[c].size, 0.0f); glEnd(); if((rand() / (float)RAND_MAX) > .75) { glColor4f(1,1,1,1); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-particles[c].size, -particles[c].size, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( particles[c].size, -particles[c].size, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( particles[c].size, particles[c].size, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-particles[c].size, particles[c].size, 0.0f); glEnd(); } glRotatef(-particles[c].rot,0,0,1); glTranslatef(-particles[c].xyz[0], -particles[c].xyz[1], -particles[c].xyz[2]); particles[c].xyz[0] += (particles[c].dXYZ[0] + (rand() / (float)RAND_MAX*.025) - (rand() / (float)RAND_MAX*.05)); particles[c].xyz[1] += (particles[c].dXYZ[1] + (rand() / (float)RAND_MAX*.025) - (rand() / (float)RAND_MAX*.05)); particles[c].xyz[2] += (particles[c].dXYZ[2] + (rand() / (float)RAND_MAX*.025) - (rand() / (float)RAND_MAX*.05)); if(particles[c].dXYZ[0] > .2) particles[c].dXYZ[0] -= .2; if(particles[c].dXYZ[1] > .2) particles[c].dXYZ[1] -= .2; if(particles[c].dXYZ[0] < -.2) particles[c].dXYZ[0] += .2; if(particles[c].dXYZ[1] < -.2) particles[c].dXYZ[1] += .2; particles[c].alpha -= (rand() / (float)RAND_MAX)/50; particles[c].rot -= 10;//32 - 5*(rand() / (float)RAND_MAX); } particles[c].life-=2; if(particles[c].life <= 0) particles[c].active = 0; if(particles[c].xyz[2] < -50) particles[c].active = 0; } } //// //Starfield Drawing //// void drawStars(void) { for(int i = 0 ; i < numStars ; i ++) { glLoadIdentity(); if(cameraMove == 1) glRotatef(cameraRot,0,0,1); glTranslatef(Starfield[0][i] , Starfield[1][i] , Starfield[2][i]); if(cameraMove == 1) glRotatef(-cameraRot,0,0,1); //glRotatef(starRot,0,0,1); glColor4f(Starfield[3][i],Starfield[4][i],Starfield[5][i],Starfield[6][i]); glBindTexture(GL_TEXTURE_2D, texture[4]); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f); glEnd(); glTranslatef(-Starfield[0][i] , -Starfield[1][i] , -Starfield[2][i]); Starfield[2][i]+= starSpeed; if(Starfield[2][i] >= 10) { Starfield[2][i] = -1000; Starfield[6][i] = 0; } if(Starfield[6][i] < 1) { if(starSpeed < 10) Starfield[6][i]+=(starSpeed/(starSpeed*100)); else if(starSpeed < 25) Starfield[6][i]+=(starSpeed/(starSpeed*50)); else Starfield[6][i]+=(starSpeed/(starSpeed*20)); } starRot-=.002; } cameraRot += spinSpeed; } //// //Text Drawing Utility Functions //// void drawString(float x, float y, float z, void *font, char *string) { char *c; glRasterPos3f(x,y,z); for (c=string; *c != '\0'; c++) { glutBitmapCharacter(font, *c); } } void setOrthographicProjection() { glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, WINX, 0, WINY); glScalef(1, -1, 1); glTranslatef(0, -WINY, 0); glMatrixMode(GL_MODELVIEW); } void resetPerpectiveProjection() { glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } //// //Main Draw //// void draw(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glLoadIdentity(); srand((unsigned int)time((time_t *)NULL)); //Draw Stars drawStars(); //Check For Kill if(nextShot.check == 1) checkShot(); //Draw Aliens glLoadIdentity(); glTranslatef(0.0f,0.0f,-20.0f); for(int i = 0 ; i < numAliens ; i++) { if(aliens[i].active == 1) drawAlien(i); } //Draw Particles glLoadIdentity(); glTranslatef(0.0f,0.0f,-20.0f); drawParticles(); //Update Locations for(int j = 0 ; j < numAliens ; j++) { if(aliens[i].active == 1) updateLocation(j); } glPopMatrix(); glutSwapBuffers(); } //// //Texture Mapping Functions //// AUX_RGBImageRec *LoadBMP(char *Filename) { FILE *File=NULL; if (!Filename) { return NULL; } File=fopen(Filename,"r"); if (File) { fclose(File); return auxDIBImageLoad(Filename); } return NULL; } int LoadGLTextures() { GLuint loop; int Status=FALSE; AUX_RGBImageRec *TextureImage[numTextures]; memset(TextureImage,0,sizeof(void *)*numTextures); if ((TextureImage[0]=LoadBMP("Data/alien1.bmp")) && (TextureImage[1]=LoadBMP("Data/alien2.bmp")) && (TextureImage[2]=LoadBMP("Data/alien3.bmp")) && (TextureImage[3]=LoadBMP("Data/alien4.bmp")) && (TextureImage[4]=LoadBMP("Data/star1.bmp")) && (TextureImage[5]=LoadBMP("Data/star2.bmp"))) { Status=TRUE; glGenTextures(numTextures, &texture[0]); for (loop=0; loopsizeX, TextureImage[loop]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data); } } for (loop=0; loopdata) { free(TextureImage[loop]->data); } free(TextureImage[loop]); } } return Status; } //// //Resize window function //// void changeSize(int w, int h) { if(h == 0) h = 1; double ratio = 1.0* w / h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glViewport(0, 0, w, h); gluPerspective(45,ratio,1,1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0,0.0,5.0, 0.0,0.0,-1.0, 0.0f,1.0f,0.0f); } //// //Process keys //// void processNormalKeys(unsigned char key, int x, int y) { if (key == 27) exit(0); } void processSpecialKeys(int key, int x, int y) { if(key == GLUT_KEY_UP) { starSpeed+=.25; } if(key == GLUT_KEY_DOWN) { //if(starSpeed > .5) starSpeed-=.25; starSpeed-=.25; } if(key == GLUT_KEY_LEFT) { spinSpeed+=.05; } if(key == GLUT_KEY_RIGHT) { spinSpeed-=.05; } } //// //Process Mouse //// void processMouse(int button, int state, int x, int y) { if(state == GLUT_DOWN) { nextShot.x = x; nextShot.y = y; nextShot.check = 1; } } //// //Get Next Alien //// int nextAlien(void) { int e = 0; while(e < numAliens) { if(aliens[e].active == 0) return e; e++; } return -1; } //// //Init //// void main(int argc, char **argv) { glutInit(&argc, argv); glutInitWindowPosition(0,0); glutInitWindowSize(WINX,WINY); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); int mainwin = glutCreateWindow("Space Invaders"); glutDisplayFunc(draw); glutIdleFunc(draw); glutReshapeFunc(changeSize); glutKeyboardFunc(processNormalKeys); glutSpecialFunc(processSpecialKeys); glutMouseFunc(processMouse); glBlendFunc(GL_SRC_ALPHA,GL_ONE); glEnable(GL_BLEND); //glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glShadeModel(GL_SMOOTH); LoadGLTextures(); glutFullScreen(); currTime = glutGet(GLUT_ELAPSED_TIME); waveOne.paths = 3; waveOne.numAliens[0] = 12; waveOne.numAliens[1] = 8; waveOne.numAliens[2] = 12; waveOne.startX[0] = 20; waveOne.startX[1] = -12; waveOne.startX[2] = 20; waveOne.startY[0] = 7.5; waveOne.startY[1] = 0; waveOne.startY[2] = -7.5; waveOne.startZ[0] = -13.33333; waveOne.startZ[1] = 0; waveOne.startZ[2] = -13.33333; waveOne.pathFunc[0] = 1; waveOne.pathFunc[1] = 0; waveOne.pathFunc[2] = 1; waveOne.stats[0] = 0; float thisRot = waveOne.stats[0]; for(int d = 0 ; d < waveOne.paths ; d++) { float thisStartX = waveOne.startX[d]; for(int k = 0 ; k < waveOne.numAliens[d] ; k++) { int tempNum = nextAlien(); aliens[tempNum].active = 1; aliens[tempNum].face = k%4; aliens[tempNum].path=waveOne.pathFunc[d]; aliens[tempNum].killed=0; aliens[tempNum].x = thisStartX; aliens[tempNum].y = waveOne.startY[d]; aliens[tempNum].z = waveOne.startZ[d]; aliens[tempNum].size = 1; aliens[tempNum].stats[0] = thisRot; aliens[tempNum].stats[1] = waveOne.startY[d]; if(waveOne.startX[d] < 0) thisStartX += 3; else if(waveOne.startX[d] > 0) thisStartX -= 3.333333; thisRot += 5; } } nextShot.check = 0; //Init Starfield srand((unsigned int)time((time_t *)NULL)); for(int j = 0 ; j < numStars ; j++) { Starfield[0][j] = 250 - (rand() % 501); Starfield[1][j] = 250 - (rand() % 501); Starfield[2][j] = -(rand() % 1000); if(colored == 1) { Starfield[3][j] = rand()/(float)RAND_MAX; Starfield[4][j] = rand()/(float)RAND_MAX; Starfield[5][j] = rand()/(float)RAND_MAX; } else { Starfield[3][j] = 1; Starfield[4][j] = 1; Starfield[5][j] = 1; } Starfield[6][j] = 1; } glutMainLoop(); }