贪食蛇

我是为了证明“这种东西其实我也可以写得出来的!”吗?

感想:用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;
}

 

发表评论