贪吃蛇小游戏

这几天跟别人学习制作了一个小游戏,现在分享一下.

贪吃蛇,一个经典的小游戏,

 

开发环境vs2017

 

在WinMain函数中,窗口创建显示完成后添加一句SendMessage(hWnd,WM_SIZE,0,0)来调整窗口的大小,

//主函数WinMain()

int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,

         _In_ LPSTR lpCmdLine, _In_ int nShowCmd)

{

 

         //类名

         TCHAR cls_name[] = TEXT("MyWinClass");

 

         //设计窗口类

         WNDCLASSEX wce = { 0 };

 

         wce.cbSize = sizeof(WNDCLASSEX);

         wce.style = CS_HREDRAW | CS_VREDRAW;

         wce.lpfnWndProc = WindowProc;

         wce.cbClsExtra = 0;

         wce.cbWndExtra = 0;

         wce.hInstance = hInstance;

         wce.hIcon = LoadIcon(hInstance, IDI_APPLICATION);

         wce.hIconSm = wce.hIcon;

         wce.hCursor = LoadCursor(NULL, IDC_ARROW);

         wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);/*::GetStockObject(BLACK_BRUSH)*/ /*黑色刷子*/

         wce.lpszMenuName = NULL;

         wce.lpszClassName = cls_name;

 

         //注册窗口类

         //ATOM nres = RegisterClassEx(&wce);

         if (FALSE == RegisterClassEx(&wce))

                   return 1;

 

         //创建窗口

         HWND hWnd = CreateWindowEx(

                   WS_EX_APPWINDOW,

                   cls_name,

                   TEXT("我的窗口"),

                   WS_OVERLAPPEDWINDOW,

                   200, 120, 600, 400,

                   NULL, NULL, hInstance,

                   NULL);

 

         //回调函数要写上默认的处理DefWindowProc,不然创建失败

         if (!hWnd)

                   return 1;

 

         //显示,更新窗口

         ShowWindow(hWnd, SW_SHOW);

         UpdateWindow(hWnd);

         //调整窗口大小

         SendMessage(hWnd, WM_SIZE, 0, 0);

         //添加加速键表

         HACCEL hAccel = NULL;/*::LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1);*/

 

         //消息循环

         MSG msg;

         while (GetMessage(&msg, NULL, 0, 0))

         {

                   if (!TranslateAccelerator(hWnd, hAccel, &msg))//有加速键表时用这,没有就不用

                   {

                            TranslateMessage(&msg);

                            DispatchMessage(&msg);

                   }

 

         }

 

 

         return 0;

}

 

2.在WM_SIZE消息中

 

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

         switch (uMsg)

         {

        

                   case WM_DESTROY:

                            PostQuitMessage(0);

                            break;

 

                   case WM_SIZE:

                   {

                            hdc = GetDC(hWnd);

                            RECT crc, wrc;

                            GetClientRect(hWnd, &crc);

                            GetWindowRect(hWnd, &wrc);

                            int bordrewidth=(wrc.right - wrc.left) - (crc.right - crc.left);

                            int bordreheight = (wrc.bottom - wrc.top) - (crc.bottom - crc.top);

                            SetWindowPos(hWnd, NULL, 0, 0,

                                     600 + bordrewidth, 600 + bordreheight, SWP_NOMOVE);

                            OnStart(hWnd);  //启动游戏

                            ReleaseDC(hWnd, hdc);

                   }break;

    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);

}

 

这样就固定了窗口大小,不能改变.

 

3.在窗口上划分格子(我只分了横竖20)

定义全局变量

HDC hdc;

int row = 20;              //20行

int col = 20;                //20列

#define WIDTH        30     //格子的宽度

#define HEIGHT      30     //格子的高度

#define MAXSIZE   50     //蛇身最大长度

POINT m_food;                 //随机食物坐标

//定义贪吃蛇的结构体

struct Snake

{

         POINT m_pos[MAXSIZE];  //身体每个格子的坐标

         int len;   //身体个数

         int m_direction;  //前进方向

}m_snake;

 

 

 

在WM_PAINT消息中添加MyPaint()函数画格子

 

case WM_PAINT:

                   {

                            PAINTSTRUCT ps;

                            hdc = ::BeginPaint(hWnd, &ps);

                            {

                                     MyPaint(hdc);

                            }

                            EndPaint(hWnd, &ps);

          }break;

 

下面就是MyPaint函数的实现

 

void MyPaint(HDC hdc)

{

         HBRUSH hbr = CreateSolidBrush(RGB(255, 0, 0));  //定义红色画刷

         HGDIOBJ hOldBrh = SelectObject(hdc, hbr);

         for (int y=0;y<row;y++)

         {

                   for (int x=0;x<col;x++)

                   {

                            Rectangle(hdc, x*WIDTH, y*HEIGHT, (x + 1)*WIDTH, (y + 1)*HEIGHT);  //画格了,行20,列20

                   }

         }

         SelectObject(hdc, hOldBrh);

 

         HBRUSH bhrgreen = CreateSolidBrush(RGB(0, 255, 0));  //绿色画刷

         hOldBrh = SelectObject(hdc, bhrgreen);

         for (int n=0;n<m_snake.len;n++)

         {

                   Rectangle(hdc, m_snake.m_pos[n].x*WIDTH, m_snake.m_pos[n].y*HEIGHT,

                            (m_snake.m_pos[n].x+1)*WIDTH,(m_snake.m_pos[n].y+1)*HEIGHT);  //画蛇的身体

         }

         SelectObject(hdc, hOldBrh);

 

         HBRUSH hbrblue = CreateSolidBrush(RGB(0, 0, 255));  //蓝色画刷

         hOldBrh = SelectObject(hdc, hbrblue);

         Rectangle(hdc, m_food.x*WIDTH, m_food.y*HEIGHT,

                   (m_food.x + 1)*WIDTH, (m_food.y + 1)*HEIGHT);  //画随机食物

     SelectObject(hdc, hOldBrh);

}

 

 

//随机食物坐标

void generatefood()

{

         srand((unsigned)time(NULL));

         m_food.x = rand() % 20;

         m_food.y = rand() % 20;

}

 

//初始化蛇

void init_snake()

{

         m_snake.len = 3;

         m_snake.m_pos[0].x = 0;

         m_snake.m_pos[0].y = 0;

         m_snake.m_direction = 1;

         for (int n = 1; n < MAXSIZE; n++)

         {

                   m_snake.m_pos[n].x = -1;

                   m_snake.m_pos[n].y = -1;

 

         }

 

         generatefood();

}

 

下面就是启动游戏了

 

void OnStart(HWND hWnd)

{

         init_snake();

         SetTimer(hWnd, 1, 300, NULL); //设置时间

}

 

在WM_TIMER消息中

case WM_TIMER:

                   {

            //循环输出蛇身位置

                            for (int n = m_snake.len - 1; n >= 1; n--)

                            {

                                     m_snake.m_pos[n] = m_snake.m_pos[n - 1];

                            }

              //判断前进方向

                            if (0 == m_snake.m_direction)//向上

                                     m_snake.m_pos[0].y = m_snake.m_pos[0].y - 1;

                            if (1 == m_snake.m_direction)//向右

                                     m_snake.m_pos[0].x = m_snake.m_pos[0].x + 1;

                            if (2 == m_snake.m_direction)//向下

                                     m_snake.m_pos[0].y = m_snake.m_pos[0].y + 1;

                            if (3 == m_snake.m_direction)//向左

                                     m_snake.m_pos[0].x = m_snake.m_pos[0].x - 1;

              //碰到食物蛇身+1,重新随机食物坐标

                            if (m_snake.m_pos[0].x == m_food.x&&m_snake.m_pos[0].y == m_food.y)

                            {

                                     m_snake.len++;

                                     generatefood();

                            }

              //判断蛇头碰墙,就Game over

                            if (m_snake.m_pos[0].x > 19 || m_snake.m_pos[0].y > 19 || m_snake.m_pos[0].x < 0 || m_snake.m_pos[0].y < 0)

                            {

                                     KillTimer(hWnd, 1);

                                     if (IDYES == MessageBox(hWnd, TEXT("Game over,你想重新开始吗?"),

                                               TEXT("提示"), MB_YESNO))

                                     {

                                               OnStart(hWnd);

                                     }

                                     else

                                     {

                                               PostQuitMessage(0);

                                     }

                            }

                            hdc = GetDC(hWnd);

                            MyPaint(hdc);//重绘窗口所有数据

                            ReleaseDC(hWnd, hdc);

 

                   }break;

 

接下来还有方向控制了,这简单

在WM_KEYDOWN消息中给蛇的m_direction赋值就行了

case WM_KEYDOWN:

                   {

                            switch (wParam)

                            {

                            case VK_UP:

                                     m_snake.m_direction = 0;

                                     break;

                            case VK_RIGHT:

                                     m_snake.m_direction = 1;

                                     break;

                            case VK_DOWN:

                                     m_snake.m_direction = 2;

                                     break;

                            case VK_LEFT:

                                     m_snake.m_direction = 3;

                                     break;

                            }

                   }break;

 

效果:

 

 贪吃蛇小游戏

 

 

 贪吃蛇小游戏

 

 

 

 

 

 

 

 

当然还有很多少足处,比如蛇的头可以从身体中穿过.

 贪吃蛇小游戏

 

 

 

这些以后再弄了,先学习学习嘛

 

上一篇:SSH配置与讲解


下一篇:面试:TCP协议经典十五连问!