贪吃蛇详解Windows编程(四)

来源:互联网 发布:魔幻笔软件 编辑:程序博客网 时间:2024/06/07 07:06

控制区的代码就不详细讲解了,自己看看就能明白,并没有什么难点。如果有兴趣的画还可以把界面做好一点,把功能做丰富一点。但是我觉得点到为止就行了。

我用的是Win32空项目写的,你也可以用自动生成的代码写,但是我觉得那个太乱代码太多。
接下来是全部的代码:

#include <windows.h>#include <vector>#include <time.h>//游戏区和控制区宽度高度#define  GAME_WIDE             70     //游戏区宽度70*10#define  GAME_HEIGHT           60     //游戏区高度60*10#define  CTRL_WIDE             30     //控制区宽度30*10#define  CTRL_HEIGHT           60     //控制区高度60*10#define  BOUNDSIZE             10     //边界厚度10   //蛇的信息#define   SNAKESIZE            10     //蛇的宽高都为10的小方块#define   SNAKEMAX            100     //蛇身长度最大值为100#define   SNAKESPEED          500     //初始化蛇的速度为500ms#define   TIMERID_1             1     //定时器ID#define   PAUSEID               1     //暂停按钮ID#define   STARTID               2     //开始按钮ID #define   SPEEDUPID             3     //加速按钮ID#define   SPEEDDOWNID           4     //减速按钮IDstd::vector<POINT> vSnakePoint;       //声明一个蛇的坐标UCHAR ucSnakeHead = 4;                //初始化蛇头为4,实际上是vSnakePoint[3];UCHAR ucSnakeTail = 0;                //初始化蛇尾为0UCHAR ucSnakekLen = 4;                //初始化蛇身长度为4UINT uiSnakeSpeed = SNAKESPEED;       //初始化蛇的速度为500msUINT uiScore = 0;                     //初始化分数为0POINT ptDirectHead = { 1,0 };         //蛇头的方向,初始化为向右POINT ptFood = { 20,20 };             //食物坐标BOOL bIsLoose = TRUE;                 //判断是否输了BOOL bIsWin = FALSE;                  //判断是否赢了BOOL bIsPause = FALSE;                //判断是否暂停了BOOL bIsStart = FALSE;                //判断是否开始了BOOL bFlagStart = FALSE;              //判断是否能开始LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);TCHAR szAppName[] = TEXT("Snake by _acme_");HINSTANCE hInst = nullptr;int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,    PSTR szCmdLine, int iCmdShow){    hInst = hInstance;    HWND     hwnd;    MSG      msg;    WNDCLASS wndclass;    wndclass.style = CS_HREDRAW | CS_VREDRAW;    wndclass.lpfnWndProc = WndProc;    wndclass.cbClsExtra = 0;    wndclass.cbWndExtra = 0;    wndclass.hInstance = hInstance;    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);    wndclass.lpszMenuName = NULL;    wndclass.lpszClassName = szAppName;    if (!RegisterClass(&wndclass))    {        MessageBox(NULL, TEXT("This program requires Windows NT!"),            szAppName, MB_ICONERROR);        return 0;    }    hwnd = CreateWindow(szAppName, szAppName,        WS_OVERLAPPEDWINDOW,        CW_USEDEFAULT, CW_USEDEFAULT,        CW_USEDEFAULT, CW_USEDEFAULT,        NULL, NULL, hInstance, NULL);    ShowWindow(hwnd, iCmdShow);    UpdateWindow(hwnd);    while (GetMessage(&msg, NULL, 0, 0))    {        TranslateMessage(&msg);        DispatchMessage(&msg);    }    return msg.wParam;}//初始化蛇VOID InitSnake(){    //先清空坐标    vSnakePoint.clear();    //给蛇坐标分配空间    vSnakePoint.resize(SNAKEMAX);    //游戏结束后再次初始化    ucSnakeHead = 4;//初始化蛇头为4,实际上是vSnakePoint[3];    ucSnakeTail = 0;//初始化蛇尾为0    ucSnakekLen = 4;//初始化蛇身长度为4    uiSnakeSpeed = SNAKESPEED;//初始化蛇的速度为200ms    ptDirectHead = { 1,0 };//初始化蛇头方向    ptFood = { 20,20 };//初始化食物坐标    uiScore = 0;//初始化分数                //初始化每一节的蛇身坐标    for (int i = 0; i < ucSnakekLen; i++)    {        vSnakePoint[i].x = i;        vSnakePoint[i].y = 0;    }}//获取蛇结点位置//index是一个偏移蛇尾的偏移量POINT &GetSnakeNode(int index){    int i = ucSnakeTail + index;//蛇身的长度    if (i >= SNAKEMAX)    {        i -= SNAKEMAX;    }    return vSnakePoint[i];}//画蛇身VOID DrawSnake(HDC hdc){    static HBRUSH hBrush = CreateSolidBrush(RGB(0, 243, 222));    SelectObject(hdc, hBrush);    //当前蛇结点    POINT ptCurrentNode = { 0 };    for (int i = 0; i < ucSnakekLen; i++)    {        ptCurrentNode = GetSnakeNode(i);        Rectangle(hdc, ptCurrentNode.x*SNAKESIZE + BOUNDSIZE, ptCurrentNode.y*SNAKESIZE + BOUNDSIZE,            (ptCurrentNode.x + 1)*SNAKESIZE + BOUNDSIZE, (ptCurrentNode.y + 1)*SNAKESIZE + BOUNDSIZE);    }}//设置食物坐标void SetFood(){    POINT ptNow = { 0 };    int x = 0, y = 0, i = 0;    while (true)    {        srand(time(0));//随机器种子        x = rand() % GAME_WIDE; //设置食物随机坐标        y = rand() % GAME_HEIGHT;        for (i = 0; i < ucSnakekLen; i++)        {            ptNow = GetSnakeNode(i);            if (ptNow.x == x && ptNow.y == y)                break;//如果食物出现在蛇身,则重新设置食物        }//如果食物不在蛇身,就退出循环        if (ucSnakekLen == i) break;    }    ptFood.x = x;    ptFood.y = y;}//判断蛇是否撞墙BOOL IsStrikeWall(POINT ptHead){    if (ptHead.x < 0 || ptHead.x >= GAME_WIDE        || ptHead.y < 0 || ptHead.y >= GAME_HEIGHT)    {        bIsLoose = FALSE;//撞墙输了        return FALSE;    }    return TRUE;}//判断是否撞到自己BOOL IsStrikeSelf(POINT ptHead){    POINT ptNow = { 0 };    for (int i = 0; i < ucSnakekLen - 1; i++)    {        ptNow = GetSnakeNode(i);        if (ptHead.x == ptNow.x && ptHead.y == ptNow.y)        {            bIsLoose = FALSE;//撞自己输了            return FALSE;        }    }    return TRUE;}//判断是否吃到食物BOOL IsEat(POINT ptHead){    return (ptHead.x == ptFood.x && ptHead.y == ptFood.y) ? TRUE : FALSE;}//显示分数void ShowScore(HWND hwnd){    HDC hdc = GetDC(hwnd);    HPEN hPen = CreatePen(PS_SOLID, 4, RGB(255, 255, 0));    SelectObject(hdc, hPen);    int iLength = 0;    TCHAR szBuffer[20] = { 0 };    iLength = wsprintf(szBuffer, L"Score: %u", uiScore);    TextOut(hdc, BOUNDSIZE * 2 + GAME_WIDE*SNAKESIZE + 100,        BOUNDSIZE + 200, szBuffer, iLength);    ReleaseDC(hwnd, hdc);    DeleteObject(hPen);}//判断是否超出范围void IsOverTake(){    if (SNAKEMAX == ucSnakeHead) ucSnakeHead = 0;   //超出范围往返循环      if (SNAKEMAX == ucSnakeTail)    ucSnakeTail = 0;    if (SNAKEMAX == ucSnakekLen)   bIsWin = TRUE;//赢了}//增加蛇的长度void AddSnakeLen(POINT ptHead){    vSnakePoint[ucSnakeHead++] = ptHead;//蛇头增长    ucSnakekLen++;//长度+1    IsOverTake();//判断是否超出范围}//让蛇动起来BOOL  SnakeMove(){    BOOL bRet = FALSE;    do    {        POINT ptNewNode = { 0 };//新的蛇头        ptNewNode.x = GetSnakeNode(ucSnakekLen - 1).x + ptDirectHead.x;        ptNewNode.y = GetSnakeNode(ucSnakekLen - 1).y + ptDirectHead.y;        if (!IsStrikeWall(ptNewNode))//判断新的蛇头是否撞墙            break;        if (!IsStrikeSelf(ptNewNode))//判断蛇是否撞到自己            break;        if (IsEat(ptNewNode))//判断是否吃到食物        {            SetFood();//重新设置食物坐标            uiScore += 10;//吃到一个食物加10分            AddSnakeLen(ptNewNode);//增加蛇的长度            break;        }        vSnakePoint[ucSnakeHead].x = ptNewNode.x;//蛇头移动        vSnakePoint[ucSnakeHead++].y = ptNewNode.y;        ucSnakeTail++;        IsOverTake();        bRet = TRUE;    } while (FALSE);    return bRet;}//画食物void DrawFood(HWND hwnd){    HDC hdc = GetDC(hwnd);    HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 0));    SelectObject(hdc, hBrush);    //椭圆食物    Ellipse(hdc, BOUNDSIZE + ptFood.x*SNAKESIZE, BOUNDSIZE + ptFood.y*SNAKESIZE        , BOUNDSIZE + (ptFood.x + 1)*SNAKESIZE, BOUNDSIZE + (ptFood.y + 1)*SNAKESIZE);    ReleaseDC(hwnd, hdc);    DeleteObject(hBrush);}LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){    RECT rect = { 0 };    static int  ixWind = 0, iyWind = 0;//窗口大小参数    static int ixClient = 0, iyClient = 0;//客户区大小参数    static HWND  hPause = nullptr;//暂停按钮句柄    static HWND  hStart = nullptr;//开始按钮句柄    static HWND  hSpeedUp = nullptr;//加速按钮句柄    static HWND  hSpeedDown = nullptr;//减速按钮句柄    DWORD dwError = 0;//错误信息    switch (message)    {       case WM_CREATE:       {          //获取窗口大小          GetWindowRect(hwnd, &rect);          ixWind = rect.right - rect.left;          iyWind = rect.bottom - rect.top;          //获取客户区大小          GetClientRect(hwnd, &rect);          ixClient = rect.right - rect.left;          iyClient = rect.bottom - rect.top;          //修改窗口大小          int nWideth = BOUNDSIZE * 3 + (GAME_WIDE + CTRL_WIDE)*SNAKESIZE + (ixWind - ixClient);          int nHeight = BOUNDSIZE * 2 + GAME_HEIGHT*SNAKESIZE + (iyWind - iyClient);          MoveWindow(hwnd, 50, 50, nWideth, nHeight, TRUE);          //初始化蛇身          InitSnake();          //创建一个暂停按钮,宽100高50          hPause = CreateWindowW(L"button", L"Pause", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,            BOUNDSIZE * 2 + GAME_WIDE*SNAKESIZE + 30, BOUNDSIZE + 20,            100, 50, hwnd, (HMENU)PAUSEID, hInst, 0);          //创建一个开始按钮,宽100高50          hStart = CreateWindowW(L"button", L"Start", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,            BOUNDSIZE * 2 + GAME_WIDE*SNAKESIZE + 170, BOUNDSIZE + 20,            100, 50, hwnd, (HMENU)STARTID, hInst, 0);          //创建一个加速按钮,宽100高50          hSpeedUp = CreateWindowW(L"button", L"SpeedUp", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,            BOUNDSIZE * 2 + GAME_WIDE*SNAKESIZE + 30, BOUNDSIZE + 90,            100, 50, hwnd, (HMENU)SPEEDUPID, hInst, 0);          //创建一个减速按钮,宽100高50          hSpeedDown = CreateWindowW(L"button", L"SpeedDown", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,            BOUNDSIZE * 2 + GAME_WIDE*SNAKESIZE + 170, BOUNDSIZE + 90,            100, 50, hwnd, (HMENU)SPEEDDOWNID, hInst, 0);       }        break;       case WM_TIMER:           switch (wParam)           {            case TIMERID_1:            {   //移动蛇               SnakeMove();               //判断是否输了               if (FALSE == bIsLoose)               {                   KillTimer(hwnd, TIMERID_1);                   MessageBox(hwnd, L"you loose!", L"", MB_OK);                   InitSnake();//初始化蛇                   bIsLoose = TRUE;                   SetWindowTextW(hStart, L"Start"); //如果输了就把ReStart变为Start                   bIsStart = FALSE;//重置开始                   bFlagStart = FALSE;               }               if (TRUE == bIsWin)//判断是否赢了               {                   KillTimer(hwnd, TIMERID_1);                   MessageBox(hwnd, L"you Win!", L"", MB_OK);                   InitSnake();//初始化蛇                   bIsWin = FALSE;               }               //重新画蛇               RECT rect = { 0 };               SetRect(&rect, 0, 0, BOUNDSIZE + GAME_WIDE*SNAKESIZE,                   BOUNDSIZE + GAME_HEIGHT*SNAKESIZE);               InvalidateRect(hwnd, &rect, TRUE);            }            break;            default:               break;           }           break;       case WM_KEYDOWN://控制方向           if (FALSE == bIsLoose || TRUE == bIsPause)               return 0;           switch (wParam)           {           case VK_UP:               if (ptDirectHead.x != 0 && ptDirectHead.y != 1)               {                   ptDirectHead.x = 0;                   ptDirectHead.y = -1;               }               break;           case VK_DOWN:               if (ptDirectHead.x != 0 && ptDirectHead.y != -1)               {                   ptDirectHead.x = 0;                   ptDirectHead.y = 1;               }               break;           case VK_LEFT:               if (ptDirectHead.y != 0 && ptDirectHead.x != 1)               {                   ptDirectHead.x = -1;                   ptDirectHead.y = 0;               }               break;           case VK_RIGHT:               if (ptDirectHead.y != 0 && ptDirectHead.x != -1)               {                   ptDirectHead.x = 1;                   ptDirectHead.y = 0;               }               break;           default:               break;           }           break;    case WM_COMMAND:    {        int wmId = LOWORD(wParam);        // 分析菜单选择:         switch (wmId)        {        case SPEEDUPID://速度加            if (uiSnakeSpeed >= 0 && bIsStart == TRUE)            {                if (100 >= uiSnakeSpeed)                    uiSnakeSpeed -= 10;                else                    uiSnakeSpeed -= 100;                SetTimer(hwnd, TIMERID_1, uiSnakeSpeed, nullptr);//重新设置                         }            SendMessage(hwnd, WM_SETFOCUS, 0, 0);            break;        case SPEEDDOWNID://速度减        {            if (uiSnakeSpeed <= 1000 && bIsStart == TRUE)            {                if (100 > uiSnakeSpeed)                    uiSnakeSpeed += 10;                else                    uiSnakeSpeed += 100;                SetTimer(hwnd, TIMERID_1, uiSnakeSpeed, nullptr);//重新设置                         }            SendMessage(hwnd, WM_SETFOCUS, 0, 0);        }        break;        case STARTID://开始        {            if (FALSE == bIsStart && FALSE == bFlagStart)            {                SetTimer(hwnd, TIMERID_1, uiSnakeSpeed, nullptr);//设置定时器                bIsStart = TRUE;//设置为已经开始                bFlagStart = TRUE;//第一次开始后就设为TREU 表示不再进入这个函数                SetWindowTextW(hStart, L"ReStart");                SendMessage(hwnd, WM_SETFOCUS, 0, 0);//把输入焦点还给游戏区            }            else            {                if (TRUE == bIsPause)                {//如果已经暂停了,按下重新开始要记得把暂停按钮恢复原样                    if (!SetWindowTextW(hPause, L"Pause"))                        dwError = GetLastError();                    bIsPause = FALSE;                }                InitSnake();//初始化,重新开始                SetTimer(hwnd, TIMERID_1, uiSnakeSpeed, nullptr);                SendMessage(hwnd, WM_SETFOCUS, 0, 0);//把焦点还给游戏区            }        }        break;        case PAUSEID://暂停            if (TRUE == bFlagStart)//游戏进行的时候才能暂停            {                if (FALSE == bIsPause)//如果没有暂停则将它暂停                {                    KillTimer(hwnd, TIMERID_1);//关掉定时器就是暂停了                    bIsPause = TRUE;          //把状态设置为暂停                    if (!SetWindowText(hPause, L"Go on"))//更改按钮标题                        dwError = GetLastError();                }                else                {//按下继续按钮就重新创建定时器                    SetTimer(hwnd, TIMERID_1, uiSnakeSpeed, nullptr);                    bIsPause = FALSE;//把状态设置为没有被暂停                    if (!SetWindowText(hPause, L"Pause"))//更改按钮标题                        dwError = GetLastError();                    SendMessage(hwnd, WM_SETFOCUS, 0, 0);//把焦点还给游戏区                }            }            break;        default:            return DefWindowProc(hwnd, message, wParam, lParam);        }    }        break;    case WM_SETFOCUS:        SetFocus(hwnd);        break;    case WM_PAINT:    {        PAINTSTRUCT ps;        HDC hdc = BeginPaint(hwnd, &ps);        static HBRUSH hBrush1 = CreateSolidBrush(RGB(58, 206, 66));        static HBRUSH hBrush2 = CreateSolidBrush(RGB(80, 87, 196));        //画游戏区        Rectangle(hdc, BOUNDSIZE, BOUNDSIZE, BOUNDSIZE + GAME_WIDE*SNAKESIZE,            BOUNDSIZE + GAME_HEIGHT*SNAKESIZE);        //填充游戏区颜色        SetRect(&rect, BOUNDSIZE, BOUNDSIZE, BOUNDSIZE + GAME_WIDE*SNAKESIZE,            BOUNDSIZE + GAME_HEIGHT*SNAKESIZE);        FillRect(hdc, &rect, hBrush1);        //画控制区        Rectangle(hdc, BOUNDSIZE * 2 + GAME_WIDE*SNAKESIZE, BOUNDSIZE,            BOUNDSIZE * 2 + (GAME_WIDE + CTRL_WIDE)*SNAKESIZE, BOUNDSIZE + CTRL_HEIGHT*SNAKESIZE);        //填充控制区颜色        SetRect(&rect, BOUNDSIZE * 2 + GAME_WIDE*SNAKESIZE, BOUNDSIZE,            BOUNDSIZE * 2 + (GAME_WIDE + CTRL_WIDE)*SNAKESIZE,            BOUNDSIZE + CTRL_HEIGHT*SNAKESIZE);        FillRect(hdc, &rect, hBrush2);        //画蛇身        DrawSnake(hdc);        //画食物        DrawFood(hwnd);        //显示分数        ShowScore(hwnd);        EndPaint(hwnd, &ps);    }    break;    case WM_DESTROY:        KillTimer(hwnd, TIMERID_1);        PostQuitMessage(0);        break;    default:        return DefWindowProc(hwnd, message, wParam, lParam);    }    return DefWindowProc(hwnd, message, wParam, lParam);}
0 0
原创粉丝点击