OpenGL实现3D魔方游戏源代码

首先这个程序是建立的是Windows应用程序,建立控制台程序是不能运行的,另外,项目——项目属性——配置属性——常规-----使用多字节字符集,这样编译才能够通过的,否则如果选择使用 Unicode 字符集,编译会有错误提示:error C2440: “初始化”: 无法从“const char [8]”转换为“LPCTSTR”,另外,链接器----输入----附加依赖项要加入:“opengl32.lib glu32.lib”的lib库。。

cubemanage.h文件为:

#ifndef CUBEMANAGE_H
#define CUBEMANAGE_H

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <math.h>

#include "wcgcube.h"

#define CUBE_SIZE  3
#define ORIENTX 0
#define ORIENTY 0
#define ORIENTZ 0

class CubeManage {
public: 
	CubeManage();
	~CubeManage();
	
	void turn(int rotateType);
	void turnByXShun(int x);
	void turnByXNi(int x);
	void turnByYShun(int y);
	void turnByYNi(int y);
	void turnByZShun(int z);
	void turnByZNi(int z);
	void output(int scr,int site);
	void output();
	void draw(int rotateType,GLfloat rotate);
	
private:
	WcgCube *cubes[CUBE_SIZE][CUBE_SIZE][CUBE_SIZE];
	
	void goStep(int *leftLeg,int *rightLeg,int *goDirection,int step,int leftEdge,int rightEdge);
};

#endif

wcgcube.h文件为:

#ifndef WCGCUBE_H
#define WCGCUBE_H

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <math.h>

#include "iostream"
using namespace std;

#define X 1
#define Y 2
#define Z 3

class WcgCube {
public:
	WcgCube();	
	~WcgCube();
	
	void turnByXShun(int x);
	void turnByXNi(int x);
	void turnByYShun(int y);
	void turnByYNi(int y);
	void turnByZShun(int z);
	void turnByZNi(int z);
	void output(int sign);
	void output();
	void draw(GLfloat x0,GLfloat y0,GLfloat z0);
	
private:
	int direct[6];
	GLfloat sideColor[6][3];
	
	void turnByX(int x,int sign);
	void turnByY(int y,int sign);
	void turnByZ(int z,int sign);
};

#endif

CubeGame.cpp文件为:

#include <windows.h>
#include <winuser.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <math.h>

#include "iostream"
using namespace std;

#include "cubemanage.h"
#include "wcgcube.h"

static GLfloat PI=3.1415f;
// Rotation amounts
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;

static GLfloat rotate=0.0f;
static int rotateType=0;
static int rotateOK=0;
static int rotateRate=100;
static GLfloat rotateStep=5*PI/180;

CubeManage cm;


HPALETTE hPalette = NULL;

// Keep track of windows changing width and height
GLfloat windowWidth;
GLfloat windowHeight;


static LPCTSTR lpszAppName = "WcgCube";

void exitGame(HWND hWnd,HDC hDC,HGLRC hRC);
// Declaration for Window procedure
LRESULT CALLBACK WndProc(	HWND 	hWnd,
							UINT	message,
							WPARAM	wParam,
							LPARAM	lParam);

// Set Pixel Format function - forward declaration
void SetDCPixelFormat(HDC hDC);


void ChangeSize(GLsizei w, GLsizei h)
	{
	GLfloat nRange = 350.0f;

	// Prevent a divide by zero
	if(h == 0)
		h = 1;

	// Set Viewport to window dimensions
    glViewport(0, 0, w, h);

	// Reset coordinate system
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// Establish clipping volume (left, right, bottom, top, near, far)
    if (w <= h) 
		glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
    else 
		glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	}


// Called by timer routine to effect movement of the rectangle.
void IdleFunction(void)
	{
	if (rotate>=PI/2) {
		cm.turn(rotateType);
		rotateType=0;
		rotateOK=0;
		rotate=0.0f;
		// Refresh the Window
//		glutPostRedisplay();
		return;
	}
	rotate+=rotateStep;
	
	// Refresh the Window
//	glutPostRedisplay();
	}



// Called by AUX library to draw scene
void RenderScene(void)
	{
	// Clear the window with current clearing color
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
  glPushMatrix();

  glRotatef(xRot, 1.0f, 0.0f, 0.0f);
	glRotatef(yRot, 0.0f, 1.0f, 0.0f);

	cm.draw(rotateType,rotate);

  glPopMatrix();

	// Show the graphics
//	glutSwapBuffers();
	}



// If necessary, creates a 3-3-2 palette for the device context listed.
HPALETTE GetOpenGLPalette(HDC hDC)
	{
	HPALETTE hRetPal = NULL;	// Handle to palette to be created
	PIXELFORMATDESCRIPTOR pfd;	// Pixel Format Descriptor
	LOGPALETTE *pPal;			// Pointer to memory for logical palette
	int nPixelFormat;			// Pixel format index
	int nColors;				// Number of entries in palette
	int i;						// Counting variable
	BYTE RedRange,GreenRange,BlueRange;
								// Range for each color entry (7,7,and 3)


	// Get the pixel format index and retrieve the pixel format description
	nPixelFormat = GetPixelFormat(hDC);
	DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

	// Does this pixel format require a palette?  If not, do not create a
	// palette and just return NULL
	if(!(pfd.dwFlags & PFD_NEED_PALETTE))
		return NULL;

	// Number of entries in palette.  8 bits yeilds 256 entries
	nColors = 1 << pfd.cColorBits;	

	// Allocate space for a logical palette structure plus all the palette entries
	pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +nColors*sizeof(PALETTEENTRY));

	// Fill in palette header 
	pPal->palVersion = 0x300;		// Windows 3.0
	pPal->palNumEntries = nColors; // table size

	// Build mask of all 1's.  This creates a number represented by having
	// the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
	// pfd.cBlueBits.  
	RedRange = (1 << pfd.cRedBits) -1;
	GreenRange = (1 << pfd.cGreenBits) - 1;
	BlueRange = (1 << pfd.cBlueBits) -1;

	// Loop through all the palette entries
	for(i = 0; i < nColors; i++)
		{
		// Fill in the 8-bit equivalents for each component
		pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
		pPal->palPalEntry[i].peRed = (unsigned char)(
			(double) pPal->palPalEntry[i].peRed * 255.0 / RedRange);

		pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
		pPal->palPalEntry[i].peGreen = (unsigned char)(
			(double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange);

		pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
		pPal->palPalEntry[i].peBlue = (unsigned char)(
			(double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);

		pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
		}
		

	// Create the palette
	hRetPal = CreatePalette(pPal);

	// Go ahead and select and realize the palette for this device context
	SelectPalette(hDC,hRetPal,FALSE);
	RealizePalette(hDC);

	// Free the memory used for the logical palette structure
	free(pPal);

	// Return the handle to the new palette
	return hRetPal;
	}


// Select the pixel format for a given device context
void SetDCPixelFormat(HDC hDC)
	{
	int nPixelFormat;

	static PIXELFORMATDESCRIPTOR pfd = {
		sizeof(PIXELFORMATDESCRIPTOR),	// Size of this structure
		1,								// Version of this structure	
		PFD_DRAW_TO_WINDOW |			// Draw to Window (not to bitmap)
		PFD_SUPPORT_OPENGL |			// Support OpenGL calls in window
		PFD_DOUBLEBUFFER,				// Double buffered mode
		PFD_TYPE_RGBA,					// RGBA Color mode
		32,								// Want 32 bit color 
		0,0,0,0,0,0,					// Not used to select mode
		0,0,							// Not used to select mode
		0,0,0,0,0,						// Not used to select mode
		16,								// Size of depth buffer
		0,								// Not used to select mode
		0,								// Not used to select mode
		0,	            				// Not used to select mode
		0,								// Not used to select mode
		0,0,0 };						// Not used to select mode

	// Choose a pixel format that best matches that described in pfd
	nPixelFormat = ChoosePixelFormat(hDC, &pfd);

	// Set the pixel format for the device context
	SetPixelFormat(hDC, nPixelFormat, &pfd);
	}

void dealKey(HWND hWnd,HDC hDC,HGLRC hRC,int wParam)
{
	switch (wParam)
	{
	case 27:
		exitGame(hWnd,hDC,hRC);
		break;
	case 113:                       //q
		if (rotateOK==1)
			return;
		rotateType=1;
		rotateOK=1;
		rotate=0.0f;
		break;
	case 119:						//w
		if (rotateOK==1)
			return;
		rotateType=2;
		rotateOK=1;
		rotate=0.0f;
		break;
	case 101:						//e
		if (rotateOK==1)
			return;
		rotateType=3;
		rotateOK=1;
		rotate=0.0f;
		break;
	case 114:						//r
		if (rotateOK==1)
			return;
		rotateType=4;
		rotateOK=1;
		rotate=0.0f;
		break;
	case 116:						//t
		if (rotateOK==1)
			return;
		rotateType=5;
		rotateOK=1;
		rotate=0.0f;
		break;
	case 121:						//y
		if (rotateOK==1)
			return;
		rotateType=6;
		rotateOK=1;
		rotate=0.0f;
		break;
	case 97:						//a
		if (rotateOK==1)
			return;
		rotateType=7;
		rotateOK=1;
		rotate=0.0f;
		break;
	case 115:						//s
		if (rotateOK==1)
			return;
		rotateType=8;
		rotateOK=1;
		rotate=0.0f;
		break;
	case 100:						//d
		if (rotateOK==1)
			return;
		rotateType=9;
		rotateOK=1;
		rotate=0.0f;
		break;
	case 102:						//f
		if (rotateOK==1)
			return;
		rotateType=10;
		rotateOK=1;
		rotate=0.0f;
		break;
	case 103:						//g
		if (rotateOK==1)
			return;
		rotateType=11;
		rotateOK=1;
		rotate=0.0f;
		break;
	case 104:						//h
		if (rotateOK==1)
			return;
		rotateType=12;
		rotateOK=1;
		rotate=0.0f;
		break;
	case VK_UP:	
		xRot-= 5.0f;
		break;
	case VK_DOWN:
		xRot += 5.0f;
		break;
	case VK_LEFT:
		yRot -= 5.0f;
		break;
	case VK_RIGHT:
		yRot += 5.0f;
		break;
	}
	if(xRot > 356.0f)
		xRot = 0.0f;

	if(xRot < -1.0f)
		xRot = 355.0f;

	if(yRot > 356.0f)
		yRot = 0.0f;

	if(yRot < -1.0f)
		yRot = 355.0f;
}

void exitGame(HWND hWnd,HDC hDC,HGLRC hRC)
{
			// Kill the timer that we created
			KillTimer(hWnd,101);

			// Deselect the current rendering context and delete it
			wglMakeCurrent(hDC,NULL);
			wglDeleteContext(hRC);

			// Delete the palette
			if(hPalette != NULL)
				DeleteObject(hPalette);

			// Tell the application to terminate after the window
			// is gone.
			PostQuitMessage(0);
}

// Entry point of all Windows programs
int APIENTRY WinMain(	HINSTANCE 	hInstance,
						HINSTANCE 	hPrevInstance,
						LPSTR 		lpCmdLine,
						int			nCmdShow)
	{
	MSG			msg;		// Windows message structure
	WNDCLASS	wc;			// Windows class structure
	HWND		hWnd;		// Storeage for window handle
	HWND		hDesktopWnd;// Storeage for desktop window handle
	HDC			hDesktopDC; // Storeage for desktop window device context
	int			nScreenX, nScreenY; // Screen Dimensions

	// Register Window style
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc		= (WNDPROC) WndProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	wc.hInstance 		= hInstance;
	wc.hIcon			= NULL;
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);
	
	// No need for background brush for OpenGL window
	wc.hbrBackground	= NULL;		
	
	wc.lpszMenuName		= NULL;
	wc.lpszClassName	= lpszAppName;

	// Register the window class
	if(RegisterClass(&wc) == 0)
		return FALSE;

    // Get he Window handle and Device context to the desktop
	hDesktopWnd = GetDesktopWindow();
	hDesktopDC = GetDC(hDesktopWnd);

    // Get the screen size
	nScreenX = GetDeviceCaps(hDesktopDC, HORZRES);
	nScreenY = GetDeviceCaps(hDesktopDC, VERTRES);

    // Release the desktop device context
    ReleaseDC(hDesktopWnd, hDesktopDC);

	// Create the main application window
	hWnd = CreateWindow(
				lpszAppName,
				lpszAppName,
				
				// OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS
				WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
	
				// Window position and size
				0, 0,
				nScreenX, nScreenY,
				NULL,
				NULL,
				hInstance,
				NULL);


	// If window was not created, quit
	if(hWnd == NULL)
		return FALSE;


	// Display the window
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);

	// Process application messages until the application closes
	while( GetMessage(&msg, NULL, 0, 0))
		{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
		}

	return msg.wParam;
	}



// Window procedure, handles all messages for this program
LRESULT CALLBACK WndProc(	HWND 	hWnd,
							UINT	message,
							WPARAM	wParam,
							LPARAM	lParam)
	{
	static HGLRC hRC;		// Permenant Rendering context
	static HDC hDC;			// Private GDI Device context

	switch (message)
	   	{
		// Window creation, setup for OpenGL
		case WM_CREATE:
			// Store the device context
			hDC = GetDC(hWnd);		

			// Select the pixel format
			SetDCPixelFormat(hDC);		

			// Create the rendering context and make it current
			hRC = wglCreateContext(hDC);
			wglMakeCurrent(hDC, hRC);

			// Create the palette
			hPalette = GetOpenGLPalette(hDC);
	// Black background
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f );

	glEnable(GL_DEPTH_TEST);	
//	glEnable(GL_DITHER);
	glShadeModel(GL_SMOOTH);

			// Create a timer that fires 30 times a second
			SetTimer(hWnd,33,1,NULL);
			break;

		// Window is being destroyed, cleanup
		case WM_DESTROY:
			exitGame(hWnd,hDC,hRC);
			break;
        
		case WM_KEYDOWN:
			dealKey(hWnd,hDC,hRC,wParam);
			InvalidateRect(hWnd,NULL,FALSE);
			break;

		case WM_CHAR:
			dealKey(hWnd,hDC,hRC,wParam);
			InvalidateRect(hWnd,NULL,FALSE);
			break;
		
		// Window is resized.
		case WM_SIZE:
			// Call our function which modifies the clipping
			// volume and viewport
			ChangeSize(LOWORD(lParam), HIWORD(lParam));
			break;

		// Timer, moves and bounces the rectangle, simply calls
		// our previous OnIdle function, then invalidates the 
		// window so it will be redrawn.
		case WM_TIMER:
			{
			IdleFunction();
		
			InvalidateRect(hWnd,NULL,FALSE);
			}
			break;

		// The painting function.  This message sent by Windows 
		// whenever the screen needs updating.
		case WM_PAINT:
			{
			// Call OpenGL drawing code
			RenderScene();

			// Call function to swap the buffers
			SwapBuffers(hDC);

			// Validate the newly painted client area
			ValidateRect(hWnd,NULL);
			}
			break;


		// Windows is telling the application that it may modify
		// the system palette.  This message in essance asks the 
		// application for a new palette.
		case WM_QUERYNEWPALETTE:
			// If the palette was created.
			if(hPalette)
				{
				int nRet;

				// Selects the palette into the current device context
				SelectPalette(hDC, hPalette, FALSE);

				// Map entries from the currently selected palette to
				// the system palette.  The return value is the number 
				// of palette entries modified.
				nRet = RealizePalette(hDC);

				// Repaint, forces remap of palette in current window
				InvalidateRect(hWnd,NULL,FALSE);

				return nRet;
				}
			break;

	
		// This window may set the palette, even though it is not the 
		// currently active window.
		case WM_PALETTECHANGED:
			// Don't do anything if the palette does not exist, or if
			// this is the window that changed the palette.
			if((hPalette != NULL) && ((HWND)wParam != hWnd))
				{
				// Select the palette into the device context
				SelectPalette(hDC,hPalette,FALSE);

				// Map entries to system palette
				RealizePalette(hDC);
				
				// Remap the current colors to the newly realized palette
				UpdateColors(hDC);
				return 0;
				}
			break;


        default:   // Passes it on if unproccessed
            return (DefWindowProc(hWnd, message, wParam, lParam));

        }

    return (0L);
	}

cubemanage.cpp文件为:

#include "iostream"
using namespace std;

#include "cubemanage.h"

CubeManage::CubeManage(){
	for (int i=0;i<CUBE_SIZE;i++) {
		for (int j=0;j<CUBE_SIZE;j++) {
			for (int k=0;k<CUBE_SIZE;k++) {
				cubes[i][j][k]=new WcgCube();
			}
		}
	}
}

CubeManage::~CubeManage(){
	for (int i=0;i<CUBE_SIZE;i++) {
		for (int j=0;j<CUBE_SIZE;j++) {
			for (int k=0;k<CUBE_SIZE;k++) {
				delete cubes[i][j][k];
			}
		}
	}
}

void CubeManage::turn(int rotateType) {	
	if (rotateType==1) {
		turnByZShun(2);
	}
	else
	if (rotateType==2) {
		turnByXShun(2);
	}
	else
	if (rotateType==3) {
		turnByZNi(0);
	}
	else
	if (rotateType==4) {
		turnByXNi(0);
	}
	else
	if (rotateType==5) {
		turnByYShun(2);
	}
	else
	if (rotateType==6) {
		turnByYNi(0);
	}
	else
	if (rotateType==7) {
		turnByZNi(2);
	}
	else
	if (rotateType==8) {
		turnByXNi(2);
	}
	else
	if (rotateType==9) {
		turnByZShun(0);
	}
	else
	if (rotateType==10) {
		turnByXShun(0);
	}
	else
	if (rotateType==11) {
		turnByYNi(2);
	}
	else
	if (rotateType==12) {
		turnByYShun(0);
	}
}

void CubeManage::draw(int rotateType,GLfloat rotate) {
	GLfloat PI=3.1415f;
	GLfloat cubeRadium=10.0f;
	GLfloat cubeSpace=2.0f;
	GLfloat x,y,z;
	int i,j,k;

	x=ORIENTX-(CUBE_SIZE/2)*(cubeRadium*2+cubeSpace);
	y=ORIENTZ-(CUBE_SIZE/2)*(cubeRadium*2+cubeSpace);
	z=ORIENTZ-(CUBE_SIZE/2)*(cubeRadium*2+cubeSpace);
	
	if (rotateType==0) {
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				for (k=0;k<CUBE_SIZE;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==1) {
  	glPushMatrix();
  	glRotatef(360-180*rotate/PI,0.0f,0.0f,1.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[i][j][CUBE_SIZE-1])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*(CUBE_SIZE-1));
			}
		}
  	glPopMatrix();
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				for (k=0;k<CUBE_SIZE-1;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==2) {
  	glPushMatrix();
  	glRotatef(360-180*rotate/PI,1.0f,0.0f,0.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[CUBE_SIZE-1][i][j])->draw(x+(cubeRadium*2+cubeSpace)*(CUBE_SIZE-1),y+(cubeRadium*2+cubeSpace)*i,z+(cubeRadium*2+cubeSpace)*j);
			}
		}
  	glPopMatrix();
		for (i=0;i<CUBE_SIZE-1;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				for (k=0;k<CUBE_SIZE;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==3) {
  	glPushMatrix();
  	glRotatef(360-180*rotate/PI,0.0f,0.0f,-1.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[i][j][0])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z);
			}
		}
  	glPopMatrix();
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				for (k=1;k<CUBE_SIZE;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==4) {
  	glPushMatrix();
  	glRotatef(360-180*rotate/PI,-1.0f,0.0f,0.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[0][i][j])->draw(x,y+(cubeRadium*2+cubeSpace)*i,z+(cubeRadium*2+cubeSpace)*j);
			}
		}
  	glPopMatrix();
		for (i=1;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				for (k=0;k<CUBE_SIZE;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==5) {
  	glPushMatrix();
  	glRotatef(360-180*rotate/PI,0.0f,1.0f,0.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[i][CUBE_SIZE-1][j])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*(CUBE_SIZE-1),z+(cubeRadium*2+cubeSpace)*j);
			}
		}
  	glPopMatrix();
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE-1;j++) {
				for (k=0;k<CUBE_SIZE;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==6) {
  	glPushMatrix();
  	glRotatef(360-180*rotate/PI,0.0f,-1.0f,0.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[i][0][j])->draw(x+(cubeRadium*2+cubeSpace)*i,y,z+(cubeRadium*2+cubeSpace)*j);
			}
		}
  	glPopMatrix();
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=1;j<CUBE_SIZE;j++) {
				for (k=0;k<CUBE_SIZE;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==7) {
  	glPushMatrix();
  	glRotatef(180*rotate/PI,0.0f,0.0f,1.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[i][j][CUBE_SIZE-1])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*(CUBE_SIZE-1));
			}
		}
  	glPopMatrix();
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				for (k=0;k<CUBE_SIZE-1;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==8) {
  	glPushMatrix();
  	glRotatef(180*rotate/PI,1.0f,0.0f,0.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[CUBE_SIZE-1][i][j])->draw(x+(cubeRadium*2+cubeSpace)*(CUBE_SIZE-1),y+(cubeRadium*2+cubeSpace)*i,z+(cubeRadium*2+cubeSpace)*j);
			}
		}
  	glPopMatrix();
		for (i=0;i<CUBE_SIZE-1;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				for (k=0;k<CUBE_SIZE;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==9) {
  	glPushMatrix();
  	glRotatef(180*rotate/PI,0.0f,0.0f,-1.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[i][j][0])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z);
			}
		}
  	glPopMatrix();
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				for (k=1;k<CUBE_SIZE;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==10) {
  	glPushMatrix();
  	glRotatef(180*rotate/PI,-1.0f,0.0f,0.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[0][i][j])->draw(x,y+(cubeRadium*2+cubeSpace)*i,z+(cubeRadium*2+cubeSpace)*j);
			}
		}
  	glPopMatrix();
		for (i=1;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				for (k=0;k<CUBE_SIZE;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==11) {
  	glPushMatrix();
  	glRotatef(180*rotate/PI,0.0f,1.0f,0.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[i][CUBE_SIZE-1][j])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*(CUBE_SIZE-1),z+(cubeRadium*2+cubeSpace)*j);
			}
		}
  	glPopMatrix();
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE-1;j++) {
				for (k=0;k<CUBE_SIZE;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
	else
	if (rotateType==12) {
  	glPushMatrix();
  	glRotatef(180*rotate/PI,0.0f,-1.0f,0.0f);
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=0;j<CUBE_SIZE;j++) {
				(cubes[i][0][j])->draw(x+(cubeRadium*2+cubeSpace)*i,y,z+(cubeRadium*2+cubeSpace)*j);
			}
		}
  	glPopMatrix();
		for (i=0;i<CUBE_SIZE;i++) {
			for (j=1;j<CUBE_SIZE;j++) {
				for (k=0;k<CUBE_SIZE;k++) {
					(cubes[i][j][k])->draw(x+(cubeRadium*2+cubeSpace)*i,y+(cubeRadium*2+cubeSpace)*j,z+(cubeRadium*2+cubeSpace)*k);
				}
			}
		}
	}
}

void CubeManage::output() {
	for (int i=0;i<CUBE_SIZE;i++) {
		for (int j=0;j<CUBE_SIZE;j++) {
			cubes[0][i][j]->output();
		}
	}
}

void CubeManage::output(int scr,int site){
	int sign;
	int i,j;

	if (site==1) {
		cout << "site=1,nonsense!" << endl;
		return;
	}
	
	switch (scr) {
		case 1:
			if (site==0)
				sign=-X;
			else
				sign=X;
			cout << "scr=" << scr << " sign=" << sign << endl;
			for (i=0;i<CUBE_SIZE;i++) {
				for (j=0;j<CUBE_SIZE;j++) {
					cout << i << "," << j << "=";
					cubes[site][i][j]->output(sign);
					cout << endl;
				}
			}
			break;
		case 2:
			if (site==0)
				sign=-Y;
			else
				sign=Y;
			for (i=0;i<CUBE_SIZE;i++) {
				for (j=0;j<CUBE_SIZE;j++) {
					cout << i << "," << j << "=";
					cubes[i][site][j]->output(sign);
					cout << endl;
				}
			}
			break;
		case 3:
			if (site==0)
				sign=-Z;
			else
				sign=Z;
			for (i=0;i<CUBE_SIZE;i++) {
				for (j=0;j<CUBE_SIZE;j++) {
					cout << i << "," << j << "=";
					cubes[i][j][site]->output(sign);
					cout << endl;
				}
			}
			break;
	}
}

void CubeManage::goStep(int *leftLeg,int *rightLeg,int *goDirection,int step,int leftEdge,int rightEdge) {
	for (int i=0;i<step;i++) {
		switch (*goDirection) {
			case 0:
				*leftLeg=*leftLeg-1;
				if (*leftLeg<leftEdge) {
					*leftLeg=*leftLeg+1;
					*goDirection=3;
					*rightLeg=*rightLeg+1;
				}
				break;
			case 1:
				*rightLeg=*rightLeg-1;
				if (*rightLeg<leftEdge) {
					*rightLeg=*rightLeg+1;
					*goDirection=0;
					*leftLeg=*leftLeg-1;
				}
				break;
			case 2:
				*leftLeg=*leftLeg+1;
				if (*leftLeg>=rightEdge) {
					*leftLeg=*leftLeg-1;
					*goDirection=1;
					*rightLeg=*rightLeg-1;
				}
				break;
			case 3:
				*rightLeg=*rightLeg+1;
				if (*rightLeg>=rightEdge) {
					*rightLeg=*rightLeg-1;
					*goDirection=2;
					*leftLeg=*leftLeg+1;
				}
				break;
		}
	}
}

void CubeManage::turnByXShun(int x) {
	int step=CUBE_SIZE-1;
	int leftEdge=0;
	int rightEdge=CUBE_SIZE;
	int goDirection0=3;
	int goDirection1=3;
	int y0=0;
	int z0=0;
	int y1=0;
	int z1=0;
	WcgCube *tempcubes[CUBE_SIZE][CUBE_SIZE];
	
	tempcubes[CUBE_SIZE/2][CUBE_SIZE/2]=cubes[x][CUBE_SIZE/2][CUBE_SIZE/2];
	cubes[x][CUBE_SIZE/2][CUBE_SIZE/2]->turnByXShun(x);
	for (int i=0;i<CUBE_SIZE/2;i++) {
		step=CUBE_SIZE-i*2-1;
		goDirection0=3;
		goDirection1=3;
		leftEdge=i;
		rightEdge=CUBE_SIZE-i;
		y0=leftEdge;
		z0=leftEdge;
		y1=leftEdge;
		z1=leftEdge;
		goStep(&y1,&z1,&goDirection1,step,leftEdge,rightEdge);
		for (int j=0;j<step*4;j++) {
			tempcubes[y1][z1]=cubes[x][y0][z0];
			cubes[x][y0][z0]->turnByXShun(x);
			goStep(&y0,&z0,&goDirection0,1,leftEdge,rightEdge);
			goStep(&y1,&z1,&goDirection1,1,leftEdge,rightEdge);
		}
		for (int m=0;m<CUBE_SIZE;m++) {
			for (int n=0;n<CUBE_SIZE;n++) {
				cubes[x][m][n]=tempcubes[m][n];
			}
		}
	}
}

void CubeManage::turnByXNi(int x) {
	turnByXShun(x);
	turnByXShun(x);
	turnByXShun(x);
}

void CubeManage::turnByYShun(int y) {
	int step=CUBE_SIZE-1;
	int leftEdge=0;
	int rightEdge=CUBE_SIZE;
	int goDirection0=3;
	int goDirection1=3;
	int x0=0;
	int z0=0;
	int x1=0;
	int z1=0;
	WcgCube *tempcubes[CUBE_SIZE][CUBE_SIZE];
	
	tempcubes[CUBE_SIZE/2][CUBE_SIZE/2]=cubes[CUBE_SIZE/2][y][CUBE_SIZE/2];
	cubes[CUBE_SIZE/2][y][CUBE_SIZE/2]->turnByYShun(y);
	for (int i=0;i<CUBE_SIZE/2;i++) {
		step=CUBE_SIZE-i*2-1;
		goDirection0=3;
		goDirection1=3;
		leftEdge=i;
		rightEdge=CUBE_SIZE-i;
		x0=leftEdge;
		z0=leftEdge;
		x1=leftEdge;
		z1=leftEdge;
		goStep(&z1,&x1,&goDirection1,step,leftEdge,rightEdge);
		for (int j=0;j<step*4;j++) {
			tempcubes[x1][z1]=cubes[x0][y][z0];
			cubes[x0][y][z0]->turnByYShun(y);
			goStep(&z0,&x0,&goDirection0,1,leftEdge,rightEdge);
			goStep(&z1,&x1,&goDirection1,1,leftEdge,rightEdge);
		}
		for (int m=0;m<CUBE_SIZE;m++) {
			for (int n=0;n<CUBE_SIZE;n++) {
				cubes[m][y][n]=tempcubes[m][n];
			}
		}
	}
}

void CubeManage::turnByYNi(int y) {
	turnByYShun(y);
	turnByYShun(y);
	turnByYShun(y);
}

void CubeManage::turnByZShun(int z) {
	int step=CUBE_SIZE-1;
	int leftEdge=0;
	int rightEdge=CUBE_SIZE;
	int goDirection0=3;
	int goDirection1=3;
	int x0=0;
	int y0=0;
	int x1=0;
	int y1=0;
	WcgCube *tempcubes[CUBE_SIZE][CUBE_SIZE];
	
	tempcubes[CUBE_SIZE/2][CUBE_SIZE/2]=cubes[CUBE_SIZE/2][CUBE_SIZE/2][z];
	cubes[CUBE_SIZE/2][CUBE_SIZE/2][z]->turnByZShun(z);
	for (int i=0;i<CUBE_SIZE/2;i++) {
		step=CUBE_SIZE-i*2-1;
		goDirection0=3;
		goDirection1=3;
		leftEdge=i;
		rightEdge=CUBE_SIZE-i;
		x0=leftEdge;
		y0=leftEdge;
		x1=leftEdge;
		y1=leftEdge;
		goStep(&x1,&y1,&goDirection1,step,leftEdge,rightEdge);
		for (int j=0;j<step*4;j++) {
			tempcubes[x1][y1]=cubes[x0][y0][z];
			cubes[x0][y0][z]->turnByZShun(z);
			goStep(&x0,&y0,&goDirection0,1,leftEdge,rightEdge);
			goStep(&x1,&y1,&goDirection1,1,leftEdge,rightEdge);
		}
		for (int m=0;m<CUBE_SIZE;m++) {
			for (int n=0;n<CUBE_SIZE;n++) {
				cubes[m][n][z]=tempcubes[m][n];
			}
		}
	}
}

void CubeManage::turnByZNi(int z) {
	turnByZShun(z);
	turnByZShun(z);
	turnByZShun(z);
}

wcgcube.cpp文件为:

#include "iostream"
using namespace std;

#include "wcgcube.h"

WcgCube::WcgCube(){
	direct[0]=Z;
	direct[1]=X;
	direct[2]=-Z;
	direct[3]=-X;
	direct[4]=Y;
	direct[5]=-Y;
	
	sideColor[0][0]=1.0f;
	sideColor[0][1]=1.0f;
	sideColor[0][2]=1.0f;
	
	sideColor[1][0]=1.0f;
	sideColor[1][1]=1.0f;
	sideColor[1][2]=0.0f;
	
	sideColor[2][0]=1.0f;
	sideColor[2][1]=0.0f;
	sideColor[2][2]=0.0f;
	
	sideColor[3][0]=1.0f;
	sideColor[3][1]=0.0f;
	sideColor[3][2]=1.0f;
	
	sideColor[4][0]=0.0f;
	sideColor[4][1]=1.0f;
	sideColor[4][2]=1.0f;
	
	sideColor[5][0]=0.0f;
	sideColor[5][1]=1.0f;
	sideColor[5][2]=0.0f;
}

WcgCube::~WcgCube(){
}

void WcgCube::draw(GLfloat orientX,GLfloat orientY,GLfloat orientZ) {
	GLfloat cubeRadium=10.0f;
	GLfloat cubeSpace=2.0f;
	for (int i=0;i<6;i++) {
		glColor3f(sideColor[i][0],sideColor[i][1],sideColor[i][2]);
		if (direct[i]==Z) {
			// Front face
			glBegin(GL_POLYGON);
				glVertex3f(orientX+cubeRadium,orientY+cubeRadium,orientZ+cubeRadium);

				glVertex3f(orientX+cubeRadium,orientY-cubeRadium,orientZ+cubeRadium);

				glVertex3f(orientX-cubeRadium,orientY-cubeRadium,orientZ+cubeRadium);

				glVertex3f(orientX-cubeRadium,orientY+cubeRadium,orientZ+cubeRadium);
			glEnd();
		}
		else
		if (direct[i]==-Z) {
			// Back Face
			glBegin(GL_POLYGON);
				glVertex3f(orientX+cubeRadium,orientY+cubeRadium,orientZ-cubeRadium);

				glVertex3f(orientX+cubeRadium,orientY-cubeRadium,orientZ-cubeRadium);

				glVertex3f(orientX-cubeRadium,orientY-cubeRadium,orientZ-cubeRadium);

				glVertex3f(orientX-cubeRadium,orientY+cubeRadium,orientZ-cubeRadium);
			glEnd();
		}
		else
		if (direct[i]==Y) {
			// Top Face
			glBegin(GL_POLYGON);
				glVertex3f(orientX+cubeRadium,orientY+cubeRadium,orientZ-cubeRadium);

				glVertex3f(orientX+cubeRadium,orientY+cubeRadium,orientZ+cubeRadium);

				glVertex3f(orientX-cubeRadium,orientY+cubeRadium,orientZ+cubeRadium);

				glVertex3f(orientX-cubeRadium,orientY+cubeRadium,orientZ-cubeRadium);
			glEnd();
		}
		else
		if (direct[i]==-Y) {
			// Bottom Face
			glBegin(GL_POLYGON);
				glVertex3f(orientX+cubeRadium,orientY-cubeRadium,orientZ-cubeRadium);

				glVertex3f(orientX+cubeRadium,orientY-cubeRadium,orientZ+cubeRadium);

				glVertex3f(orientX-cubeRadium,orientY-cubeRadium,orientZ+cubeRadium);

				glVertex3f(orientX-cubeRadium,orientY-cubeRadium,orientZ-cubeRadium);
			glEnd();
		}
		else
		if (direct[i]==X) {
			// Left face
			glBegin(GL_POLYGON);
				glVertex3f(orientX+cubeRadium,orientY+cubeRadium,orientZ+cubeRadium);

				glVertex3f(orientX+cubeRadium,orientY+cubeRadium,orientZ-cubeRadium);

				glVertex3f(orientX+cubeRadium,orientY-cubeRadium,orientZ-cubeRadium);

				glVertex3f(orientX+cubeRadium,orientY-cubeRadium,orientZ+cubeRadium);
			glEnd();
		}
		else
		if (direct[i]==-X) {
			// Right face
			glBegin(GL_POLYGON);
				glVertex3f(orientX-cubeRadium,orientY+cubeRadium,orientZ+cubeRadium);

				glVertex3f(orientX-cubeRadium,orientY+cubeRadium,orientZ-cubeRadium);

				glVertex3f(orientX-cubeRadium,orientY-cubeRadium,orientZ-cubeRadium);

				glVertex3f(orientX-cubeRadium,orientY-cubeRadium,orientZ+cubeRadium);
			glEnd();
		}
	}
}

void WcgCube::output() {
	for (int i=0;i<6;i++) {
		cout << "direct[" << i << "]=" << direct[i] << endl;
	}
}

void WcgCube::output(int sign) {
	for (int i=0;i<6;i++) {
		if (direct[i]==sign)
			cout <<  i;
	}
}

void WcgCube::turnByXShun(int x) {
	turnByX(x,-1);
}

void WcgCube::turnByXNi(int x) {
	turnByX(x,1);
}

void WcgCube::turnByX(int x,int sign) {
	for (int i=0;i<6;i++) {
		switch (direct[i]) {
			case Z:
				direct[i]=(-1)*sign*Y;
				break;
			case -Z:
				direct[i]=sign*Y;
				break;
			case Y:
				direct[i]=sign*Z;
				break;
			case -Y:
				direct[i]=(-1)*sign*Z;
				break;
		}
	}
}

void WcgCube::turnByYShun(int y) {
	turnByY(y,-1);
}

void WcgCube::turnByYNi(int y) {
	turnByY(y,1);
}

void WcgCube::turnByY(int y,int sign) {
	for (int i=0;i<6;i++) {
		switch (direct[i]) {
			case Z:
				direct[i]=sign*X;
				break;
			case -Z:
				direct[i]=(-1)*sign*X;
				break;
			case X:
				direct[i]=(-1)*sign*Z;
				break;
			case -X:
				direct[i]=sign*Z;
				break;
		}
	}
}

void WcgCube::turnByZShun(int z) {
	turnByZ(z,-1);
}

void WcgCube::turnByZNi(int z) {
	turnByZ(z,1);
}

void WcgCube::turnByZ(int z,int sign) {
	for (int i=0;i<6;i++) {
		switch (direct[i]) {
			case Y:
				direct[i]=(-1)*sign*X;
				break;
			case -Y:
				direct[i]=sign*X;
				break;
			case X:
				direct[i]=sign*Y;
				break;
			case -X:
				direct[i]=(-1)*sign*Y;
				break;
		}
	}
}

通过键盘上的按键q、w、e、r、t、a、s、d、f、g、h来旋转改变魔方的各种组合。

最终效果图如下所示:

OpenGL实现3D魔方游戏源代码



你可能感兴趣的:(OpenGL)