经过几天的构思, 终于有一点思路了. 现把雏形贴上, 供大家指点一二. 只实现了移动, 其它的未完成. 用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> bool block(HDC surface, int x, int y); #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 queue int itsLength() const; // get queue's length ~CList(); private: Node* head; }; #endif // _QUEUE_H_ /* snake class declaration. */ #ifndef _SNAKE_H_ #define _SNAKE_H_ #include "resource.h" #include "list.h" class CSnake{ public: CSnake(); void run(); bool north(); bool south(); bool west(); bool east(); bool move(); bool draw(HDC surface); ~CSnake(); private: bool bFlag; int iSpeed; int iScore; int iDirection; // 1: north; 2: south; 3: west; 4: east CList segment; }; #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 = 20; // 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 /* 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; for (int i = 8; i > 3; --i ) { elem.xPos = i; segment.Insert(1, elem); } // set default direction iDirection = 4; } // default constructor /* Parameter : HDC Return : true or false Description : draw the snake. */ bool CSnake::draw(HDC surface) { 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; } 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; } 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; } 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; } return true; } // north /* Parameter : none Return : true or false Description : move the block except the head block. */ bool CSnake::move() { ElemType data; char buffer[30]; int iLast = segment.itsLength(); for (int i = iLast - 1; i > 0; --i ) { segment.GetElem(i+1, data); sprintf(buffer, "x : %d y : %d", data.xPos, data.yPos); MessageBox(NULL, buffer, "snake infor", MB_OK); segment.Assign(i, data); } return true; } // move /* 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 Teris. // //============================================================================= #include "resource.h" #include "snake.h" char* g_szAppName = "Snake Game"; CSnake snake; inline int RandInt(int x, int y) {return rand() % (y - x +1) +x; } 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, 640, 480, 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; // set random seed srand((unsigned)time(NULL)); // 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: snake.west(); //snake.move(); break; case VK_RIGHT: snake.east(); //snake.move(); break; case VK_UP: snake.north(); break; case VK_DOWN: 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