WinAPI双人贪吃蛇

来源:互联网 发布:ica算法 编辑:程序博客网 时间:2024/04/28 18:55

(上学期写的,确实很冗余的代码,菜鸟一枚还请大家包涵)

2个文件:snakeList.h和snake.cpp

首先是第一个:

#include <windows.h>#pragma oncetypedef struct tagNODE{POINT apt[4];struct tagNODE * previous, *next;}NODE;typedef struct tagSNAKE{int length;NODE *head, *tail;}SNAKE;
其次:

/*********************************************************    Wy05/21/2013**********************************************************/#include <windows.h>#include <cstdlib>#include <ctime>#include "snakeList.h"#define UNIT 30#define ID_TIMER_SPEED 1#define ID_TIMER_TIME  3enum direction{//记录蛇移动的方向UP, DOWN, RIGHT, LEFT}dire1,dire2;//判断是否吃到食物,作为全局变量,是因为如果写过程函数中,则后面的函数中//要用到eat,则需要给许多函数传入eat这个参数,太麻烦,所以设为全局变量。bool eat1 = false;//定义一个全局变量,当蛇遇到墙壁或者自身时,将其设置为truebool game_over = false;void square (HDC, POINT[]);void border (HDC);void drawSnake (HDC, SNAKE*);bool isBorder (POINT[]);bool isFood (POINT[], POINT[]);bool isSelf (SNAKE*, SNAKE*, POINT[]);void drawUp (SNAKE*, SNAKE*, POINT[]);void drawDown (SNAKE*, SNAKE*, POINT[]);void drawRight (SNAKE*, SNAKE*, POINT[]);void drawLeft (SNAKE*, SNAKE*, POINT[]);void runDef (SNAKE*, SNAKE*, direction*, POINT[]);void creatFood (SNAKE*, SNAKE*, POINT[]);void initializeSnake1(SNAKE*);void initializeSnake2(SNAKE*);void drawFood (HDC,POINT[]);void clearSnake(SNAKE*);void initializeGame (SNAKE*, SNAKE*);LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow){//注册窗口类static TCHARszAppName[] = TEXT ("snake");HWNDhwnd;MSGmsg;WNDCLASSwcls;wcls.cbClsExtra= 0;wcls.cbWndExtra= 0;wcls.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH);wcls.hCursor= LoadCursor (NULL, IDC_ARROW);wcls.hIcon= LoadIcon (NULL, IDI_APPLICATION);wcls.hInstance= hInstance;wcls.lpfnWndProc= WndProc;wcls.lpszClassName= szAppName;wcls.lpszMenuName= NULL;wcls.style= CS_HREDRAW | CS_VREDRAW;if (!RegisterClass (&wcls)){MessageBox (NULL, TEXT ("Program requires WinNT!"), szAppName, MB_ICONERROR);}//创建窗口hwnd = CreateWindow (szAppName, TEXT("snake"),WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX,CW_USEDEFAULT, CW_USEDEFAULT,23*UNIT-13, 15*UNIT,NULL, NULL, hInstance, NULL);//显示和更新窗口ShowWindow (hwnd, iCmdShow);UpdateWindow (hwnd);//消息循环while (GetMessage (&msg, NULL, 0, 0)){TranslateMessage (&msg);DispatchMessage (&msg);}return msg.wParam;}//过程函数LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){static intcxClient, cyClient;HDChdc;PAINTSTRUCTps;static SNAKEsnake1,snake2;//定义蛇结构体static POINTfood[4];//食物static boolisKeyDown = false;//是否有方向键按下static inttime;TCHARszBuffer[1000];switch (message){case WM_SIZE:cxClient = LOWORD (lParam);cyClient = HIWORD (lParam);return 0;case WM_CREATE:SetTimer (hwnd, ID_TIMER_SPEED, 200, NULL);//设定游戏速度定时器SetTimer (hwnd, ID_TIMER_TIME, 1000, NULL);//设定游戏时间定时器initializeSnake1(&snake1);//初始化蛇1initializeSnake2(&snake2);//初始化蛇2dire2 = RIGHT;//初始化为向右移动dire1 = RIGHT;//初始化为向右移动creatFood(&snake1,&snake2,food);//创建食物return 0;case WM_TIMER:switch (wParam){case ID_TIMER_SPEED:InvalidateRect (hwnd, NULL, TRUE);//如果设为FALSE,则蛇移动后会留下痕迹return 0;case ID_TIMER_TIME:++time;return 0;default:return 0;}case WM_CHAR:{switch (wParam){case 'w':if (dire2 != DOWN)//防止反向移动,以下类似{isKeyDown = true;dire2 = UP;//将方向更新drawUp(&snake2, &snake1, food);//更行蛇的结点坐标}return 0;case 's':if (dire2 != UP){isKeyDown = true;dire2 = DOWN;drawDown(&snake2, &snake1, food);}return 0;case 'd':if (dire2 != LEFT){isKeyDown = true;dire2 = RIGHT;drawRight(&snake2, &snake1, food);}return 0;case 'a':if (dire2 != RIGHT){isKeyDown = true;dire2 = LEFT;drawLeft(&snake2, &snake1, food);}return 0;}return 0;}case WM_KEYDOWN://按键控制{switch (wParam){case VK_UP:if (dire1 != DOWN)//防止反向移动,以下类似{isKeyDown = true;dire1 = UP;//将方向更新drawUp(&snake1, &snake2, food);//更行蛇的结点坐标}return 0;case VK_DOWN:if (dire1 != UP){isKeyDown = true;dire1 = DOWN;drawDown(&snake1, &snake2, food);}return 0;case VK_RIGHT:if (dire1 != LEFT){isKeyDown = true;dire1 = RIGHT;drawRight(&snake1, &snake2, food);}return 0;case VK_LEFT:if (dire1 != RIGHT){isKeyDown = true;dire1 = LEFT;drawLeft(&snake1, &snake2, food);}return 0;case VK_SPACE:KillTimer(hwnd,1);if (IDNO == MessageBox(hwnd,TEXT("回到游戏?"),TEXT("暂停游戏"),MB_YESNO)){PostQuitMessage(0);}else{SetTimer (hwnd, ID_TIMER_SPEED, 200, NULL);//恢复定时器}return 0;case VK_ESCAPE:KillTimer(hwnd,1);if (IDYES == MessageBox(hwnd,TEXT("退出游戏?"),TEXT("退出游戏"),MB_YESNO)){PostQuitMessage(0);}else{SetTimer (hwnd, ID_TIMER_SPEED, 200, NULL);//恢复定时器}return 0;default:return 0;}InvalidateRect (hwnd, NULL, TRUE);//使客户区无效return 0;}case WM_PAINT:hdc = BeginPaint (hwnd, &ps);border(hdc);//画边框if (!isKeyDown)//判断是否有键按下{runDef(&snake1,&snake2,&dire1,food);//如果没有,则按默认方式,即原方向移动runDef(&snake2,&snake2,&dire2,food);//如果没有,则按默认方式,即原方向移动}if (game_over){KillTimer(hwnd,1);//暂停定时器if (IDNO == MessageBox(hwnd,TEXT("Game Over! Try Again?"),TEXT("Snake!"),MB_YESNO)){PostQuitMessage(0);}else{initializeGame(&snake1,&snake2);time = 0;SetTimer (hwnd, ID_TIMER_SPEED, 200, NULL);//恢复定时器}}drawSnake (hdc, &snake1);//画蛇1drawSnake (hdc, &snake2);//画蛇2drawFood(hdc,food);//画食物TextOut(hdc,10,12*UNIT+3,TEXT("玩家1控制:上W,下S,左A,右D                玩家2控制:上↑,下↓,左←,右→"),50);TextOut(hdc,10,12*UNIT+25,TEXT("空格键:暂停游戏"),8);TextOut(hdc,150,12*UNIT+25,TEXT("Esc键:退出游戏"),9);TextOut(hdc,300,12*UNIT+25,szBuffer,wsprintf(szBuffer,TEXT("Player1 Score: %d"),snake1.length));TextOut(hdc,450,12*UNIT+25,szBuffer,wsprintf(szBuffer,TEXT("Player2 Score: %d"),snake2.length));TextOut(hdc,600,12*UNIT+25,szBuffer,wsprintf(szBuffer,TEXT("time: %d"),time));EndPaint (hwnd, &ps);isKeyDown = false;//将其恢复为falsereturn 0;case WM_DESTROY:KillTimer (hwnd, ID_TIMER_SPEED);PostQuitMessage (0);return 0;}return DefWindowProc (hwnd, message, wParam, lParam);}void square (HDC hdc, POINT apt[4]){//paint a square based on 4 pointsMoveToEx (hdc, apt[0].x, apt[0].y, NULL);LineTo (hdc, apt[1].x, apt[1].y);MoveToEx (hdc, apt[1].x, apt[1].y, NULL);LineTo (hdc, apt[2].x, apt[2].y);MoveToEx (hdc, apt[2].x, apt[2].y, NULL);LineTo (hdc, apt[3].x, apt[3].y);MoveToEx (hdc, apt[3].x, apt[3].y, NULL);LineTo (hdc, apt[0].x, apt[0].y);return;}void border (HDC hdc){//画出边框POINTborder[22][4];for (int i=0; i!=22; ++i){//初始化上边框的每个方格的四个点坐标border[i][0].x = i*UNIT;border[i][0].y = 0;border[i][1].x = (i+1)*UNIT;border[i][1].y = 0;border[i][2].x = (i+1)*UNIT;border[i][2].y = UNIT;border[i][3].x = i*UNIT;border[i][3].y = UNIT;}for (int i=0; i!=22; ++i){//画出上边框square (hdc, border[i]);}for (int i=0; i!=22; ++i){//初始化下边框每个方格的四个点坐标border[i][0].x = i*UNIT;border[i][0].y = 11*UNIT;border[i][1].x = (i+1)*UNIT;border[i][1].y = 11*UNIT;border[i][2].x = (i+1)*UNIT;border[i][2].y = 12*UNIT;border[i][3].x = i*UNIT;border[i][3].y = 12*UNIT;}for (int i=0; i!=22; ++i){//画出下边框square (hdc, border[i]);}for (int i=0; i!=10; ++i){//初始化左边框每个方格的四个点坐标border[i][0].x = 0;border[i][0].y = (i+1)*UNIT;border[i][1].x = UNIT;border[i][1].y = (i+1)*UNIT;border[i][2].x = UNIT;border[i][2].y = (i+2)*UNIT;border[i][3].x = 0;border[i][3].y = (i+2)*UNIT;}for (int i=0; i!=22; ++i){//画出左边框square (hdc, border[i]);}for (int i=0; i!=10; ++i){//初始化右边框每个方格的四个点坐标border[i][0].x = 21*UNIT;border[i][0].y = (i+1)*UNIT;border[i][1].x = 22*UNIT;border[i][1].y = (i+1)*UNIT;border[i][2].x = 22*UNIT;border[i][2].y = (i+2)*UNIT;border[i][3].x = 21*UNIT;border[i][3].y = (i+2)*UNIT;}for (int i=0; i!=22; ++i){//画出右边框square (hdc, border[i]);}return;}void drawSnake (HDC hdc, SNAKE* s){NODE* iter = s->head;for (int i=0; i!=s->length; ++i){square (hdc, iter->apt);iter = iter->next;}iter = NULL;free (iter);return;}bool isBorder (POINT apt[4]){if (apt[0].x==0 || apt[0].x==21*UNIT || apt[0].y==0 || apt[0].y==11*UNIT)return true;elsereturn false;}bool isFood (POINT food[4], POINT apt[4]){if (apt[0].x == food[0].x && apt[0].y == food[0].y)return true;elsereturn false;}bool isSelf (SNAKE* s1, SNAKE* s2, POINT apt[4]){NODE* current = s1->head;for (int i=0; i!=s1->length; ++i){if (current->apt[0].x==apt[0].x && current->apt[0].y==apt[0].y)return true;current = current->next;}current = s2->head;for (int i=0; i!=s2->length; ++i){if (current->apt[0].x==apt[0].x && current->apt[0].y==apt[0].y)return true;current = current->next;}return false;}void drawUp (SNAKE* s1, SNAKE* s2, POINT food[4]){POINT temp[4];//蛇头上方的方格temp[0].x = s1->head->apt[0].x;temp[0].y = s1->head->apt[0].y - UNIT;temp[1].x = s1->head->apt[1].x; temp[1].y = s1->head->apt[1].y - UNIT;temp[2] = s1->head->apt[1];temp[3] = s1->head->apt[0];if (isBorder(temp) || isSelf(s1, s2, temp)){//判断是否为墙或者自身game_over = true;}else if (isFood(food, temp)){//如果是食物,则只添加头结点NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?new_head->apt[0] = temp[0];new_head->apt[1] = temp[1];new_head->apt[2] = temp[2];new_head->apt[3] = temp[3];new_head->next = s1->head;s1->head->previous = new_head;s1->head = new_head;eat1 = true;s1->length++;if (eat1)creatFood(s1,s2,food);eat1 = false;}else{//为空。则添加头结点,删除尾结点NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?new_head->apt[0] = temp[0];new_head->apt[1] = temp[1];new_head->apt[2] = temp[2];new_head->apt[3] = temp[3];new_head->next = s1->head;s1->head->previous = new_head;s1->head= new_head;NODE* temp_tail;temp_tail = s1->tail;s1->tail = s1->tail->previous;s1->tail->next = NULL;free (temp_tail);}}void drawDown (SNAKE* s1, SNAKE* s2, POINT food[4]){POINT temp[4];//蛇头下方的方格temp[3].x = s1->head->apt[3].x;temp[3].y = s1->head->apt[3].y + UNIT;temp[2].x = s1->head->apt[2].x; temp[2].y = s1->head->apt[2].y + UNIT;temp[0] = s1->head->apt[3];temp[1] = s1->head->apt[2];if (isBorder(temp) || isSelf(s1,s2,temp)){//判断是否为墙或者自身game_over = true;}else if (isFood(food, temp)){//如果是食物,则只添加头结点NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?new_head->apt[0] = temp[0];new_head->apt[1] = temp[1];new_head->apt[2] = temp[2];new_head->apt[3] = temp[3];new_head->next = s1->head;s1->head->previous = new_head;s1->head= new_head;eat1 = true;s1->length++;if (eat1)creatFood(s1,s2,food);eat1 = false;}else{//为空。则添加头结点,删除尾结点NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?new_head->apt[0] = temp[0];new_head->apt[1] = temp[1];new_head->apt[2] = temp[2];new_head->apt[3] = temp[3];new_head->next = s1->head;s1->head->previous = new_head;s1->head= new_head;NODE* temp_tail;temp_tail = s1->tail;s1->tail = s1->tail->previous;s1->tail->next = NULL;free (temp_tail);}}void drawRight (SNAKE* s1, SNAKE* s2, POINT food[4]){POINT temp[4];//蛇头右方的方格temp[1].x = s1->head->apt[1].x + UNIT;temp[1].y = s1->head->apt[1].y;temp[2].x = s1->head->apt[2].x + UNIT; temp[2].y = s1->head->apt[2].y;temp[0] = s1->head->apt[1];temp[3] = s1->head->apt[2];if (isBorder(temp) || isSelf(s1, s2, temp)){//判断是否为墙或者自身game_over = true;}else if (isFood(food, temp)){//如果是食物,则只添加头结点NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?new_head->apt[0] = temp[0];new_head->apt[1] = temp[1];new_head->apt[2] = temp[2];new_head->apt[3] = temp[3];new_head->next = s1->head;s1->head->previous = new_head;s1->head = new_head;eat1 = true;s1->length++;if (eat1)creatFood(s1,s2,food);eat1 = false;}else{//为空。则添加头结点,删除尾结点NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?new_head->apt[0] = temp[0];new_head->apt[1] = temp[1];new_head->apt[2] = temp[2];new_head->apt[3] = temp[3];new_head->next = s1->head;s1->head->previous = new_head;s1->head  = new_head;NODE* temp_tail;temp_tail = s1->tail;s1->tail = s1->tail->previous;s1->tail->next = NULL;free (temp_tail);}}void drawLeft (SNAKE* s1, SNAKE* s2, POINT food[4]){POINT temp[4];//蛇头上方的方格temp[0].x = s1->head->apt[0].x - UNIT;temp[0].y = s1->head->apt[0].y;temp[3].x = s1->head->apt[3].x - UNIT; temp[3].y = s1->head->apt[3].y;temp[2] = s1->head->apt[3];temp[1] = s1->head->apt[0];if (isBorder(temp) || isSelf(s1, s2, temp)){//判断是否为墙或者自身game_over = true;}else if (isFood(food, temp)){//如果是食物,则只添加头结点NODE* new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?new_head->apt[0] = temp[0];new_head->apt[1] = temp[1];new_head->apt[2] = temp[2];new_head->apt[3] = temp[3];new_head->next = s1->head;s1->head->previous = new_head;s1->head= new_head;eat1 = true;s1->length++;if (eat1)creatFood(s1, s2, food);eat1 = false;}else{//为空。则添加头结点,删除尾结点NODE *new_head = (NODE*)malloc(sizeof(NODE));//在函数结束时,能否添加进去?new_head->apt[0] = temp[0];new_head->apt[1] = temp[1];new_head->apt[2] = temp[2];new_head->apt[3] = temp[3];new_head->next = s1->head;s1->head->previous = new_head;s1->head = new_head;NODE* temp_tail;temp_tail = s1->tail;s1->tail = s1->tail->previous;s1->tail->next = NULL;free (temp_tail);}}void runDef (SNAKE* s1, SNAKE* s2, direction* d, POINT food[4]){//默认移动方式,即按原方向移动switch (*d){case UP:drawUp(s1,s2,food);break;case DOWN:drawDown(s1,s2,food);break;case RIGHT:drawRight(s1,s2,food);break;case LEFT:drawLeft(s1,s2,food);break;default:break;}}void creatFood (SNAKE* snake1, SNAKE* snake2, POINT food[4]){do{//防止食物出现在蛇身srand((unsigned)time(NULL));//初始化时间种子int seedx = rand()%20 + 1;//设置食物随即出现的x坐标int seedy = rand()%10 + 1;//设置食物随即出现的y坐标food[0].x = seedx*UNIT;food[0].y = seedy*UNIT;food[1].x = (seedx + 1)*UNIT;food[1].y = seedy*UNIT;food[2].x = (seedx + 1)*UNIT;food[2].y = (seedy + 1)*UNIT;food[3].x = seedx*UNIT;food[3].y = (seedy + 1)*UNIT;} while (isSelf(snake1,snake2,food));}void drawFood (HDC hdc,POINT food[4]){square(hdc,food);}void initializeSnake1(SNAKE* snake1){NODE*one = (NODE*)malloc(sizeof(NODE));NODE*two = (NODE*)malloc(sizeof(NODE));NODE*three = (NODE*)malloc(sizeof(NODE));//初始化蛇的三个节点链接one->next= two;two->next= three;three->next= NULL;three->previous= two;two->previous= one;one->previous= NULL;//初始化蛇的三个节点坐标one->apt[0].x= 6*UNIT;one->apt[0].y= 3*UNIT;one->apt[1].x= 7*UNIT;one->apt[1].y= 3*UNIT;one->apt[2].x= 7*UNIT;one->apt[2].y= 4*UNIT;one->apt[3].x = 6*UNIT;one->apt[3].y = 4*UNIT;two->apt[0].x = 5*UNIT;two->apt[0].y = 3*UNIT;two->apt[1].x= 6*UNIT;two->apt[1].y= 3*UNIT;two->apt[2].x= 6*UNIT;two->apt[2].y= 4*UNIT;two->apt[3].x= 5*UNIT;two->apt[3].y = 4*UNIT;three->apt[0].x= 4*UNIT;three->apt[0].y= 3*UNIT;three->apt[1].x= 5*UNIT;three->apt[1].y= 3*UNIT;three->apt[2].x= 5*UNIT;three->apt[2].y= 4*UNIT;three->apt[3].x= 4*UNIT;three->apt[3].y= 4*UNIT;//初始化蛇snake1->length= 3;snake1->head= one;snake1->tail= three;}void initializeSnake2(SNAKE* snake2){NODE* one = (NODE*)malloc(sizeof(NODE));NODE* two = (NODE*)malloc(sizeof(NODE));NODE* three = (NODE*)malloc(sizeof(NODE));//初始化蛇的三个节点链接one->next= two;two->next= three;three->next= NULL;three->previous= two;two->previous= one;one->previous= NULL;//初始化蛇的三个节点坐标one->apt[0].x= 6*UNIT;one->apt[0].y= 6*UNIT;one->apt[1].x= 7*UNIT;one->apt[1].y= 6*UNIT;one->apt[2].x= 7*UNIT;one->apt[2].y= 7*UNIT;one->apt[3].x = 6*UNIT;one->apt[3].y = 7*UNIT;two->apt[0].x = 5*UNIT;two->apt[0].y = 6*UNIT;two->apt[1].x= 6*UNIT;two->apt[1].y= 6*UNIT;two->apt[2].x= 6*UNIT;two->apt[2].y= 7*UNIT;two->apt[3].x= 5*UNIT;two->apt[3].y = 7*UNIT;three->apt[0].x= 4*UNIT;three->apt[0].y= 6*UNIT;three->apt[1].x= 5*UNIT;three->apt[1].y= 6*UNIT;three->apt[2].x= 5*UNIT;three->apt[2].y= 7*UNIT;three->apt[3].x= 4*UNIT;three->apt[3].y= 7*UNIT;//初始化蛇snake2->length= 3;snake2->head= one;snake2->tail= three;}void clearSnake(SNAKE* snake){//删除蛇所有结点NODE* current = snake->head;while (current){NODE* temp = current;current = current->next;delete temp;temp = NULL;}}void initializeGame (SNAKE* snake1, SNAKE* snake2){//初始化游戏clearSnake(snake1);//删除原来蛇1所有结点clearSnake(snake2);//删除原来蛇2所有结点initializeSnake1(snake1);//初始化蛇1initializeSnake2(snake2);//初始化蛇2game_over = false;//恢复游戏dire1 = RIGHT;//初始化方向dire2 = RIGHT;//初始化方向}