Inside the loop we reset the modelview matrix, and position the current enemy (enemy[loop1]). We position the enemy using it's fine x and y values (fx and fy). After positioning the current enemy we set the color to pink and start drawing.
The first line will run from 0, –7 (7 pixels up from the starting location) to –7,0 (7 pixels left of the starting location). The second line runs from –7,0 to 0,7 (7 pixels down from the starting location). The third line runs from 0,7 to 7,0 (7 pixels to the right of our starting location), and the last line runs from 7,0 back to the beginning of the first line (7 pixels up from the starting location). This creates a non spinning pink diamond on the screen.
for (loop1=0; loop1<(stage*level); loop1++) // Loop To Draw Enemies
{
glLoadIdentity(); // Reset The Modelview Matrix
glTranslatef(enemy[loop1].fx+20.0f,enemy[loop1].fy+70.0f,0.0f);
glColor3f(1.0f,0.5f,0.5f); // Make Enemy Body Pink
glBegin(GL_LINES); // Start Drawing Enemy
glVertex2d( 0,-7); // Top Point Of Body
glVertex2d(-7, 0); // Left Point Of Body
glVertex2d(-7, 0); // Left Point Of Body
glVertex2d( 0, 7); // Bottom Point Of Body
glVertex2d( 0, 7); // Bottom Point Of Body
glVertex2d( 7, 0); // Right Point Of Body
glVertex2d( 7, 0); // Right Point Of Body
glVertex2d( 0,-7); // Top Point Of Body
glEnd(); // Done Drawing Enemy Body
We don't want the enemy to look boring either so we'll add a dark red spinning blade ('X') on top of the diamond that we just drew. We rotate on the z-axis by enemy[loop1].spin, and then draw the 'X'. We start at the top left and draw a line to the bottom right. Then we draw a second line from the top right to the bottom left. The two lines cross eachother creating an 'X' (or blade … grin).
glRotatef(enemy[loop1].spin,0.0f,0.0f,1.0f); // Rotate The Enemy Blade
glColor3f(1.0f,0.0f,0.0f); // Make Enemy Blade Red
glBegin(GL_LINES); // Start Drawing Enemy Blade
glVertex2d(-7,-7); // Top Left Of Enemy
glVertex2d( 7, 7); // Bottom Right Of Enemy
glVertex2d(-7, 7); // Bottom Left Of Enemy
glVertex2d( 7,-7); // Top Right Of Enemy
glEnd(); // Done Drawing Enemy Blade
}
return TRUE; // Everything Went OK
}
I added the KillFont() command to the end of KillGLWindow(). This makes sure the font display list is destroyed when the window is destroyed.
GLvoid KillGLWindow(GLvoid) // Properly Kill The Window
{
if (fullscreen) // Are We In Fullscreen Mode?
{
ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}
if (hRC) // Do We Have A Rendering Context?
{
if (!wglMakeCurrent(NULL, NULL)) // Are We Able To Release The DC And RC Contexts?
{
MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC?
{
MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
hRC=NULL; // Set RC To NULL
}
if (hDC && !ReleaseDC(hWnd,hDC)) // Are We Able To Release The DC
{
MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
hDC=NULL; // Set DC To NULL
}
if (hWnd && !DestroyWindow(hWnd)) // Are We Able To Destroy The Window?
{
MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hWnd=NULL; // Set hWnd To NULL
}
if (!UnregisterClass("OpenGL",hInstance)) // Are We Able To Unregister Class
{
MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
hInstance=NULL; // Set hInstance To NULL
}
KillFont(); // Kill The Font We Built
}
The CreateGLWindow() and WndProc() code hasn't changed so search until you find the following section of code.
int WINAPI WinMain(HINSTANCE hInstance, // Instance
HINSTANCE hPrevInstance, // Previous Instance
LPSTR lpCmdLine, // Command Line Parameters
int nCmdShow) // Window Show State
{
MSG msg; // Windows Message Structure
BOOL done=FALSE; // Bool Variable To Exit Loop
// Ask The User Which Screen Mode They Prefer
if (MessageBox(NULL, "Would You Like To Run In Fullscreen Mode?", "Start FullScreen?", MB_YESNO|MB_ICONQUESTION) == IDNO) {
fullscreen=FALSE; // Windowed Mode
}
This section of code hasn't changed that much. I changed the window title to read "NeHe's Line Tutorial", and I added the ResetObjects() command. This sets the player to the top left point of the grid, and gives the enemies random starting locations. The enemies will always start off at least 5 tiles away from you. TimerInit() initializes the timer so it's set up properly.
if (!CreateGLWindow("NeHe's Line Tutorial", 640, 480, 16, fullscreen)) // Create Our OpenGL Window
{
return 0; // Quit If Window Was Not Created
}
ResetObjects(); // Set Player / Enemy Starting Positions
TimerInit(); // Initialize The Timer
while(!done) // Loop That Runs While done=FALSE
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) // Is There A Message Waiting?
{
if (msg.message==WM_QUIT) // Have We Received A Quit Message?
{
done=TRUE; // If So done=TRUE
} else // If Not, Deal With Window Messages
{
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
} else // If There Are No Messages
{
Now to make the timing code work. Notice before we draw our scene we grab the time, and store it in a floating point variable called start. We then draw the scene and swap buffers.
Immediately after we swap the buffers we create a delay. We do this by checking to see if the current value of the timer (TimerGetTime( )) is less than our starting value plus the game stepping speed times 2. If the current timer value is less than the value we want, we endlessly loop until the current timer value is equal to or greater than the value we want. This slows down REALLY fast systems.