This OpenGL program lays the groundwork for a basic asteroid-type game where users can aim a spaceship and fire missiles with the mouse and use menus to modify the type of missile.
spaceship.cc:
// Peter Bui // CSE 40166 Computer Graphics (Fall 2010) // Example 5: spaceship #include <cmath> #include <cstdio> #include <cstdlib> #include <list> #ifdef __APPLE__ #include <GLUT/glut.h> #else #include <GL/glut.h> #endif using namespace std; // Missile data structure ------------------------------------------------------ typedef struct { double x; double y; double angle; } missile; // Constants ------------------------------------------------------------------- enum DISPLAY_LISTS { DL_SPACESHIP, DL_CROSSHAIR, DL_MISSILE_TRIANGLE, DL_MISSILE_DIAMOND, DL_MISSILE_CIRCLE, DL_MAX }; // Global variables ------------------------------------------------------------ static GLuint DisplayListsBase; static size_t WindowWidth = 640; static size_t WindowHeight = 480; static GLuint CursorX, CursorY; static GLuint SpaceshipX, SpaceshipY; static GLuint FrameRate = 60; static GLuint MissileType = DL_MISSILE_TRIANGLE; static int MissileTypeMenu; static int MainMenu; static list<missile> Missiles; // Draw spaceship -------------------------------------------------------------- void draw_spaceship() { glBegin(GL_TRIANGLE_FAN); { double ox = 0.0, oy = 0.0, radius = 0.5; int triangles = 32; glVertex2f(ox, oy); for (int i = 0; i <= triangles; i++) { double angle = i * 2.0 * M_PI / triangles; glVertex2f(ox + radius * cos(angle), oy + radius * sin(angle)); } } glEnd(); glBegin(GL_TRIANGLES); { glVertex2f( 0.55, 0.4); glVertex2f( 0.55, -0.4); glVertex2f( 0.95, 0.0); } glEnd(); } // Draw crosshair -------------------------------------------------------------- void draw_crosshair() { glBegin(GL_LINE_LOOP); { glVertex2f(-0.5, -0.5); glVertex2f(-0.5, 0.5); glVertex2f( 0.5, 0.5); glVertex2f( 0.5, -0.5); } glEnd(); glBegin(GL_LINES); { glVertex2f(-0.5, 0.0); glVertex2f( 0.5, 0.0); glVertex2f( 0.0, 0.5); glVertex2f( 0.0, -0.5); } glEnd(); } // Draw missile triangle ------------------------------------------------------- void draw_missile_triangle() { glBegin(GL_TRIANGLES); { glVertex2f(-0.5, 0.5); glVertex2f(-0.5, -0.5); glVertex2f( 0.5, 0.0); } glEnd(); } // Draw missile diamond -------------------------------------------------------- void draw_missile_diamond() { glBegin(GL_QUADS); { glVertex2f(-0.5, 0.0); glVertex2f( 0.0, -0.5); glVertex2f( 0.5, 0.0); glVertex2f( 0.0, 0.5); } glEnd(); } // Draw missile circle --------------------------------------------------------- void draw_missile_circle() { glBegin(GL_TRIANGLE_FAN); { double ox = 0.0, oy = 0.0, radius = 1.0; int triangles = 32; glVertex2f(ox, oy); for (int i = 0; i <= triangles; i++) { double angle = i * 2.0 * M_PI / triangles; glVertex2f(ox + radius * cos(angle), oy + radius * sin(angle)); } } glEnd(); } // Compute angle --------------------------------------------------------------- double compute_angle(double a_x, double a_y, double b_x, double b_y) { double angle = 0.0; if (b_x > a_x && b_y > a_y) angle = atan2(b_y - a_y, b_x - a_x) * 180.0 / M_PI; else if (b_x < a_x && b_y > a_y) angle = 180.0 - (atan2(b_y - a_y, a_x - b_x) * 180.0 / M_PI); else if (b_x < a_x && b_y < a_y) angle = 180.0 + (atan2(a_y - b_y, a_x - b_x) * 180.0 / M_PI); else if (b_x > a_x && b_y < a_y) angle = 360.0 - (atan2(a_y - b_y, b_x - a_x) * 180.0 / M_PI); return angle; } // Draw scene ------------------------------------------------------------------ void draw_scene() { double angle = compute_angle(SpaceshipX, SpaceshipY, CursorX, CursorY); glColor3f(0.0, 1.0, 0.0); glPushMatrix(); glTranslatef(SpaceshipX, SpaceshipY, 0.0); glRotatef(angle, 0.0, 0.0, 1.0); glScalef(20.0, 20.0, 1.0); glCallList(DisplayListsBase + DL_SPACESHIP); glPopMatrix(); glPushMatrix(); glColor3f(1.0, 0.0, 0.0); glTranslatef(CursorX, CursorY, 0.0); glScalef(10.0, 10.0, 1.0); glCallList(DisplayListsBase + DL_CROSSHAIR); glPopMatrix(); for (list<missile>::iterator i = Missiles.begin(); i != Missiles.end(); i++) { glColor3f(0.0, 0.0, 1.0); i->x += 5.0*cos(i->angle*M_PI/180.0); i->y += 5.0*sin(i->angle*M_PI/180.0); if (i->x < 0 || i->x > WindowWidth || i->y < 0 || i->y > WindowHeight) { i = Missiles.erase(i); } else { glPushMatrix(); glTranslatef(i->x, i->y, 0.0); glRotatef(i->angle, 0.0, 0.0, 1.0); glScalef(10.0, 10.0, 1.0); glCallList(DisplayListsBase + MissileType); glPopMatrix(); } } } // Initialize scene ------------------------------------------------------------ void init_scene() { glClearColor(1.0, 1.0, 1.0, 1.0); glutSetCursor(GLUT_CURSOR_NONE); SpaceshipX = WindowWidth / 2; SpaceshipY = WindowHeight / 2; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, WindowWidth, 0, WindowHeight); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, WindowWidth, WindowHeight); } // Menu functions -------------------------------------------------------------- void missile_type_menu(int id) { glutSetMenu(MissileTypeMenu); switch (MissileType) { case DL_MISSILE_TRIANGLE: glutChangeToMenuEntry(1, "Triangle", DL_MISSILE_TRIANGLE); break; case DL_MISSILE_DIAMOND: glutChangeToMenuEntry(2, "Diamond", DL_MISSILE_DIAMOND); break; case DL_MISSILE_CIRCLE: glutChangeToMenuEntry(3, "Circle", DL_MISSILE_CIRCLE); break; } MissileType = id; switch (MissileType) { case DL_MISSILE_TRIANGLE: glutChangeToMenuEntry(1, "Triangle <", DL_MISSILE_TRIANGLE); break; case DL_MISSILE_DIAMOND: glutChangeToMenuEntry(2, "Diamond <", DL_MISSILE_DIAMOND); break; case DL_MISSILE_CIRCLE: glutChangeToMenuEntry(3, "Circle <", DL_MISSILE_CIRCLE); break; } } void main_menu(int id) { switch (id) { case 1: exit(EXIT_SUCCESS); } } void setup_menus() { MissileTypeMenu = glutCreateMenu(missile_type_menu); glutAddMenuEntry("Triangle <", DL_MISSILE_TRIANGLE); glutAddMenuEntry("Diamond", DL_MISSILE_DIAMOND); glutAddMenuEntry("Circle", DL_MISSILE_CIRCLE); MainMenu = glutCreateMenu(main_menu); glutAddSubMenu("Missile Type", MissileTypeMenu); glutAddMenuEntry("Quit", 1); glutAttachMenu(GLUT_RIGHT_BUTTON); } // Make display lists ---------------------------------------------------------- void make_display_lists() { DisplayListsBase = glGenLists(DL_MAX); glNewList(DisplayListsBase + DL_SPACESHIP, GL_COMPILE); { glPushMatrix(); draw_spaceship(); glPopMatrix(); } glEndList(); glNewList(DisplayListsBase + DL_CROSSHAIR, GL_COMPILE); { glPushMatrix(); draw_crosshair(); glPopMatrix(); } glEndList(); glNewList(DisplayListsBase + DL_MISSILE_TRIANGLE, GL_COMPILE); { glPushMatrix(); draw_missile_triangle(); glPopMatrix(); } glEndList(); glNewList(DisplayListsBase + DL_MISSILE_DIAMOND, GL_COMPILE); { glPushMatrix(); draw_missile_diamond(); glPopMatrix(); } glEndList(); glNewList(DisplayListsBase + DL_MISSILE_CIRCLE, GL_COMPILE); { glPushMatrix(); draw_missile_circle(); glPopMatrix(); } glEndList(); } // Display callback ------------------------------------------------------------ void display() { glClear(GL_COLOR_BUFFER_BIT); draw_scene(); glutSwapBuffers(); } // Reshape callback ------------------------------------------------------------ void reshape(GLsizei nw, GLsizei nh) { WindowWidth = nw; WindowHeight = nh; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, WindowWidth, 0, WindowHeight); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, WindowWidth, WindowHeight); } // Mouse callback -------------------------------------------------------------- void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { missile m; CursorX = x; CursorY = WindowHeight - y; m.x = SpaceshipX; m.y = SpaceshipY; m.angle = compute_angle(SpaceshipX, SpaceshipY, CursorX, CursorY); Missiles.push_back(m); } } // Passive Motion callback ------------------------------------------------------ void passive_motion(int x, int y) { CursorX = x; CursorY = WindowHeight - y; } // Keyboard callback ------------------------------------------------------------ void keyboard(unsigned char key, int x, int y) { if (key == 'q' || key == 'Q') exit(EXIT_SUCCESS); } // Timer callback --------------------------------------------------------------- void timer(int value) { glutPostRedisplay(); glutTimerFunc(1000/FrameRate, timer, value); } // Main execution --------------------------------------------------------------- int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowSize(WindowWidth, WindowHeight); glutCreateWindow("board"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutPassiveMotionFunc(passive_motion); glutKeyboardFunc(keyboard); glutTimerFunc(1000/FrameRate, timer, 0); init_scene(); make_display_lists(); setup_menus(); glutMainLoop(); return (EXIT_SUCCESS); } // vim: sts=4 sw=4 ts=8 ft=cpp