经过两天时间的编写, 这个小游戏终于可以玩一下了, 不过还没有达到大家熟悉的面孔. 以下为全部代码, 使用VC++6.0, Win32 Application工程编译通过. /* include files and constant variables here. */ #ifndef _RESOURCE_H_ #define _RESOURCE_H_ #include <time.h> #include <windows.h> #include <stdio.h> inline int RandInt(int x, int y) {return rand() % (y - x +1) +x; } bool block(HDC surface, int x, int y); bool circle(HDC surface, int x, int y, int radius); #endif //_RESOURCE_H_ /* Link list class declarations. */ #ifndef _LIST_H_ #define _LIST_H_ #include "resource.h" typedef struct { int xPos; int yPos; }ElemType; typedef struct SNode{ ElemType data; struct SNode* pNext; }Node; class CList{ public: CList(); bool Insert(int iPos, ElemType elem); bool Assign(int iPos, ElemType elem); bool GetElem(int iPos, ElemType& elem) const; bool GetHead(ElemType& elem) const; bool SetHead(ElemType elem); bool isEmpty() const; // if list is empty return true bool Traverse(HDC hDC) const; // traverse the link list int itsLength() const; // get link list's length ~CList(); private: Node* head; }; #endif // _LIST_H_ /* snake class declaration. */ #ifndef _SNAKE_H_ #define _SNAKE_H_ #include "resource.h" #include "list.h" class CSnake{ public: CSnake(); void run(); bool eat(); bool north(); bool south(); bool west(); bool east(); bool collision(); bool draw(HDC surface); ~CSnake(); private: int iSpeed; int iScore; int iDirection; // 1: north; 2: south; 3: west; 4: east bool bStop; CList segment; ElemType food; }; #endif // _SNAKE_H_ /* some useful functions. */ #include "resource.h" // /* Parameter : HDC, int, int Return : true or false Description : draw a rectangle in the position : (x,y) */ bool block(HDC surface, int x, int y) { int iSize = 10; // set block size RECT rect; rect.left = x * iSize; rect.top = y * iSize; rect.right = rect.left + iSize; rect.bottom = rect.top + iSize; Rectangle(surface, rect.left, rect.top, rect.right, rect.bottom); return true; } // block /* Parameter : HDC, int , int , int Return : true or false Description : draw a circle in the (x,y) position. */ bool circle(HDC surface, int x, int y, int radius) { int iSize = 10; x *= iSize; y *= iSize; x += 5; y += 5; HBRUSH hBrush; HBRUSH hOldBrush; hBrush = CreateSolidBrush(RGB(255, 0, 0)); hOldBrush = (HBRUSH)SelectObject(surface, hBrush); Ellipse(surface, x - radius, y - radius, x + radius, y + radius); SelectObject(surface, hOldBrush); // if not delete object, application will stop... DeleteObject(hBrush); return true; } // circle /* CList class definition. */ #include "list.h" /* Parameter : none Return : none Description : class default constructor. */ CList::CList() { head = new Node; head->pNext = NULL; } // default constructor /* Parameter : int, ElemType Return : true or false Description : insert an element in the iPos. */ bool CList::Insert(int iPos, ElemType elem) { int i = 0; Node* p = head; Node* q = new Node; // search for the destination while (p && i < iPos - 1) { p = p->pNext; i++; } if (!p || i > iPos - 1) { MessageBox(NULL, "less than or more the list length...", "List insert", MB_OK); return false; } // do insert action q->data = elem; q->pNext = p->pNext; p->pNext = q; return true; } // Insert /* Parameter : int, ElemType Return : true or false Description : get an element int the iPos. */ bool CList::GetElem(int iPos, ElemType& elem) const { int i = 0; Node* p = head->pNext; if (iPos < 1 || iPos > itsLength()) { MessageBox(NULL, "wrong position in GetElem function!", "snake game", MB_OK); return false; } // search for the destination while (p && i < iPos - 1) { p = p->pNext; i++; } if (!p || i > iPos - 1) { MessageBox(NULL, "less than or more the list length...", "List insert", MB_OK); return false; } elem = p->data; return true; } // Delete /* Parameter : ElemType& Return : true or false Description : get list head: last element; */ bool CList::GetHead(ElemType& elem) const { int iLast = itsLength(); if (GetElem(iLast, elem)) { return true; } else { return false; } } // GetHead /* Parameter : ElemType Return : true or false Description : set head element in the list. */ bool CList::SetHead(ElemType elem) { int iLast = itsLength(); if (Assign(iLast, elem)) { return true; } else { return false; } } // SetHead /* Parameter : int, ElemType Return : true or false Description : assign an element to the list. */ bool CList::Assign(int iPos, ElemType elem) { int i = 0; Node* p = head->pNext; if (iPos < 1 || iPos > itsLength()) { MessageBox(NULL, "wrong position in Assign function ", "snake game", MB_OK); return false; } // move to the position while (p && i < iPos - 1) { p = p->pNext; i++; } if (!p || i > iPos - 1) { MessageBox(NULL, "less than or more than list length", "snake game", MB_OK); return false; } // assign data to element p->data = elem; return true; } // Assign /* Parameter : none Return : true or false Description : if list is empty return ture; */ bool CList::isEmpty() const { if (head->pNext) { return false; } else { return true; } } // isEmpty /* Parameter : none Return : list's length. Description : get list length. */ int CList::itsLength() const { Node* p = head->pNext; int iLen = 0; while (p) { p = p->pNext; iLen++; } return iLen; } // itsLength /* Parameter : none Return : true or false Description : visit queue every element. */ bool CList::Traverse(HDC hDC) const { Node* p = head->pNext; while(p) { block(hDC, p->data.xPos, p->data.yPos); p = p->pNext; } return true; } // Traverse /* Parameter : none Return : none Description : destroy queue no matter empty or not. */ CList::~CList() { } // default destructor /* snake class definitions. */ #include "snake.h" /* Parameter : none Return : none Description : class default constructor. */ CSnake::CSnake() { ElemType elem; elem.yPos = 8; // set random seed srand((unsigned)time(NULL)); for (int i = 8; i > 6; --i ) { elem.xPos = i; segment.Insert(1, elem); } // set default direction iDirection = 4; // set first food position food.xPos = RandInt(1, 62); food.yPos = RandInt(1, 43); } // default constructor /* Parameter : HDC Return : true or false Description : draw the snake. */ bool CSnake::draw(HDC surface) { circle(surface, food.xPos, food.yPos, 5); segment.Traverse(surface); return true; } // draw /* Parameter : none Return : true or false Description : move snake head to east direction. */ bool CSnake::east() { ElemType elem; ElemType data; ElemType next; segment.GetHead(elem); segment.GetHead(data); // move head segment to east elem.xPos += 1; segment.SetHead(elem); // move the rest segments for (int i = segment.itsLength() - 1; i > 0; --i) { segment.GetElem(i, next); segment.Assign(i, data); data = next; } // eat eat(); return true; } // east /* Parameter : none Return : true or false Description : move snake head to west direction. */ bool CSnake::west() { ElemType elem; ElemType data; ElemType next; segment.GetHead(elem); segment.GetHead(data); // move head segment to west elem.xPos -= 1; segment.SetHead(elem); // move rest segments for (int i = segment.itsLength() - 1; i > 0; --i) { segment.GetElem(i, next); segment.Assign(i, data); data = next; } // eat(); return true; } // west /* Parameter : none Return : true or false Description : move snake head to north direction. */ bool CSnake::north() { ElemType elem; ElemType data; ElemType next; segment.GetHead(elem); segment.GetHead(data); // store head inofrmation in data // move head segment to west elem.yPos -= 1; segment.SetHead(elem); // move rest segments for (int i = segment.itsLength() - 1; i > 0; --i) { segment.GetElem(i, next); segment.Assign(i, data); data = next; } eat(); return true; } // north /* Parameter : none Return : true or false Description : move snake head to south direction. */ bool CSnake::south() { ElemType elem; ElemType data; ElemType next; segment.GetHead(elem); segment.GetHead(data); // move head segment to west elem.yPos += 1; segment.SetHead(elem); // move rest segment for (int i = segment.itsLength() - 1; i > 0; --i) { segment.GetElem(i, next); segment.Assign(i, data); data = next; } // eat(); return true; } // north /* Parameter : none Return : true or false Description : check the snake crash itself or wall. */ bool CSnake::collision() { ElemType head; ElemType data; segment.GetHead(head); // collision with wall if (head.xPos < 0 || head.xPos > 62 || head.yPos < 0 || head.yPos > 43) { MessageBox(NULL, "collision with wall! GAME OVER", "snake game", MB_OK); return true; } // collision with itself for (int i = segment.itsLength() - 1; i > 0; --i) { segment.GetElem(i, data); if (head.xPos == data.xPos && head.yPos == data.yPos) { MessageBox(NULL, "collision with itselt! GAME OVER", "snake game", MB_OK); return true; } } return false; } // move /* Parameter : none Return : true or false Description : check if eat food. */ bool CSnake::eat() { ElemType head; segment.GetHead(head); if (head.xPos == food.xPos && head.yPos == food.yPos) { //MessageBox(NULL, "full! can not eat more... ", "snake game", MB_OK); // reset food position food.xPos = RandInt(0, 62); food.yPos = RandInt(0, 43); // increase snake length ElemType data; segment.GetElem(1, data); segment.Insert( 1, data); return true; } return false; } // eat /* Parameter : none Return : none Description : class default destructor. */ CSnake::~CSnake() { } // default destructor //----------------------------------------------------------------------------- // Copyright (c) 2009 eryar All rights reserved. // // File : main.cpp // Author : eryar@163.com // Date : 2010-01-07 // Version : 1.0v // // Description : classic game : Snake Game. // //============================================================================= #include "resource.h" #include "snake.h" char* g_szAppName = "Snake Game"; CSnake snake; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { MSG Msg; HWND hWnd; WNDCLASSEX wc; bool bFlag = false; char* szClassName = "CTeris"; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW|CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassEx(&wc)) { MessageBox(NULL, "register window class failed! ", g_szAppName, MB_OK|MB_ICONERROR); return false; } hWnd = CreateWindowEx(NULL, szClassName, g_szAppName, WS_CAPTION|WS_OVERLAPPED|WS_SYSMENU|WS_VISIBLE|WS_THICKFRAME, 0,0, 645, 485, NULL, NULL, hInstance, NULL); if (!hWnd) { MessageBox(NULL, "create window failed! ", g_szAppName, MB_OK|MB_ICONERROR); return false; } ShowWindow(hWnd, nShowCmd); UpdateWindow(hWnd); while (!bFlag) { while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) { if (Msg.message == WM_QUIT) { bFlag = true; } else { TranslateMessage(&Msg); DispatchMessage(&Msg); } } // This will call WM_PAINT which well render our scene InvalidateRect(hWnd, NULL, true); UpdateWindow(hWnd); } UnregisterClass(szClassName, wc.hInstance); return Msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { // these hold the dimensions of the client windows area static cxClient, cyClient; // used to create the back buffer HDC hDC; static HDC hDCBackBuffer; static HBITMAP hBitmap; static HBITMAP hOldBitmap; PAINTSTRUCT ps; switch(Msg) { case WM_CREATE: RECT rect; GetClientRect(hWnd, &rect); cxClient = rect.right; cyClient = rect.bottom; // create a surface for us to render to(back buffer) hDCBackBuffer = CreateCompatibleDC(NULL); hDC = GetDC(hWnd); hBitmap = CreateCompatibleBitmap(hDC, cxClient, cyClient); // select the bitmap into the memory device context hOldBitmap = (HBITMAP)SelectObject(hDCBackBuffer, hBitmap); // don't forget to release the DC ReleaseDC(hWnd, hDC); break; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); SelectObject(hDCBackBuffer, hOldBitmap); hDC = GetDC(hWnd); hBitmap = CreateCompatibleBitmap(hDC, cxClient, cyClient); hOldBitmap = (HBITMAP)SelectObject(hDCBackBuffer, hBitmap); ReleaseDC(hWnd, hDC); break; case WM_PAINT: hDC = BeginPaint(hWnd, &ps); // fill our back buffer with white BitBlt(hDCBackBuffer, 0, 0, cxClient, cyClient, NULL,NULL, NULL, WHITENESS); // render scene code here snake.draw(hDCBackBuffer); // now blit the back buffer to front BitBlt(hDC, 0, 0, cxClient, cyClient, hDCBackBuffer, 0, 0, SRCCOPY); ReleaseDC(hWnd, hDC); EndPaint(hWnd, &ps); break; case WM_KEYDOWN: switch(wParam) { case VK_ESCAPE: PostQuitMessage(0); break; case VK_RETURN: break; case VK_SPACE: break; case VK_LEFT: if (!snake.collision()) { snake.west(); } break; case VK_RIGHT: if (!snake.collision()) { snake.east(); } break; case VK_UP: if (!snake.collision()) { snake.north(); } break; case VK_DOWN: if (!snake.collision()) { snake.south(); } break; default: break; } SendMessage(hWnd, WM_PAINT, wParam, lParam); break; case WM_DESTROY: SelectObject(hDCBackBuffer, hOldBitmap); // clean up our back buffer objects DeleteDC(hDCBackBuffer); DeleteObject(hBitmap); // kill the application, this sends a WM_QUIT message PostQuitMessage(0); break; default: break; } return DefWindowProc(hWnd, Msg, wParam, lParam); } // WndProc 请大家指导啊...