简陋版贪吃蛇

/***********************【程序说明】********************************/
//                文件名:snake.c 
//                介绍:win32贪吃蛇程序
//                作者:茫静无
//                时间:2022/1/12
//                参考:《Windows程序设计第五版》 Charles Petzold著
/******************************************************************/

//-------------------------------【头文件包含部分】-------------------------------
// 描述:引入必要的头文件
//-------------------------------------------------------------------------------
//windows编程嘛,当然需要包含windows头文件,以便使用windosAPI函数编程
#include <windows.h> 
#include <stdlib.h> 

//-------------------------------【宏定义部分】------------------------------------
// 描述:定义一些辅助的宏
//--------------------------------------------------------------------------------
//定义两宏表示窗口的大小
#define  WND_WIDTH   800
#define  WND_HEIGHT  600

//定义表示界面元素的宏
#define   WALL      -2   //表示墙体
#define   EMPTY      0   //表示没有物体的位置
#define   HEAD       1   //表示蛇头

//-------------------------------【全局结构体声明部分】----------------------------
// 描述:声明一些结构体
//--------------------------------------------------------------------------------
//声明一个蛇的相关信息的SNAKE结构体
typedef struct{
    int head_x;//蛇头在第几格
    int head_y;
    int tail_x;//蛇尾在第几格
    int tail_y;
    char direction;//蛇前进方向
}SNAKE;

//声明一个表示食物信息的结构体
typedef struct{
    int x;
    int y;
}FOOD;


//-------------------------------【WndProc()函数声明】----------------------------
// 描述:下面声明一个窗口过程(回调)函数。当事件发生时,Windows会系统调用该函数,
//我们可以为我们感兴趣的事件写上处理代码。
//--------------------------------------------------------------------------------
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

//-------------------------------setNewTail()函数声明】----------------------------
// 描述:找到新的蛇尾的位置,并通过第二个和第三个参数带回
//--------------------------------------------------------------------------------
void setNewTail(const int canvas[][50] ,int row,int* tail_x, int* tail_y);




//定义一个WinMain函数,类似与c语言控制台程序要定义一个main函数来作为入口函数
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                    PSTR szCmdLine, int iCmdShow)
{
    /**************************************************************************/
    //Step1:创建一个窗口类,填写窗口的特征
    /**************************************************************************/
    HWND        hwnd;   //定义一个窗口句柄
    MSG         msg;    //定义一个消息结构
    WNDCLASS   wndclass;    //定义一个窗口类
    static TCHAR AppName[] = TEXT("snake"); //给我们的窗口类取一个名字
    //给窗口类各字段赋值
    wndclass.style              = CS_HREDRAW | CS_VREDRAW; //设置为窗口大小发生改变时要重新绘制
    wndclass.lpfnWndProc        = WndProc;  //为窗口类绑定窗口过程函数
    wndclass.cbClsExtra         = 0;    //设为0即可,不必深究
    wndclass.cbWndExtra         = 0;    //设为0即可
    wndclass.hInstance          = hInstance;
    //为应用程序设定一个手绘的图标,!!!必须要严格的ico格式图标文件!!!
    wndclass.hIcon              = (HICON) LoadImage( NULL, TEXT("snake.ico"), IMAGE_ICON, 
                                                    0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
    wndclass.hCursor            = LoadCursor (NULL, IDC_ARROW); //使用默认的鼠标指针
    //选择一个喜欢颜色的画刷,系统会用这种颜色把我们的窗口背景刷成黑色
    wndclass.hbrBackground      = (HBRUSH) GetStockObject (BLACK_BRUSH);    
    wndclass.lpszClassName      = AppName;  //前面已经取好了的名字
    /*****************************************************************************************/


    /*******************************************************************************/
    //Step2:注册窗口类,告诉Windows我们的窗口属性已经设定好了
    /*******************************************************************************/
    if ( !RegisterClass (&wndclass) )
    {
        // 如果注册失败,输出提示信息
        MessageBox (NULL, TEXT("error!!!"), TEXT("snake"), MB_ICONERROR);

        return 0;
    }

    //创建窗口
    hwnd = CreateWindow ( AppName,               //窗口类名称
                          TEXT("snake"),         //窗口的标题
                          WS_OVERLAPPEDWINDOW,   //默认这样就好了
                          CW_USEDEFAULT,         //窗口出现的x坐标,设为默认的好了
                          CW_USEDEFAULT,         //窗口出现的y坐标
                          WND_WIDTH,             //窗口的宽度
                          WND_HEIGHT,            //窗口的高度
                          NULL,                  //剩余参数,不用深究
                          NULL,
                          hInstance,
                          NULL);

    ShowWindow (hwnd, iCmdShow);//显示窗口,这个时候实实在在可以看到我们的窗口了
    //接下来显示内容
    UpdateWindow (hwnd);
    //消息循环
    while (GetMessage (&msg, NULL, 0 ,0))
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    } 

    return msg.wParam;
}



/*******************************************************************************/
//step3:在窗口过程中写游戏主体代码
/*******************************************************************************/

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC                     hdc;//定义一个设备dc,方便绘图
    PAINTSTRUCT              ps;
    static RECT            rect;
    //将贪吃蛇界面分成60x50个小格子,创建一个二维数组存储界面信息:
    //    -2  ------------  代表墙体  ----------  WALL 
    //    -1  ------------  代表食物  ----------  FOOD
    //     0  ------------  代表无元素----------  EMPTY
    //     1  ------------  代表蛇头  ----------  HEAD
    //     2-n -----------  代表蛇身  
    static int s_canvas[60][50] = {EMPTY}; 
    static SNAKE s_snake;
    int row,col;
    HPEN            pen;
    HBRUSH          hBrush;
    static  FOOD    food;
    switch (message)
    {
        /***********************************************/
        //step4: 在WM_CREATE中进行游戏的初始化
        /************************************************/
        case WM_CREATE:
            GetClientRect(hwnd,&rect);
            //初始化墙体
            for (row=0; row<60; row++)
            {
                s_canvas[row][0] = -2;
                s_canvas[row][49] = -2;
            }
            for (col=0; col<50; col++)
            {
                s_canvas[0][col] = -2;
                s_canvas[59][col] = -2;
            }
            //初始化一个蛇体,方向向右
            s_canvas[33][25] = HEAD;
            s_canvas[32][25] = 2;//蛇体大于1
            s_canvas[31][25] = 3;
            s_canvas[30][25] = 4;
            s_snake.direction = 'R';
            s_snake.head_x = 33;
            s_snake.head_y = 25;
            s_snake.tail_x = 30;
            s_snake.tail_y = 25;
            //下面来手动生成一个食物
            food.x =  45;
            food.y = 45;
            s_canvas[food.x][food.y] = -1;
            SetTimer(hwnd,1,300,NULL);//由于机制问题,这种定时方式不准,简单起见,将就着用
            break;

        /*********************************************************************/
        //step5:在timer消息中进行状态更新,不直接更新界面,而是更新s_canvas的内容
        /********************************************************************/
        case WM_TIMER:
            for (col=0; col < 50; col++)
            { 
                for (row=0; row < 60; row++) 
                {
                    if (s_canvas[row][col] > 0)
                    {
                        s_canvas[row][col] = s_canvas[row][col] + 1;
                    }
                    
                }
            }
            //边界检查
            switch(s_snake.direction)
            {
                case 'R':
                    if ( !(s_snake.head_x == 58) && !(s_canvas[s_snake.head_x+1][s_snake.head_y] > 0))//向右没撞墙也没有撞到自己
                    {
                        s_canvas[++s_snake.head_x][s_snake.head_y] = 1;//新蛇头
                    }
                    else
                    {
                        exit(0);
                    }
                    break;
                case 'D':
                    if ( !(s_snake.head_y == 48) && !(s_canvas[s_snake.head_x][s_snake.head_y+1] > 0))
                    {
                        s_canvas[s_snake.head_x][++s_snake.head_y] = 1;
                    }
                    else
                    {
                        exit(0);
                    } 
                    break;
                case 'L':
                    if ( !(s_snake.head_x == 1) && !(s_canvas[s_snake.head_x-1][s_snake.head_y] > 0) )
                    {
                        s_canvas[--s_snake.head_x][s_snake.head_y] = 1;
                    }
                    else
                    {
                        exit(0);
                    }
                    break;
                case 'U':
                    if ( !(s_snake.head_y == 1) && !(s_canvas[s_snake.head_x][s_snake.head_y-1] > 0))
                    {
                        s_canvas[s_snake.head_x][--s_snake.head_y] = 1;
                    }
                    else
                    {
                        exit(0);
                    }
                    break;
            }
            
            if ( !(s_snake.head_x == food.x && s_snake.head_y == food.y) )//如果蛇没有吃到食物
            {
                //设置新蛇尾的位置
                s_canvas[s_snake.tail_x][s_snake.tail_y] = 0;
                setNewTail(s_canvas,60,&s_snake.tail_x,&s_snake.tail_y);
            }
            else 
            {
                //生成一个新的食物
                food.x = rand() % 58 + 1;
                food.y = rand() % 48 + 1;
                while ( s_canvas[food.x][food.y] > 0 )
                {
                    food.x = rand() % 48 + 1;
                }
                s_canvas[food.x][food.y] = -1;
            }
            //间接发送WM_PAINT消息
            //第三个参数为FALSE表示重绘时不擦除原来显示的内容,可以防止画面闪烁
            InvalidateRect(hwnd,NULL,TRUE);
            break;

        //step6:在此处进行游戏界面的绘制
        case WM_PAINT://在该消息中根据s_canvas的内容进行界面的绘制
            hdc = BeginPaint (hwnd, &ps);//绘图从此处开始
            pen = CreatePen(PS_INSIDEFRAME,1,RGB(255,0,0));//创建红色画笔
            SelectObject (hdc,pen);//将画笔选入当前设备
            //绘制界面
            hBrush = CreateSolidBrush(RGB(0,255,0));//创建绿色画刷
            SelectObject(hdc,hBrush);//将画刷选入当前设备
            for (col=0; col < 50; col++)
            {
                for (row=0; row < 60; row++)   
                {
                    //绘制蛇身
                    if (s_canvas[row][col] > 1)
                    {
                        Rectangle(hdc,row*10,col*10,row*10+10,col*10+10);
                    }
                    //绘制蛇头
                    if (s_canvas[row][col] == 1)
                    {
                        Ellipse(hdc,row*10,col*10,row*10+10,col*10+10);
                    }
                    //绘制食物
                    if (s_canvas[row][col] == -1 )
                    {
                        Ellipse(hdc,row*10,col*10,row*10+10,col*10+10);
                    }
                    //绘制墙体
                    if (s_canvas[row][col] == -2)
                    {
                        Rectangle(hdc,row*10,col*10,row*10+10,col*10+10);
                    }    
                }
            }
            EndPaint (hwnd, &ps);//绘图结束
            break;

        case WM_KEYDOWN://在键盘按下消息中处理蛇前进方向的设置
            switch(wParam)
            {
                case  'W'://此处的大写W只代表键盘上的字母键W被按下,与你输入时的大小写状态无关
                case VK_UP://设置蛇的运动方向为向上
                    if ( s_snake.direction  != 'D')//做判断是为了防止蛇出现反向运动
                    {
                        s_snake.direction = 'U';
                    }
                    break;
                
                case   'S':
                case VK_DOWN://设置运动方向向下
                    if ( s_snake.direction != 'U')
                    {
                        s_snake.direction = 'D';
                    }
                    break;

                case   'A':
                case VK_LEFT://设置运动方向向左
                    if ( s_snake.direction != 'R')
                    {
                        s_snake.direction = 'L';
                    }
                    break;

                case  'D':
                case VK_RIGHT://设置运动方向向右
                    if ( s_snake.direction != 'L')
                    {
                        s_snake.direction = 'R';
                    }
                    
                    break;  
            }

            break;

        case WM_DESTROY://在此处进行善后工作

            PostQuitMessage(0);//保证程序彻底退出
            break;
        
    }
    return DefWindowProc (hwnd, message, wParam, lParam);
}

//找到新蛇尾的位置
void setNewTail(const int canvas[][50] , int row, int* tail_x, int* tail_y)
{
    int r,col;
    for (r=0; r < row; r++)
    {
        for (col=0; col < 50; col++)
        {
            if (canvas[r][col] > canvas[*tail_x][*tail_y])
            {
                *tail_x = r;
                *tail_y = col;
            }
        }
    }
    
}

运行截图:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值