我是为了证明“这种东西其实我也可以写得出来的!”吗?
感想:用WM_TIMER定时实在是不够准,偏差太大。最后还是换了WaitableTimer
#define _WIN32_WINNT 0x0400
#include <Windows.h>
#include <commctrl.h>
#include <stdlib.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "comctl32.lib")
#pragma comment(linker, "/subsystem:windows")
//可调整的初始数据
enum { BlockLen = 30, HCnt = 15, VCnt = 15, InitPosX = 5, InitPosY = 5, InitLen = 3, InitTimerInterval = 800 };
struct SnakeNode {
int x;
int y;
struct SnakeNode* next;
};
struct Map {
SnakeNode* snake;
int eggx; //蛋的位置
int eggy;
int snakedx; //蛇的方向
int snakedy;
int curLevel; //难度
int eggCnt; //吃的蛋的个数
} gameMap;
HWND hMain, hPic, hInfo;
void GenEgg() //生成新的蛋的位置
{
int x, y;
for(;;) {
int flag = 0;
x = rand() % HCnt;
y = rand() % VCnt;
int snkCnt = 0;
struct SnakeNode* s = gameMap.snake;
while(s != 0) {
if (s->x == x && s->y == y) {
flag = 1;
++snkCnt;
}
s = s->next;
}
if (snkCnt == HCnt * VCnt) break; //如果地图满了
if (flag == 0) break;
}
gameMap.eggx = x;
gameMap.eggy = y;
}
void ReleaseGameMap()
{
while(gameMap.snake != 0) {
void* p = gameMap.snake;
gameMap.snake = gameMap.snake->next;
free(p);
}
}
void InitGameMap()
{
struct SnakeNode *ls = 0, *s;
int i;
int x = InitPosX, y = InitPosY;
for(i = 0; i < InitLen; ++i) {
s = (struct SnakeNode*) malloc(sizeof(*s));
s->x = x; s->y = y;
if (ls == 0) {
gameMap.snake = ls = s;
} else {
ls->next = s;
ls = s;
}
--x;
}
gameMap.snakedx = 0;
gameMap.snakedy = 0;
ls->next = 0;
gameMap.eggCnt = 0;
gameMap.curLevel = 0;
GenEgg();
}
void GenPic() {
HDC wdc = GetDC(hPic);
HBITMAP buf = CreateCompatibleBitmap(wdc, HCnt * BlockLen, VCnt * BlockLen);
HDC mdc = CreateCompatibleDC(wdc);
SelectObject(mdc, buf);
HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
HPEN whitePen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
HBRUSH redBrush = CreateSolidBrush(RGB(255, 0, 0));
HPEN redPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
ReleaseDC(hPic, wdc);
SelectObject(mdc, whitePen);
SelectObject(mdc, whiteBrush);
Rectangle(mdc, 0, 0, HCnt * BlockLen, VCnt * BlockLen);
//画蛋
SelectObject(mdc, redBrush);
SelectObject(mdc, redPen);
int eggl = gameMap.eggx * BlockLen;
int eggt = gameMap.eggy * BlockLen;
Ellipse(mdc, eggl, eggt, eggl + BlockLen, eggt + BlockLen);
//画蛇
LOGBRUSH lb;
lb.lbColor = RGB(0, 255, 0);
lb.lbStyle = BS_SOLID;
lb.lbHatch = 0;
HPEN snakePen = ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_ROUND | PS_JOIN_ROUND, BlockLen - 2, &lb, 0, 0);
SelectObject(mdc, snakePen);
int snkCnt = 0;
struct SnakeNode* sn = gameMap.snake;
while(sn != 0) {
++snkCnt;
sn = sn->next;
}
POINT* pots = (POINT*) malloc(sizeof(POINT) * snkCnt);
int i = 0;
sn = gameMap.snake;
while(sn != 0) {
pots[i].x = sn->x * BlockLen + BlockLen / 2;
pots[i].y = sn->y * BlockLen + BlockLen / 2;
++i;
sn = sn->next;
}
Polyline(mdc, pots, snkCnt);
free(pots);
//点蛇头
SelectObject(mdc, redBrush);
SelectObject(mdc, redPen);
Ellipse(mdc, gameMap.snake->x * BlockLen, gameMap.snake->y * BlockLen, gameMap.snake->x * BlockLen + BlockLen, gameMap.snake->y * BlockLen + BlockLen);
DeleteObject(snakePen);
DeleteObject(redBrush);
DeleteObject(redPen);
DeleteObject(whiteBrush);
DeleteObject(whitePen);
DeleteDC(mdc);
HBITMAP oldbm = (HBITMAP)SendMessage(hPic, STM_GETIMAGE, (WPARAM)IMAGE_BITMAP, 0);
SendMessage(hPic, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)buf);
if (oldbm != 0)
DeleteObject(oldbm);
InvalidateRect(hPic, NULL, FALSE);
//显示信息
TCHAR infoBuf[64];
wsprintf(infoBuf, TEXT("难度:%d 得分:%d"), gameMap.curLevel, gameMap.eggCnt);
SetWindowText(hInfo, infoBuf);
}
void ChangeWay(int dx, int dy)
{
struct SnakeNode* sn = gameMap.snake;
if (sn->x + dx == sn->next->x && sn->y + dy == sn->next->y)
;
else
gameMap.snakedx = dx, gameMap.snakedy = dy;
}
bool Forward()
{
bool ret = true;
if (gameMap.snakedx == 0 && gameMap.snakedy == 0)
return true;
int x = gameMap.snake->x;
int y = gameMap.snake->y;
x += gameMap.snakedx;
y += gameMap.snakedy;
struct SnakeNode* sn;
//超出边界
if (x < 0 || y < 0 || x >= HCnt || y >= VCnt) {
ret = false;
} else {
sn = gameMap.snake;
while(sn != 0) {
if (sn->x == x && sn->y == y) {
ret = false; //撞了自己
break;
}
sn = sn->next;
}
}
if (x == gameMap.eggx && y == gameMap.eggy) {
//吃了蛋
sn = (struct SnakeNode*)malloc(sizeof(*sn));
sn->x = x;
sn->y = y;
sn->next = gameMap.snake;
gameMap.snake = sn;
++gameMap.eggCnt;
GenEgg();
} else {
sn = (struct SnakeNode*)malloc(sizeof(*sn));
sn->x = x;
sn->y = y;
sn->next = gameMap.snake;
gameMap.snake = sn;
while(sn->next->next != 0)
sn = sn->next;
free(sn->next);
sn->next = 0;
}
return ret;
}
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmd, INT nShow)
{
srand((unsigned int)GetTickCount());
InitCommonControls();
hMain = CreateWindow(TEXT("#32770"), TEXT("贪食蛇 by 空雪梦见 2013-12-16"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, hInst, 0);
hPic = CreateWindow(TEXT("Static"), TEXT(""), WS_CHILD | WS_VISIBLE | SS_BITMAP,
0, 0, BlockLen * HCnt, BlockLen * VCnt, hMain, 0, hInst, 0);
hInfo = CreateWindow(TEXT("Static"), TEXT(""), WS_CHILD | WS_VISIBLE,
20, BlockLen * VCnt, BlockLen * HCnt - 40, 30, hMain, 0, hInst, 0);
RECT r;
GetWindowRect(hMain, &r);
r.right = r.left + HCnt * BlockLen;
r.bottom = r.top + VCnt * BlockLen + 30;
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE);
MoveWindow(hMain, r.left, r.top, r.right - r.left, r.bottom - r.top, FALSE);
ShowWindow(hMain, nShow);
InitGameMap();
GenEgg();
GenPic();
GetAsyncKeyState(VK_UP);
GetAsyncKeyState(VK_DOWN);
GetAsyncKeyState(VK_LEFT);
GetAsyncKeyState(VK_RIGHT);
HANDLE hTimer = CreateWaitableTimer(0, FALSE, 0);
LARGE_INTEGER liDueTime;
liDueTime.QuadPart = -InitTimerInterval * 10000;
SetWaitableTimer(hTimer, &liDueTime, InitTimerInterval, 0, 0, TRUE);
MSG m;
for(;;) {
DWORD r = MsgWaitForMultipleObjects(1, &hTimer, FALSE, INFINITE, QS_ALLINPUT);
if (GetAsyncKeyState(VK_UP) & 1)
ChangeWay(0, -1);
else if (GetAsyncKeyState(VK_DOWN) & 1)
ChangeWay(0, 1);
else if (GetAsyncKeyState(VK_LEFT) & 1)
ChangeWay(-1, 0);
else if (GetAsyncKeyState(VK_RIGHT) & 1)
ChangeWay(1, 0);
if (r == WAIT_OBJECT_0) {
if (Forward() == false) {
GenPic();
MessageBox(hMain, TEXT("你死了"), TEXT("死死死死死"), MB_OK);
ReleaseGameMap();
InitGameMap();
liDueTime.QuadPart = -InitTimerInterval * 10000;
SetWaitableTimer(hTimer, &liDueTime, InitTimerInterval, 0, 0, TRUE);
}
if (gameMap.curLevel <= gameMap.eggCnt / 10) {
int x = InitTimerInterval;
++gameMap.curLevel;
int i, iend = gameMap.curLevel;
for (i = 0; i < iend; ++i) {
x *= 8;
x /= 10;
}
liDueTime.QuadPart = -x * 10000;
SetWaitableTimer(hTimer, &liDueTime, x, 0, 0, TRUE);
}
GenPic();
} else if (r == WAIT_OBJECT_0 + 1) {
bool quit = false;
while( PeekMessage(&m, 0, 0, 0, PM_REMOVE) != FALSE) {
if (m.hwnd == hMain && m.message == WM_COMMAND && m.wParam == (WPARAM)MAKEWORD(IDCANCEL, BN_CLICKED)) {
quit = true;
break;
}
TranslateMessage(&m);
DispatchMessage(&m);
}
if(quit)
break;
}
}
CloseHandle(hTimer);
return 0;
}