zoukankan      html  css  js  c++  java
  • C图形化第一步

      之前的贪吃蛇都是在cmd下实现,每次都要调用cls刷新屏幕,简直是闪瞎了我的狗眼。

      度娘得知有一种方法可以避免闪烁,即:双缓冲。原理是先在内存中作图,然后将做好的图复制到前台,同时禁止背景刷新。

      主要使用函数:

        LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

        int WINAPI WinMain(HINSTANCE, HINSTANCE,PSTR, int);

      涉及主要方法:

    WNDCLASS wndclass; 
    wndclass.style=CS_HREDRAW|CS_VREDRAW;//位置改变时重绘 
    wndclass.lpfnWndProc=(WNDPROC)WndProc;//消息处理函数 
    wndclass.hInstance=0;//当前实例句柄 
    wndclass.hbrBackground=(HBRUSH)COLOR_WINDOWFRAME;//背景色 
    wndclass.lpszClassName=szWindowClass;//参窗口类名 
    wndclass.hIcon=0;//图标
    wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);//光标 
    wndclass.lpszMenuName=0;//菜单名称 
    wndclass.hIconSm=0;//最小化图标 
    RegisterClassEx(&wndclass);//注册窗口类

      CreateWindow:

    HWND CreateWindow(
    LPCTSTR lpClassName,    // 如果lpClassName是一个字符串,它指定了窗口的类名
    LPCTSTR lpWindowName,   // 指向一个指定窗口名的空结束的字符串指针,可使用lpWindowName来指定控制文本
    DWORD dwStyle,          // 指定创建窗口的风格, WS_CAPTION:创建一个有标题框的窗口
                            // WS_SYSMENU:创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格
    int x,    // 指定窗口的初始水平位置
            // 如果该参数被设为CW_USEDEFAULT则系统为窗口选择缺省的左上角坐标并忽略Y参数。
            // CW_USEDEFAULT只对层叠窗口有效,如果为弹出式窗口或子窗口设定,则X和y参数被设为零
    int y,  // 
    int nWidth, // 以设备单元指明窗口的宽度
                // 若nWidth是CW_USEDEFAULT,则系统为窗口选择一个缺省的高度和宽度:
                // 缺省宽度为从初始X坐标开始到屏幕的右边界,缺省高度为从初始Y坐标开始到目标区域的顶部。
                // CW_USEDEFAULT只对层叠窗口有效;如果为弹出式窗口和子窗口设定CW_USEDEFAULT标志则nWidth和nHeight被设为零。
    int nHeight, //
    HWND hWndParent, // 指向被创建窗口的父窗口或所有者窗口的句柄
    HMENU hMenu,     // 菜单句柄,或依据窗口风格指明一个子窗口标识
    HANDLE hlnstance, // 与窗口相关联的模块实例的句柄
    LPVOID lpParam   // 指向一个值的指针,该值传递给窗口WM_CREATE消息
    )
    // 返回值:如果函数成功,返回值为新窗口的句柄:如果函数失败,返回值为NULL。

      将字符贪吃蛇迁移过来,gcc 编译时需加 -mwindows 参数,如:

      gcc snake.c -mwindows

      代码如下:  

    #include <windows.h>
    #define ID_TIMER 1
    #define WIDTH 12     //
    #define HEIGHT 8     //
    #define DEBUG 0
    const char FENCE ='*';    // 栅栏
    const char HEAD  ='@';  // 蛇头
    const char BODY  ='#';  // 蛇身
    const char FOOD  ='O';  // 食物
    const char BLANK =' ';  // 空白
    char arr[HEIGHT][WIDTH];
    struct Snake{
        int y,x;
    }snake[WIDTH*HEIGHT];  // 结构体,保存坐标点
    int len=0,food=0,key=0,score=0,alive=1,direct=4,speed=1,full=(WIDTH-2)*(HEIGHT-2);  // 长度、食物、按键、总分、存活、方向、速度
    int uldr[5][2]={{},{-1,0},{0,-1},{1,0},{0,1}};  // 上、左、下、右
    
    void init(){           // 初始化游戏地图
        int y=0,x=0,start_pos=HEIGHT/2;
        for(y=0;y<HEIGHT;y++)
            for(x=0;x<WIDTH;x++)
                if( y == 0 || y == HEIGHT-1 || x == 0 || x == WIDTH-1 ){
                        arr[y][x] = FENCE;
                }
                else{
                    arr[y][x] = BLANK;
                }    
        snake[0].y=start_pos;
        snake[0].x=3;
        len++;
        snake[1].y=start_pos;
        snake[1].x=2;
        len++;    
        arr[ snake[0].y ][ snake[0].x ] = HEAD ;
        arr[ snake[1].y ][ snake[1].x ] = BODY ;    
    }
    
    void make_food(){
        int rx,ry;
        while(!food){
            rx = rand()%WIDTH;
            ry = rand()%HEIGHT;
            if(    arr[ry][rx] == BLANK ){
                arr[ry][rx]=FOOD;
                food=1;
                break;
            }
        }
    }
    
    void move(){
        int cnt=0;
        len++;  // 准备将当前位置放在snake数组首部
        if(DEBUG)printf("len:%d
    ",len);
        for(cnt=len-1;cnt>0;cnt--){
            snake[cnt].x=snake[cnt-1].x;
            snake[cnt].y=snake[cnt-1].y;    // 1234 变为 51234
        }
        snake[0].y+=uldr[direct][0];
        snake[0].x+=uldr[direct][1];    // 移动蛇头
    }
    
    void check_head(){
        int y=snake[0].y;
        int x=snake[0].x;
        int i=0;
        int cnt=0;
        if(y < 1 || y > HEIGHT-2 || x < 1 || x > WIDTH-2){  // 是否越界
            alive=0;
        }
        if( arr[y][x] == BODY ){  // 是否吃到自己
            alive=0;
        }
        if( arr[y][x] == BLANK){
            arr[y][x] = HEAD;
        }
        if( arr[y][x] == FOOD ){  // 吃到食物
            arr[y][x] = HEAD;
            score++;
            len++;
            food=0;
            snake[len-1].y=snake[len-2].y;  // 蛇尾增加一节蛇身
            snake[len-1].x=snake[len-2].x;
            make_food();
        }
        if(DEBUG)printf("len:%d
    ",len);
        if(DEBUG){
            for(;i<len;i++){
                printf("y,x:(%d,%d)
    ",snake[i].y,snake[i].x);
            }
        }
        arr[ snake[len-1].y ][ snake[len-1].x ]=BLANK;    // 先清除蛇尾显示
        len--;
        for(cnt=1;cnt<=len-1;cnt++){
            arr[ snake[cnt].y ][ snake[cnt].x ]=BODY;   // 蛇身显示
        }
    }
    
    void handle(){
        init();
        make_food();
        while(alive && len<full){
            move();
            check_head();
            speed=(speed > 9)?9:(score/5+1);
            if(alive){
                Sleep(1000-speed*100);  // 多久刷新一次
            }
        }
        if( len == full){
            printf("congratulations!
    ");
        }
        else{
            printf("you lose
    ");
        }
    }
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                PSTR szCmdLine, int iCmdShow)
    {
        static TCHAR szAppName[] = TEXT ("snake") ;
        HWND        hwnd ;
        MSG        msg ;
        WNDCLASS    wndclass ;
    
        wndclass.style        = CS_HREDRAW | CS_VREDRAW ;
        wndclass.lpfnWndProc    = WndProc ;
        wndclass.cbClsExtra    = 0 ;
        wndclass.cbWndExtra    = 0 ;
        wndclass.hInstance    = hInstance ;
        wndclass.hIcon        = LoadIcon (NULL, IDI_APPLICATION) ;
        wndclass.hCursor    = LoadCursor (NULL, IDC_ARROW) ;
        wndclass.hbrBackground    = (HBRUSH) GetStockObject (BLACK_BRUSH) ;
        wndclass.lpszMenuName    = NULL ;
        wndclass.lpszClassName    = szAppName ;
    
        if(!RegisterClass (&wndclass))
        {
            MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ;
            return 0;
        }
    
        hwnd = CreateWindow (szAppName, TEXT("snake"),
                    WS_CAPTION | WS_SYSMENU ,  //| WS_THICKFRAME,
                    0, 0,
                    240, 240,
                    NULL, NULL, hInstance,
                    NULL) ;
    
        ShowWindow (hwnd, SW_SHOW) ; //显示
        UpdateWindow (hwnd) ;
        //ShowCursor(FALSE); //隐藏鼠标光标
        
        while (GetMessage (&msg, NULL, 0, 0))
        {
            TranslateMessage (&msg) ;
            DispatchMessage (&msg) ;
        }
        ShowCursor(TRUE); //显示鼠标光标
        return msg.wParam ;
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
          HDC      hdc ;
          static  HDC hdcMem;
          HFONT    hFont;
          static  HBITMAP hBitmap;
          static  int cxScreen, cyScreen; //屏幕的宽度 高度.
          static  int iFontWidth=10, iFontHeight=15; //字体的宽度 高度
    
          switch (message)
          {
        case WM_CREATE:
            cxScreen = GetSystemMetrics(SM_CXSCREEN) ; //屏幕宽度
            cyScreen = GetSystemMetrics(SM_CYSCREEN) ;
    
            hdc = GetDC(hwnd);
            hdcMem = CreateCompatibleDC(hdc);
            hBitmap = CreateCompatibleBitmap(hdc, cxScreen, cyScreen);
            SelectObject(hdcMem, hBitmap);
            ReleaseDC(hwnd, hdc);
            //创建字体
            hFont = CreateFont(iFontHeight, iFontWidth-5, 0, 0, FW_NORMAL, 0, 0, 0,
                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
                    DRAFT_QUALITY, FIXED_PITCH | FF_SWISS, TEXT("Fixedsys"));
            SelectObject(hdcMem, hFont);
            DeleteObject (hFont) ;
            SetBkMode(hdcMem, TRANSPARENT); //设置背景模式为 透明
            init();
            make_food();
    
        case WM_TIMER:
            hdc = GetDC(hwnd);
            PatBlt (hdcMem, 0, 0, cxScreen, cyScreen, BLACKNESS) ; //将内存设备映像刷成黑色
            int y,x,size_s,size_p,size_l,size_w;
            TCHAR sText[64],pText[64],lText[64],wText[64];
            
            move();
            check_head();
            speed=(speed > 9)?9:(score/5+1);
            SetTimer (hwnd, ID_TIMER, (1000-speed*100), NULL) ;
            size_s = wsprintf( sText,TEXT("your score: %d"),score);   // 计算字符长度
            size_p = wsprintf( pText,TEXT("current speed: %d"),speed);
            size_l = wsprintf( lText,TEXT("you lose"));
            size_w = wsprintf( wText,TEXT("you win"));
            SetTextColor(hdcMem, RGB(220, 220, 220));   // 字体颜色
            
            TextOut(hdcMem, 0, 0 , sText, size_s);        // hdc、x坐标、y坐标、字符地址、字符长度
            TextOut(hdcMem, 0, 15, pText, size_p);
            if(alive && len<full){
                for(y=0 ; y<HEIGHT ; y++ ){
                    for(x=0 ; x<WIDTH ; x++ ){               
                        TextOut(hdcMem, x*10, (y+2)*15, &arr[y][x], 1);
                    }
                }
            }
            else{  
                for(y=0 ; y<HEIGHT ; y++ )
                    for(x=0 ; x<WIDTH ; x++ )
                        if( y==0 || y==HEIGHT-1 || x==0 || x==WIDTH-1){               
                            TextOut(hdcMem, x*10, (y+2)*15, &arr[y][x], 1); 
                        }      
                if(alive == 0){
                    TextOut(hdcMem, 30, (2+HEIGHT/2)*15,  lText, size_l);
                }else{
                    TextOut(hdcMem, 30, (2+HEIGHT/2)*15,  wText, size_w);
                }
                BitBlt(hdc, 0, 0, cxScreen, cyScreen, hdcMem, 0, 0, SRCCOPY);
                KillTimer (hwnd, ID_TIMER) ;
            }
            BitBlt(hdc, 0, 0, cxScreen, cyScreen, hdcMem, 0, 0, SRCCOPY);
            ReleaseDC(hwnd, hdc);          
            return 0;
    
        case WM_RBUTTONDOWN:
            KillTimer (hwnd, ID_TIMER) ;
            return 0;
    
        case WM_RBUTTONUP:
            SetTimer (hwnd, ID_TIMER, 10, NULL) ;
            return 0;
    
        // 按下 w a s d 时
        case WM_CHAR:
            switch (wParam){
            case 'w' : direct=(direct == 3)?3:1;break;
            case 'a' : direct=(direct == 4)?4:2;break;
            case 's' : direct=(direct == 1)?1:3;break;
            case 'd' : direct=(direct == 2)?2:4;break;
            default : direct;
            }
            return 0;
        //处理善后工作
        case WM_DESTROY:
            KillTimer (hwnd, ID_TIMER) ;
            DeleteObject(hBitmap);
            DeleteDC(hdcMem);
            PostQuitMessage (0) ;
            return 0 ;
        }
        return DefWindowProc (hwnd, message, wParam, lParam) ;
    }
    View Code
  • 相关阅读:
    Hadoop之MapReduce
    Hadoop之序列化
    Hadoop之mapreduce 实例五
    Hadoop之hive和hadoop的交互流程
    protel总结1
    将正数十进制转换为2~16进制数
    基于verilog分频器总结
    MATLAB设计FIR滤波器
    centos7+hadoop完全分布式集群搭建
    Linux下常用配置文件
  • 原文地址:https://www.cnblogs.com/wbjxxzx/p/4602348.html
Copyright © 2011-2022 走看看