贪吃蛇详解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
- 贪吃蛇详解Windows编程(四)
- 贪吃蛇详解Windows编程(二)
- 贪吃蛇详解Windows编程(三)
- 贪吃蛇详解Windows编程(一)
- 【Windows编程】球球大作战(二) 贪吃蛇的实现
- Android-贪吃蛇(四)- 布局文件
- windows下c/c++编程实现 贪吃蛇简易版
- unity----贪吃蛇详解
- Android中贪吃蛇游戏的学习(四)
- JS写怀旧小游戏系列(四)贪吃蛇
- Windows API 贪吃蛇代码
- 贪吃蛇游戏编程学习
- C++贪吃蛇编程过程
- Java编程---贪吃蛇游戏
- 游戏编程笔记-起步(三)-贪吃蛇游戏实现
- 再读《悟透javascript》之四、贪吃蛇
- 《windows核心编程》笔记(四)
- windows编程几个小例子(四)
- Block
- PCF8591芯片以及AD学习(一)
- BGP学习总结
- GIT分布式版本控制系统--基本用法与常遇到的错误
- 计算机网络常见基本概念
- 贪吃蛇详解Windows编程(四)
- js判断对象类型
- WinForm常用窗体属性及控件
- D2UB
- centos上安装R语言
- Hibernate的学习
- EasyUI+Ajax+Json+一般处理程序实现数据的前台与后台的交互
- MySQL 索引的分类
- [leetcode] 171. Excel Sheet Column Number 解题报告