// 游戏控制的一个主要流程。 // 当计时器发生时进行的处理逻辑。 void OnTimer(HWND hwnd) { // 计时器到时以后,蛇移动一步。 // 根据以后以后的状态,进行后续处理。 switch (SnakeMove()) { // 如果蛇已经死了 case SNAKE_DEAD: // 首先关闭计时器,避免在计时器的驱动下再次调用本函数 KillTimer(hwnd, TIMER_ID); // 然后通知玩家,Game Over了,退出进程。 MessageBox(0, "Game Over", "Game Over", 0); ExitProcess(0); break; // 如果蛇吃到了食物 case SNAKE_EATEN_FOOD: // 计分; score++; // 创建新的食物。食物是一个全局唯一变量。 CreateFood(); // 蛇进行生长,然后判断蛇生长以后的状态,进行后续处理。 switch (SnakeGorwup()) { // 玩家赢了,停止计时器。 case SNAKE_COMPLETE: KillTimer(hwnd, TIMER_ID); // 通知玩家,退出进程,结束游戏。 MessageBox(0, "You Win!", "You Win", 0); ExitProcess(0); break; // 发生错误,停止计时器,并退出。 case SNAKE_ERROR: KillTimer(hwnd, TIMER_ID); MessageBox(hwnd, "Error!!", "Error!1", MB_OK); ExitProcess(0); break; // 没有结束,也没有错误,正常吃到食物。 case SNAKE_GROWUP: // 判断计分,是否升级。 if (IS_SPEEDUP(score)) { level++; SpeedUp(hwnd); } break; } //switch (SnakeGorwup()) 结束 break; case SNAKE_MOVED: break; } return; }
//改变方向 void CSnakeGame::ChangeDirection(int iDirection) { //如果是相同方向或者游戏不是运行中状态,则返回 if (m_enGameState != GAMESTATE_RUNNING || m_iSnakeDirection == iDirection) { return; } //按钮音效 PLAY_EFFECT(EFFECT_CHANGE2); //设置方向 int nOldDirection = m_iSnakeDirection; m_iSnakeDirection = iDirection; //如果是反方向 if (iDirection == OPPSITE_DIRECTION[nOldDirection]) { //转换 int iNodeCount = m_mapSnakeNodes.size(); for (int i = 0; i < iNodeCount / 2; ++i) { POSITION stTempPos = m_mapSnakeNodes[i]; m_mapSnakeNodes[i] = m_mapSnakeNodes[iNodeCount - 1 - i]; m_mapSnakeNodes[iNodeCount - 1 - i] = stTempPos; } //获取下一个位置 POSITION stHeaderPos = m_mapSnakeNodes[0]; GetNextPos(stHeaderPos); //是否可以按照反方向移动,不能则恢复之前的方向 if (CheckGameOver(stHeaderPos)) { m_iSnakeDirection = nOldDirection; } } //移动 SnakeMove(); //重置时间 m_fWaitRefreshTime = 0; }
LRESULT CALLBACK windProc(HWND hwnd,UINT Message,WPARAM wParam,LPARAM lParam) { int i; static HDC hdc; static HDC hdcDes; static HBITMAP hBitMap[BMPS]; static BITMAP bitMap; static HINSTANCE hInstance; static HBRUSH hBrush; static RECT rectStartButton;//开始游戏按钮区 static PAINTSTRUCT ps; static POINT mouseLocation; static int x,y; hBrush = CreateSolidBrush(RGB(255,255,255)); switch (Message) { case WM_CREATE: hInstance = ((LPCREATESTRUCT)lParam)->hInstance; hBitMap[0] = LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_BRICK));//墙 hBitMap[1] = LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_NUMERS));//分数 hBitMap[2] = LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_SCORE));//得分字样 hBitMap[3] = LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_GAMELEVEL));//游戏等级字样 hBitMap[4] = LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_ANIMATE));//开机动画的贴图 hBitMap[5] = LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_GAMESTART));//游戏开始按钮 hBitMap[6] = LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_WORDSNAKE));//snake四个英文字母 hBitMap[7] = LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_SNAKE));//蛇的身体以及食物 hBitMap[8] = LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_STARTCHANGE));//鼠标放在开始按钮上时改变颜色 hBitMap[9] = LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_GAMEOVER));//GAMEOVER四个字母 srand((unsigned)time(NULL)); SetClientRect(hwnd,704,576); return 0; case WM_SIZE: GetClientRect(hwnd,&rectClient); rectSnake.left = rectClient.left+32; rectSnake.top = rectClient.top+32; rectSnake.bottom = rectClient.bottom-32; rectSnake.right = rectClient.left+17*32; rectStartButton.left = rectSnake.left+150; rectStartButton.right = rectStartButton.left+236; rectStartButton.top = rectSnake.bottom-100; rectStartButton.bottom = rectStartButton.top+79; return 0; case WM_KEYDOWN: switch (wParam) { case VK_SPACE: Pause = !Pause; if(Pause) { if(GameState != 1) { GameLevel = 1; GameState = 1; SnakeLength = 1; GameSpeed = 200; Snake[0].x = rectSnake.left+160;//初始化蛇头坐标信息 Snake[0].y = rectSnake.left+160; x = Snake[0].x; y = Snake[0].y; } SetTimer(hwnd,GAMETIMER,GameSpeed,NULL);//设置时间计时器 } else KillTimer(hwnd,GAMETIMER); break; case VK_ESCAPE: int result; result = MessageBox(NULL,TEXT("你确定要退出游戏吗?"),TEXT("Warning!"),MB_YESNO|MB_ICONWARNING); switch (result) { case IDYES: DestroyWindow(hwnd); break; case IDNO: break; default: break; } break; case VK_LEFT: if(MoveDirection != 2) MoveDirection = 1; return 0; case VK_RIGHT: if(MoveDirection != 1) MoveDirection = 2; return 0; case VK_UP: if(MoveDirection != 4) MoveDirection = 3; return 0; case VK_DOWN: if(MoveDirection != 3) MoveDirection = 4; return 0; } return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case ID_ABOUT: DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIABOUT),NULL,AboutProc); break; case ID_GAMESTART://点击菜单中的开始游戏按钮开始游戏 GameLevel = 1; GameState = 1; SnakeLength = 1; GameSpeed = 200; SetTimer(hwnd,GAMETIMER,GameSpeed,NULL);//设置时间计时器 Snake[0].x = rectSnake.left+160;//初始化蛇头坐标信息 Snake[0].y = rectSnake.left+160; x = Snake[0].x; y = Snake[0].y; Pause = TRUE; break; case ID_GAMEQUIT: KillTimer(hwnd,GAMETIMER); ReleaseDC(hwnd,hdc); DestroyWindow(hwnd); exit(0); break ; } return 0; case WM_PAINT: hdc = GetDC(hwnd); hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd,&rectClient); hdcDes = CreateCompatibleDC(hdc); Draw(hwnd,hdc,hBitMap,rectClient); if(GameState == 0) { DrawAnimate(hwnd,hdc,hBitMap,rectSnake);//开机动画 } else if(GameState == 1) { FillRect(hdc,&rectSnake,hBrush); SelectObject(hdcDes,hBitMap[7]); GetObject(hBitMap[7],sizeof(BITMAP),&bitMap); if(!food.state) BitBlt(hdc, food.foodLocation.x, food.foodLocation.y, bitMap.bmWidth, bitMap.bmHeight/2,hdcDes,0,16,SRCCOPY); for(i =0;i<SnakeLength;i++) { BitBlt(hdc, Snake[i].x, Snake[i].y, bitMap.bmWidth, bitMap.bmHeight/2,hdcDes,0,0,SRCCOPY); } } else if(GameState == 2) { DrawGameOver(hwnd,hdc,hBitMap,9); KillTimer(hwnd,GAMETIMER); } DeleteDC(hdcDes); EndPaint(hwnd,&ps); Flag = FALSE; return 0; case WM_TIMER: if(GameState == 1) { if(MoveDirection == 4) { x= x; y = y +16; } else if(MoveDirection == 3) { x = x; y = y - 16; } else if(MoveDirection == 2) { x = x+16; y = y; } else if(MoveDirection == 1) { x = x -16; y = y; } SnakeMove(x,y); InvalidateRect(hwnd,&rectSnake,FALSE); } return 0; case WM_LBUTTONDOWN: mouseLocation.x = LOWORD(lParam); mouseLocation.y = HIWORD(lParam); if(GameState == 0) { if(PtInRect(&rectStartButton,mouseLocation))//点击开始游戏按钮开始游戏 { GameLevel = 1; GameState = 1; SnakeLength = 1; GameSpeed = 200; SetTimer(hwnd,GAMETIMER,GameSpeed,NULL);//设置时间计时器 Snake[0].x = rectSnake.left+160;//初始化蛇头坐标信息 Snake[0].y = rectSnake.left+160; x = Snake[0].x; y = Snake[0].y; Pause = TRUE; } } return 0; //按钮效果实现 case WM_MOUSEMOVE: TRACKMOUSEEVENT TrackME; mouseLocation.x = LOWORD(lParam); mouseLocation.y = HIWORD(lParam); TrackME.cbSize = sizeof(TrackME); TrackME.dwFlags = TME_LEAVE | TME_HOVER; TrackME.hwndTrack = hwnd; TrackME.dwHoverTime = 1;//持续多长算HOVER TrackMouseEvent(&TrackME); if(GameState == 0) { if(PtInRect(&rectStartButton,mouseLocation)) { FillRect(hdc,&rectStartButton,hBrush); SetCursor(LoadCursor(NULL,IDC_HAND)); DrawButton(hwnd,hdc,hBitMap,rectStartButton,8); } else { FillRect(hdc,&rectStartButton,hBrush); DrawButton(hwnd,hdc,hBitMap,rectStartButton,5); } } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,Message,wParam,lParam); }
//更新 void CSnakeGame::Play(float dt) { if (m_enGameState == GAMESTATE_RUNNING) { //刷新标记 bool bNeedRefreshFlag = false; m_fWaitRefreshTime += dt; float fMaxTime = m_bImproveSpeed ? 50 : (SNAKE_MOVE_INTERVAL - 30 * m_iSpeed); if (m_fWaitRefreshTime >= fMaxTime) { m_fWaitRefreshTime = 0; SnakeMove(); bNeedRefreshFlag = true; } m_fAppleShowTime += dt; if (m_fAppleShowTime >= APPLE_REFRESH_INTERVAL) { m_fAppleShowTime = 0; m_bAppleState = !m_bAppleState; bNeedRefreshFlag = true; } //是否需要刷新界面 if (!bNeedRefreshFlag) { return; } } else if (m_enGameState == GAMESTATE_PASS) { //时间更新 m_fWaitRefreshTime += dt; if (m_fWaitRefreshTime < GAMEPASS_REFRESH_INTERVAL) { return; } m_fWaitRefreshTime = 0; if (m_iAddScoreCount < GAMEPASS_ADDCOUNT) { ++m_iAddScoreCount; m_iScore += GAMEPASS_ADDSCORE; m_pGameScene->UpdateScore(m_iScore); return; } else { //更新速度和等级 if (++m_iSpeed > 10) { m_iSpeed = 0; if (++m_iLevel > 10) { m_iLevel = 0; } } //更新显示 m_pGameScene->UpdateLevel(m_iLevel); m_pGameScene->UpdateSpeed(m_iSpeed); //重置数据 InitData(); } } else if (m_enGameState == GAMESTATE_OVER) { //时间更新 m_fWaitRefreshTime += dt; if (m_fWaitRefreshTime < BOOM_REFRESH_INTERVAL) { return; } m_fWaitRefreshTime = 0; if (m_iShowBoomCount < BOOM_SHOWCOUNT) { m_bShowBoom = !m_bShowBoom; ++m_iShowBoomCount; } else { //设置剩余生命 --m_iLife; m_pGameScene->UpdateSmallBricks(); //检查是否有剩余生命,没有则返回游戏结束界面 if (m_iLife <= 0) { m_pGameScene->RunScene(SCENE_GAMEOVER); return; } //重置数据 InitData(); } } m_pGameScene->UpdateBricks(); }