// 蛇生长 int SnakeGorwup() { // 给新的节点分配内存 PGAME_COORD pNewTail; PGAME_COORD pTail; // 倒数第一节点 PGAME_COORD pLastButOne; // 倒数第二节点 int size = GetSnakeSize(); if (size >= boundary.x*boundary.y-1) //长到最长了,游戏结束!~ return SNAKE_COMPLETE; if (size == 0) // 没有头,不知从何生长,返回错误。 return SNAKE_ERROR; pNewTail = (PGAME_COORD)malloc(sizeof(GAME_COORD)); if (size == 1) // 只有一个节点,按照当前的移动方向生长。 { pTail = (PGAME_COORD)GetSnakeTail(); switch (snake_dir) { case SNAKE_LEFT: pNewTail->x = pTail->x + 1; pNewTail->y = pTail->y; break; case SNAKE_RIGHT: pNewTail->x = pTail->x - 1; pNewTail->y = pTail->y; break; case SNAKE_UP: pNewTail->x = pTail->x ; pNewTail->y = pTail->y + 1; break; case SNAKE_DOWN: pNewTail->x = pTail->x; pNewTail->y = pTail->y - 1; break; } } else // 有两个以上节点,取倒数第一和倒数第二计算生长方向。 { pTail = (PGAME_COORD)GetSnakeTail(); pLastButOne = (PGAME_COORD)GetSnakeAt(size - 2); // 沿着倒数第二->倒数第一的方向,添加一个新的节点。 pNewTail->x = pTail->x + (pTail->x - pLastButOne->x); pNewTail->y = pTail->y + (pTail->y - pLastButOne->y); } // 新节点放入到蛇尾的位置 ListPushBack(snake_list, pNewTail); return SNAKE_GROWUP; }
void GamePaint(HWND hwnd) { /******************************************************************************* * ########## 关于 GDI ########## * * GDI的全称是Graphics Device Interface,图形设备接口。 * GDI是Windows系统中最基础的图形图像接口,我们在这里演示的是GDI中最基础的部分, * 但是对于编写贪吃蛇这样的小游戏已经足够用了。 * * 来看GDI最基础的三个概念: * 1、DC:DC的全称是Device Context,绘制操作在此进行。可以类比理解为一块画布,对应屏幕的一个区域。 * GDI的绘制操作必须在一个DC上进行,因此第一步就是得到DC的句柄,BeginPaint或者GetDC函数。 * 2、GDI对象:包括PEN、BRUSH、FONT等,每一种绘制操作都会使用到一个或者多个GDI对象, * 所以,在绘制操作之前必须的一个操作是将绘制所用的GDI对象放入DC中,使用SelectObject函数完成。 * 3、绘制操作:即在DC上使用被选择如DC中的GDI对象绘制图形、线条、文字等。 * 如LineTo画出线条、Ellipse画出(椭)圆、Rectangle画出矩形、TextOut输出文字 * * 使用GDI输出各类图像有其特定的流程,如下: *******************************************************************************/ HPEN hpen; //HBRUSH hbrush; HDC hdc, hdcmem; HBITMAP hbmMem; HPEN hPenBoundary; HPEN hOldPen; HBRUSH hbrushFood; HBRUSH hBrushSnake; HBRUSH hOldBrush; HFONT hFont, hOldFont; RECT rect; PGAME_COORD pSnakeBody; PGAME_COORD lpFood; int i, snake_size; GetClientRect(hwnd, &rect); hdc = GetDC(hwnd); // 注意 CreateCompatibleDC 中的这一段话: // Before an application can use a memory DC for drawing operations, // it must select a bitmap of the correct width and height into the DC. // To select a bitmap into a DC, use the CreateCompatibleBitmap function // 注意: // http://msdn.microsoft.com/en-us/library/windows/desktop/dd183488(v=vs.85).aspx hdcmem = CreateCompatibleDC(hdc); hbmMem = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top); SelectObject(hdcmem, hbmMem); // 创建需要用到的PEN和BRUSH hbrushFood = CreateSolidBrush(COLOR_FOOD); // RGB颜色,实心BRUSH hpen = CreatePen(PS_NULL, 0, RGB(0, 0, 0)); // PEN, PS_NULL表示不可见 hBrushSnake = CreateSolidBrush(COLOR_SNAKE); hPenBoundary = CreatePen(0, 3, COLOR_BOUNDARY); /******************************************************************************* * ############# 画背景 ################ * *******************************************************************************/ FillRect(hdcmem, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); /******************************************************************************* * ############# 画食物 ################ * *******************************************************************************/ // 将画图需要用的PEN和BRUSH选择到DC中 hOldBrush = (HBRUSH)SelectObject(hdcmem, hbrushFood); hOldPen = (HPEN)SelectObject(hdcmem, hpen); lpFood = GetFood(); // (椭)圆形,使用上面选择的PEN勾勒边框,BRUSH填充 Rectangle(hdcmem, lpFood->x * CELL_PIXEL + rectBoundary.left, lpFood->y * CELL_PIXEL + rectBoundary.top, (lpFood->x + 1)*CELL_PIXEL + rectBoundary.left, (lpFood->y + 1)*CELL_PIXEL + rectBoundary.top); /******************************************************************************* * ############# 画蛇 ################ * *******************************************************************************/ SelectObject(hdcmem, hBrushSnake); snake_size = GetSnakeSize(); for (i = 0; i < snake_size; i++) { pSnakeBody = (PGAME_COORD)GetSnakeAt(i); Rectangle(hdcmem, pSnakeBody->x * CELL_PIXEL + rectBoundary.left, pSnakeBody->y * CELL_PIXEL + rectBoundary.top, (pSnakeBody->x + 1)*CELL_PIXEL + rectBoundary.left, (pSnakeBody->y + 1)*CELL_PIXEL + rectBoundary.top); } /******************************************************************************* * ############# 画墙 ################ * *******************************************************************************/ SelectObject(hdcmem, hPenBoundary); // 将PEN移动到需要绘制的方框的左上角 MoveToEx(hdcmem, rectBoundary.left, rectBoundary.top, NULL); // 画了一个方框。演示LineTo函数 LineTo(hdcmem, rectBoundary.left, rectBoundary.bottom); LineTo(hdcmem, rectBoundary.right, rectBoundary.bottom); LineTo(hdcmem, rectBoundary.right, rectBoundary.top); LineTo(hdcmem, rectBoundary.left, rectBoundary.top); /******************************************************************************* * ############# 写一行字 ################ * *******************************************************************************/ // 创建了一个字体对象 hFont = CreateFont(48, 0, 0, 0, FW_DONTCARE, 0, 1, 0, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Consolas")); // 将这个FONT对象放入DC中 if (hOldFont = (HFONT)SelectObject(hdcmem, hFont)) { CHAR szSourceInfo[1024]; wsprintf(szSourceInfo, "score %d level %d", GetScore(), GetLevel()); // 设置输出颜色 SetTextColor(hdcmem, COLOR_TEXT); // 输出字符串。 TextOut(hdcmem, rectBoundary.left + 3, rectBoundary.bottom + 3, szSourceInfo, lstrlen(szSourceInfo)); // 输出完成,将原来的字体对象放回DC中 SelectObject(hdcmem, hOldFont); } // 在内存DC中画完,一次输出的窗口DC上。 BitBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, hdcmem, 0, 0, SRCCOPY); /******************************************************************************* * ############# 回收和释放资源 ################ * *******************************************************************************/ // 回收资源 // DeleteObject 释放GDI对象 DeleteObject(hbmMem); DeleteObject(hdcmem); DeleteObject(hbrushFood); DeleteObject(hBrushSnake); DeleteObject(hpen); DeleteObject(hPenBoundary); DeleteObject(hFont); /******************************************************************************* * ############# ReleaseDC 函数 ################ * 释放占用的DC等系统资源。 *******************************************************************************/ ReleaseDC(hwnd, hdc); }