经过两天时间的编写, 这个小游戏终于可以玩一下了, 不过还没有达到大家熟悉的面孔.
以下为全部代码, 使用VC++6.0, Win32 Application工程编译通过.
#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_
#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_
#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_
#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
#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
#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
#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
请大家指导啊...