C + API 贪吃蛇程序

来源:互联网 发布:百合小说 知乎 编辑:程序博客网 时间:2024/05/18 03:21
#include <windows.h>#include <time.h>#include <stdlib.h>//定义4个方向#define UP1  //向上,蛇头y坐标不断减小#define DOWN2  //向下,蛇头y坐标不断增大#define LEFT3  //向左,蛇头x坐标不断减小#define RIGHT4  //向右,蛇头x坐标不断增大#define SNAKEWIDTH10  //单节蛇的大小#define XWIDTH20  //游戏区的宽度#define YHEIGHT20  //游戏区的高度#define GETSCORE10//吃一个食物的得分#define ID_TIMER1   //定时器ID#define TIMERSET600 //定时间隔static intdirect = RIGHT;  //方向(注:方向由蛇头决定)static intScore;  //吃到的食物数量boolIsOver = false, bEat = false;struct Snake{Snake():next(NULL), before(NULL) {pt.x = 0; pt.y = 0;}Snake(const POINT &npt, Snake *, Snake *);POINTpt;Snake * next, * before;} snake;  //定义蛇头Snake::Snake(const POINT &npt, Snake * nnext, Snake * nbefore):pt(npt), next(nnext), before(nbefore){}Snake * psLast = NULL, * food = NULL;bool GameClient[XWIDTH][YHEIGHT]; //定义游戏区坐标布尔值,表示相应点的蛇身以及是否有食物。LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){TCHARszAppName[]= TEXT("Snake"),szWindowName[]= TEXT("贪吃蛇 by 阿卡(QQ:8596801)");WNDCLASSwndcls;wndcls.cbClsExtra= 0;wndcls.cbWndExtra= 0;wndcls.hbrBackground= (HBRUSH) GetStockObject(WHITE_BRUSH);wndcls.hCursor= LoadCursor(hInstance, IDC_ARROW);wndcls.hIcon= LoadIcon(hInstance, IDI_APPLICATION);wndcls.hInstance= hInstance;wndcls.lpfnWndProc= WndProc;wndcls.lpszClassName= szAppName;wndcls.lpszMenuName= NULL;wndcls.style= CS_HREDRAW | CS_VREDRAW;RegisterClass(&wndcls);HWND hwnd = CreateWindow(szAppName, szWindowName,WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU,CW_USEDEFAULT, CW_USEDEFAULT, (XWIDTH + 10) * SNAKEWIDTH, (YHEIGHT + 5) * SNAKEWIDTH,NULL, NULL, hInstance, NULL);ShowWindow(hwnd, nCmdShow);UpdateWindow(hwnd);MSG msg;while(GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return msg.wParam;}//新食物刷新void NewFood(HWND hwnd){food = new Snake();SYSTEMTIME st;GetLocalTime(&st);srand(st.wMilliseconds);food->pt.x = rand() % XWIDTH, food->pt.y = rand() % YHEIGHT;while(GameClient[food->pt.x][food->pt.y]){GetLocalTime(&st);srand(st.wMilliseconds);food->pt.x = rand() % XWIDTH, food->pt.y = rand() % YHEIGHT;}GameClient[food->pt.x][food->pt.y] = true;InvalidateRect(hwnd, NULL, TRUE);}//判断前方是否是食物inline bool IsFood(){if(snake.pt.x == food->pt.x && snake.pt.y == food->pt.y)return true;elsereturn false;}//判断是否撞墙或者撞到自己身体bool TouchWall(){Snake * temp = psLast;//超越边界判断if(snake.pt.x >= XWIDTH ||snake.pt.x < 0 ||snake.pt.y < 0 ||snake.pt.y >= YHEIGHT)return true;//碰撞自身身体判断while(temp != &snake){if(snake.pt.x == temp->pt.x &&snake.pt.y == temp->pt.y)return true;temp = temp->before;}return false;}void Move(HWND hwnd){int x, y;  //用于记录蛇头的当前位置(未前进时)//标记前方是否为食物,默认为不是食物,表示系通常的前进Snake * temp = psLast;//记录蛇头当前坐标x = snake.pt.x;y = snake.pt.y;//测试前进的地方是否是食物,同时将蛇头前进switch(direct){case UP:--snake.pt.y;break;case DOWN:++snake.pt.y;break;case LEFT:--snake.pt.x;break;case RIGHT:++snake.pt.x;break;default:break;}//如果不是食物,作如下处理if(!IsFood()){//最后一节不是蛇头if(temp != &snake){GameClient[temp->pt.x][temp->pt.y] = false;while(temp != snake.next){temp->pt.x = temp->before->pt.x;temp->pt.y = temp->before->pt.y;temp = temp->before;}temp->pt.x = x;temp->pt.y = y;GameClient[temp->pt.x][temp->pt.y] = true;}else  //psLast == &snake,即蛇只有蛇头GameClient[x][y] = false;if(TouchWall())IsOver = true;//则标记游戏结束elseGameClient[snake.pt.x][snake.pt.y] = true;//不然移动后的蛇头位置标记为有方块了InvalidateRect(hwnd, NULL, TRUE);//刷新游戏区}//如果是食物,作如下处理else{++Score;food->before = psLast;psLast->next = food;if(temp != &snake){food->pt.x = psLast->pt.x;food->pt.y = psLast->pt.y;while(temp != snake.next){temp->pt.x = temp->before->pt.x;temp->pt.y = temp->before->pt.y;temp = temp->before;}temp->pt.x = x;temp->pt.y = y;}else  //psLast == &snake,即蛇只有蛇头{food->pt.x = x; food->pt.y = y;}psLast = food;NewFood(hwnd);}}LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){HDChdc;PAINTSTRUCTps;TEXTMETRICtm;static intcxChar, cyChar;TCHARszScore[]= TEXT("得分:"),szGameOver[]= TEXT("游戏结束!"),szPause[]= TEXT("游戏暂停!"),szBuffer[20],*szText = NULL;intx, y;static boolpause = false;switch(message){case WM_CREATE:direct= RIGHT;   //游戏开局,默认方向向右snake.pt.x= XWIDTH / 2;  //默认显示在游戏区中间位置snake.pt.y= YHEIGHT / 2;psLast= &snake;GameClient[snake.pt.x][snake.pt.y] = true;hdc = GetDC(hwnd);GetTextMetrics(hdc, &tm);cyChar = tm.tmExternalLeading + tm.tmHeight;ReleaseDC(hwnd, hdc);NewFood(hwnd);SetTimer(hwnd, ID_TIMER, TIMERSET, NULL);return 0;case WM_TIMER:if(pause) return 0;Move(hwnd);if(IsOver){KillTimer(hwnd, ID_TIMER);InvalidateRect(hwnd, NULL, TRUE);}return 0;case WM_KEYDOWN:if(IsOver || pause) return 0;switch(wParam){case VK_UP:if(direct != DOWN){direct = UP;Move(hwnd);}break;case VK_DOWN:if(direct != UP){direct = DOWN;Move(hwnd);}break;case VK_LEFT:if(direct != RIGHT){direct = LEFT;Move(hwnd);}break;case VK_RIGHT:if(direct != LEFT){direct = RIGHT;Move(hwnd);}break;default:break;}return 0;case WM_CHAR:if(IsOver && wParam != 'r') return 0;switch(wParam){case 'p':{pause = !pause;InvalidateRect(hwnd, NULL, TRUE);}break;case 'r':{for(int x = 0; x < XWIDTH; ++x)for(int y = 0; y < YHEIGHT; ++y)GameClient[x][y] = false;}SetTimer(hwnd, ID_TIMER, TIMERSET, NULL);direct= RIGHT;   //游戏开局,默认方向向右snake.pt.x= XWIDTH / 2;  //默认显示在游戏区中间位置snake.pt.y= YHEIGHT / 2;psLast= &snake;IsOver= false;pause= false;GameClient[snake.pt.x][snake.pt.y] = true;NewFood(hwnd);break;default:break;}return 0;case WM_PAINT:hdc = BeginPaint(hwnd, &ps);SetViewportOrgEx(hdc, SNAKEWIDTH, SNAKEWIDTH, NULL);//画游戏区的边框MoveToEx(hdc, -1, -1, NULL);LineTo(hdc, XWIDTH * SNAKEWIDTH + 1, -1);LineTo(hdc, XWIDTH * SNAKEWIDTH + 1, YHEIGHT * SNAKEWIDTH + 1);LineTo(hdc, -1, YHEIGHT * SNAKEWIDTH + 1);LineTo(hdc, -1, -1);TextOut(hdc, (XWIDTH + 1) * SNAKEWIDTH, 0, szScore, lstrlen(szScore));TextOut(hdc, (XWIDTH + 1) * SNAKEWIDTH, cyChar,szBuffer, wsprintf(szBuffer, TEXT("%4d"), Score));if(pause)TextOut(hdc, (XWIDTH + 1) * SNAKEWIDTH, 3 * cyChar, szPause, lstrlen(szPause));else if(IsOver)TextOut(hdc, (XWIDTH + 1) * SNAKEWIDTH, 3 * cyChar, szGameOver, lstrlen(szGameOver));SelectObject(hdc, GetStockObject(BLACK_BRUSH));for(x = 0; x < XWIDTH; ++x){for(y = 0; y < YHEIGHT; ++y){if(GameClient[x][y])Rectangle(hdc, x * SNAKEWIDTH, y * SNAKEWIDTH,(x + 1) * SNAKEWIDTH, (y + 1) * SNAKEWIDTH);}}return 0;case WM_DESTROY:KillTimer(hwnd, ID_TIMER);PostQuitMessage(0);return 0;}return DefWindowProc(hwnd, message, wParam, lParam);}