📄 billiards.cpp
字号:
// Render iconic ball images for balls already sunk. for (int k=0; k < ballCount; k++) { if (players[currentPlayer].balls[k] == true) { glColor3f(1.0, 1.0, 1.0); glBindTexture(GL_TEXTURE_2D, theTexture[k+16]); glBegin(GL_POLYGON); glTexCoord2f(0.0, 1.0); glVertex2f(displayOffset - 32, 5); glTexCoord2f(1.0, 1.0); glVertex2f(displayOffset, 5); glTexCoord2f(1.0, 0.0); glVertex2f(displayOffset, 37); glTexCoord2f(0.0, 0.0); glVertex2f(displayOffset - 32, 37); glEnd(); displayOffset -= 36.0; } } glEnable(GL_LIGHTING); switchFromOrtho();}// Updates the camera eye coordinatesvoid updateCamera() { camera[0] = zoom*(cos(theta)) + camera[3]; camera[1] = zoom*sin(elevationAngle) + camera[4]; camera[2] = zoom*(sin(theta)) + camera[5]; if (camera[1] < 29) camera[1] = 29; if (camera[1] > 90) camera[1] = 90; glutPostRedisplay();}// Updates the camera look-at positionvoid updateTarget() { camera[3] = ballList[0].position.x; camera[4] = ballList[0].position.y; camera[5] = ballList[0].position.z; glutPostRedisplay();}// Switches from perspective to orthographic projection.void switchToOrtho() { glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, parentWindowWidth, 0, parentWindowHeight); glScalef(1, -1, 1); glTranslatef(0, -1.0*parentWindowHeight, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity();}// Switch back from orthographic to perspective projection.void switchFromOrtho() { glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW);}// The main rendering functionvoid renderParentWindow(void) { double eq [] = {0.0f, 1.0f, 0.0f, 0.0f}; double eqr[] = {0.0f,-1.0f, 0.0f, 0.0f}; glutSetWindow(mainWindow); glClearColor(0.6, 0.6, 0.6, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glLoadIdentity(); if (gameover == false) { drawUI(); } else { shootMode = false; doAnimation = false; } glLoadIdentity(); glPushMatrix(); gluLookAt(camera[0],camera[1],camera[2],camera[3],camera[4],camera[5], 0.0, 1.0, 0.0); renderBalls(); glCallList(displayList[2]); glCallList(displayList[3]); if (doAnimation == true) { if (power >= 3.0) { power -= power/2.0; } else { ballList[0].setDefaults(); ballList[0].updateSpeedSize(); ballList[0].accell = (ballList[0].speed * -1.0) * (ballList[0].accellSize) * (1 / ballList[0].speedSize); power = 3.0; doAnimation = false; shootMode = false; turnStarting = false; players[currentPlayer].noOfShots -= 1; alSourcePlay(soundClip[SHOOT]); if ((error = alGetError()) != AL_NO_ERROR) DisplayALError("alSourcePlay 0 : ", error); glutIdleFunc(idle); } glutPostRedisplay(); } // The following (rather large) section of code is responsible for the reflection of // the table on the floor. glDisable(GL_DEPTH_TEST); glColorMask(0,0,0,0); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glDisable(GL_DEPTH_TEST); glPushMatrix(); glTranslatef(0.0f, 25.0, 0.0f); renderSurface(500.0, 500.0, 1.0, 1.0, -24.0, 12.0, 12.0, 0.0, 1.0, 0.0,theTexture[CHECKER]); glPopMatrix(); glEnable(GL_DEPTH_TEST); glColorMask(1,1,1,1); glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glEnable(GL_CLIP_PLANE0); glClipPlane(GL_CLIP_PLANE0, eqr); glPushMatrix(); glScalef(1.0f, -1.0f, 1.0f); glTranslatef(0.0f, 25.0f, 0.0f); glCallList(displayList[1]); glPopMatrix(); glDisable(GL_CLIP_PLANE0); glDisable(GL_STENCIL_TEST); glLightfv(GL_LIGHT0,GL_POSITION,light0Pos); glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,light0Dir); glLightfv(GL_LIGHT1,GL_POSITION,light1Pos); glEnable(GL_BLEND); glDisable(GL_LIGHTING); glColor4f(1.0f, 1.0f, 1.0f, 0.8f); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPushMatrix(); glTranslatef(0.0f, 25.0f, 0.0f); glRotatef(45.0, 0.0, 1.0, 0.0); renderSurface(500.0, 500.0, 1.0, 1.0, -24.0, 12.0, 12.0, 0.0, 1.0, 0.0, theTexture[CHECKER]); glPopMatrix(); glEnable(GL_LIGHTING); glDisable(GL_BLEND); glEnable(GL_CLIP_PLANE0); glClipPlane(GL_CLIP_PLANE0, eq); glPushMatrix(); glTranslatef(0.0f, 25.0f, 0.0f); glCallList(displayList[1]); glPopMatrix(); glDisable(GL_CLIP_PLANE0); if (shootMode == true) { renderCueStick(); if (useLazer == true) drawGuideLine(); } glPopMatrix(); if (gameover == true) { drawEndScreen(); } glutSwapBuffers();}// The idle function, handles collision detection and response for the table (and various other things like ball animation)void idle() { // Check for and handle collisions between balls for (int s=0; s < (ballCount-1); s++) { for (int t=(s+1); t < ballCount; t++) { if ((ballList[s].collides(ballList[t]) == true) && (ballList[s].collided == false) && (ballList[t].collided == false) && (ballList[s].inPlay == true) && (ballList[t].inPlay == true)) { deflectBalls(s, t); } } } // Check for and handle collisions between balls and table sides for (int t=0; t < ballCount; t++) { if(ballList[t].inPlay == true) { // Determine if the ball was sunk into a pocket if (ballList[t].position.z > (maxZ - pocketRadius) ) { if (ballList[t].position.x < (minX + pocketRadius)) ballInPocket(t, 1); else if (ballList[t].position.x > (maxX - pocketRadius)) ballInPocket(t, 2); } else if (ballList[t].position.z < (minZ + pocketRadius) ) { if (ballList[t].position.x < (minX + pocketRadius)) ballInPocket(t, 3); else if (ballList[t].position.x > (maxX - pocketRadius)) ballInPocket(t, 4); } else if ((ballList[t].position.z < (pocketRadius)) && (ballList[t].position.z > (-1.0*pocketRadius))) { if (ballList[t].position.x < (minX + pocketRadius)) ballInPocket(t, 5); else if (ballList[t].position.x > (maxX - pocketRadius)) ballInPocket(t, 6); } if ((ballList[t].position.x > maxX) || (ballList[t].position.x < minX)) { ballList[t].position.x = ballList[t].position.x - ballList[t].speed.x*1.3; ballList[t].position.z = ballList[t].position.z - ballList[t].speed.z*1.3; ballList[t].speed.x = ballList[t].speed.x*(-0.8); ballList[t].speed.z = ballList[t].speed.z*(0.8); ballList[t].accell.x = ballList[t].accell.x*(-1.0); alSourcePlay(soundClip[SIDES]); if ((error = alGetError()) != AL_NO_ERROR) DisplayALError("alSourcePlay SIDES : ", error); } if ((ballList[t].position.z > maxZ) || (ballList[t].position.z < minZ)) { ballList[t].position.x = ballList[t].position.x - ballList[t].speed.x*1.3; ballList[t].position.z = ballList[t].position.z - ballList[t].speed.z*1.3; ballList[t].speed.z = ballList[t].speed.z*(-0.8); ballList[t].speed.x = ballList[t].speed.x*(0.8); ballList[t].accell.z = ballList[t].accell.z*(-1.0); alSourcePlay(soundClip[SIDES]); if ((error = alGetError()) != AL_NO_ERROR) DisplayALError("alSourcePlay SIDES : ", error); } } } rollingBalls = false; // Let the balls roll on for (int p=0; p < ballCount; p++) { if (ballList[p].inPlay == true) { rollingBalls = rollingBalls | ballList[p].roll(); } else { rollingBalls = rollingBalls | false; } ballList[p].collided = false; } if (rollingBalls == false) { if (returnWhiteBall == true) { ballList[0] = mySphere(0.0, 24.9 , minZ - minZ/3); ballList[0].setDefaults(); returnWhiteBall = false; } if (turnStarting == false) { if (players[currentPlayer].noOfShots <= 0) { turnStarting = true; players[currentPlayer].noOfShots = 0; currentPlayer = (currentPlayer + 1) % playerCount; players[currentPlayer].noOfShots += 1; } else { turnStarting = true; } } } if (turnStarting == true) { glutIdleFunc(NULL); } glutPostRedisplay();}// Handles normal (non-keypad) key input.void keys(unsigned char key, int x, int y) { if (key == ESCAPE) exit(1); // Rotate left if(key == 'a') { theta = theta - 0.05; camera[0] = 65.0*(cos(theta)) + camera[3]; camera[2] = 65.0*(sin(theta)) + camera[5]; updateCamera(); } // Rotate right if(key == 'd') { theta = theta + 0.05; camera[0] = 65.0*(cos(theta)) + camera[3]; camera[2] = 65.0*(sin(theta)) + camera[5]; updateCamera(); } // Move forward if(key == 'w') { zoom -= 1.0; if (zoom < 10) zoom = 10; updateCamera(); } // Move backward if(key == 's') { zoom += 1.0; if (zoom > 100) zoom = 100; updateCamera(); } // Ascend if(key == 'z') { camera[1] = camera[1] + 1.0; if (camera[1] > 90.0) camera[1] = 90.0; updateCamera(); } // Descend if(key == 'x') { camera[1] = camera[1] - 1.0; if (camera[1] < 24.9) camera[1] = 24.9; updateCamera(); } // Increase power of shot if(key == 'g') { power += 2.0; if (power >= 35.0) power = 35.0; } // Decrease power of shot if (key == 'f') { power -= 2.0; if (power <= 3.0) power = 3.0; } // Shoot if (key == 't') { GLfloat powX = power*(cos(theta)); GLfloat powZ = power*(sin(theta)); ballList[0].speed.x = powX*(-0.1); ballList[0].speed.z = powZ*(-0.1); doAnimation = true; } // Toggle shootmode if (key == ' ') { shootMode = !shootMode; } // Handle choice at end of game if (gameover == true) { if (key == 'y') resetGame(); if (key == 'n') exit(0); } // Toggle lazer guided aiming if (key == 'l') { useLazer = !useLazer; } glutSetWindow(mainWindow); glutPostRedisplay();}// Handles all special (keypad) key input.void specialKeyPressed(int key, int x, int y) { switch (key) { case GLUT_KEY_PAGE_UP: keys('z',0,0); break; case GLUT_KEY_PAGE_DOWN: keys('x',0,0); break; case GLUT_KEY_UP: keys('w',0,0); break; case GLUT_KEY_DOWN: keys('s',0,0); break; case GLUT_KEY_LEFT: keys('a',0,0); break; case GLUT_KEY_RIGHT: keys('d',0,0); break; }}// Handles any mouse input from the user.void useMouse(int button, int state, int x, int y) { prevMouseX = x; prevMouseY = y; if (turnStarting == true) updateTarget(); if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN)) { pressedTheta = theta; pressedElevation = elevationAngle; leftMouseButton = true; } if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_UP)) { leftMouseButton = false; } if (rollingBalls == false) { if ((button == GLUT_RIGHT_BUTTON) && (state == GLUT_DOWN)) { pressedTheta = theta; shootMode = true; rightMouseButton = true; } if ((button == GLUT_RIGHT_BUTTON) && (state == GLUT_UP)) { rightMouseButton = false; GLfloat powX = power*(cos(theta)); GLfloat powZ = power*(sin(theta));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -