库的具体文档可以通过头文件右键转到文档查看详细解析

案例:画直线,并且给直线上色,并改变线的风格

  1. #include<graphics.h>//绘图库文件 graphics(绘图,图案);使用绘图文件,说明书在选中右键可以查找到具体的使用手册
  2. #include<conio.h>//con(console) i(input) o(output) 类似的有:stdio.h; iostream
  3. /*
  4. 十六进制表示颜色
  5. 0xbbggrr
  6. 二进制范围
  7. 0~255
  8. */
  9. int main()
  10. {
  11. initgraph(640, 480); //initialization(初始化) 初始化一个绘图屏幕
  12. setlinecolor(RGB(255, 255, 0)); //给线条上色,这里时黄色;为什么颜色的数值时255,因为二进制算法最终的结果就是255
  13. line(200, 240, 440, 240); //画直线 起点坐标(200,240) 终点(440,240)
  14. setlinecolor(0x0000ff); //<==>RGB(255,0,0) 二进制:11111111 <==> 2^7 + 2^6 + 2^5 + 2^4 + 2^3 + 2^2 + 2^1 + 2^0 == 255;1111 == 15 十六进制:0 1 2 3 4 5 6 7 8 9 a b c d e f
  15. setlinestyle(PS_DASH, 6);//更改线的样式,第一个填的是线的类型,第二个是线的粗细
  16. line(320, 120, 320, 360);
  17. _getch(); //get char:从控制台输入一个字符,输入字符
  18. closegraph(); //关闭屏幕窗口
  19. return 0;
  20. }

案例:渐变

  1. #include<graphics.h>
  2. #include<conio.h>
  3. int main()
  4. {
  5. initgraph(640, 480);
  6. //x轴方向逐像素绘制一条直线
  7. for (int i = 1; i < 255; i++)
  8. {
  9. setlinecolor(RGB(255 - i, 0, 0));
  10. line(128 + i, 120, 128 + i, 400);
  11. }
  12. _getch();
  13. closegraph();
  14. return 0;
  15. }

输出结果:
image.png


案例:隔行上色画线

  1. #include<graphics.h>
  2. #include<conio.h>
  3. int main()
  4. {
  5. initgraph(640, 480);
  6. for (int y = 100, flag = 1; y < 200; y += 20)
  7. {
  8. if (flag)
  9. {
  10. setcolor(RGB(255, 0, 0));
  11. flag = 0;
  12. }
  13. else
  14. {
  15. setcolor(RGB(0, 0, 255));
  16. flag = 1;
  17. }
  18. line(100, y, 300, y);
  19. }
  20. _getch();
  21. closegraph();
  22. return 0;
  23. }

输出结果:
image.png


案例:棋盘格

棋盘格一

  1. #include<graphics.h>
  2. #include<conio.h>
  3. int main()
  4. {
  5. //设置每隔多少像素输出一条直线
  6. int step = 30;
  7. initgraph(600, 600);
  8. setbkcolor(YELLOW); //设置背景颜色
  9. cleardevice(); //用设置的颜色刷一遍背景色
  10. setlinestyle(PS_SOLID,2); //设置直线为实线,宽为两个像素
  11. setcolor(RGB(0, 0, 0)); //设置为黑色
  12. for (int i = 1; i <= 19; i++) //画线
  13. {
  14. line(i * step, 1 * step, i * step, 19 * step); //竖线
  15. line(1 * step, i * step, 19 * step, i * step); //横线
  16. }
  17. _getch();
  18. closegraph();
  19. return 0;
  20. }

输出结果:
image.png

棋盘格二

  1. #include<graphics.h>
  2. #include<conio.h>
  3. int main()
  4. {
  5. int step = 50;
  6. initgraph(500, 500);
  7. setbkcolor(YELLOW); //设置背景颜色
  8. cleardevice(); //清空背景色
  9. setlinestyle(PS_SOLID,2); //设置直线为实线,宽为两个像素
  10. setcolor(RGB(0, 0, 0)); //设置为黑色
  11. for (int i = 1; i <= 8; i++) //画线
  12. {
  13. for (int j = 1; j <= 8; j++)
  14. {
  15. if ((i+j)%2 ==1)
  16. {
  17. //绘制黑色砖块
  18. setfillcolor(BLACK);
  19. solidrectangle(i * step, j * step, (i + 1) * step, (j + 1) * step);
  20. }
  21. else
  22. {
  23. //绘制白色砖块
  24. setfillcolor(WHITE);
  25. solidrectangle(i * step, j * step, (i + 1) * step, (j + 1) * step);
  26. }
  27. }
  28. }
  29. _getch();
  30. closegraph();
  31. return 0;
  32. }

输出结果:
image.png


案例:直线扫描动画

  1. #include<graphics.h>
  2. #include<conio.h>
  3. int main()
  4. {
  5. initgraph(640, 480);
  6. for (int y = 0; y <= 480; y++)
  7. {
  8. //绘制绿色线
  9. setlinecolor(GREEN);
  10. line(0, y, 640, y);
  11. //延时
  12. Sleep(10);
  13. //绘制黑色线(就是擦除掉之前画的线)
  14. setlinecolor(BLACK);
  15. line(0, y, 640, y);
  16. }
  17. _getch();
  18. closegraph();
  19. return 0;
  20. }

输出结果:
test 2021-10-21 18-00-34.gif


案例:小球视窗内反弹,并且接近中心处停止运动,开始变大并改变颜色

  1. #include<graphics.h>
  2. #include<conio.h>
  3. int main()
  4. {
  5. initgraph(640, 480);
  6. //小球初始位置
  7. int x = 80;
  8. int y = 160;
  9. //小球x,y方向的加速度
  10. int a = 4;
  11. int b = 4;
  12. //圆的半径
  13. int r = 20;
  14. while (1)
  15. {
  16. x = x + a; //x方向的偏移
  17. y = y + b; //y方向的偏移
  18. //小球碰撞到四边的反应
  19. if (x >= 620) //当x碰到到右边墙时做反弹
  20. {
  21. a = -a;
  22. }
  23. if (y >= 460) //当y碰到到地面时做反弹
  24. {
  25. b = -b;
  26. }
  27. if (x <= 20) //当x碰到到左边墙时做反弹
  28. {
  29. a = -a;
  30. }
  31. if (y <= 20) //当y碰到到顶面时做反弹
  32. {
  33. b = -b;
  34. }
  35. //这里的条件相当于定义了一个正方形在中心,小球碰到这个正方形就退出该循环
  36. if (x >= 300 && x <= 340 && y >= 220 && y <= 260)
  37. {
  38. break;
  39. }
  40. //渲染一个绿色填充,黄色边框的园
  41. setfillcolor(GREEN);
  42. setlinecolor(YELLOW);
  43. fillcircle(x, y, r);
  44. //延时
  45. Sleep(10);
  46. //用一个黑色圆覆盖掉之前的圆
  47. setfillcolor(BLACK);
  48. setlinecolor(BLACK);
  49. fillcircle(x, y, r);
  50. }
  51. //进入新的循环,给圆变色,并且放大
  52. for (r = 20; r < 200; r += 3)
  53. {
  54. //绘制一个红的色的圆
  55. setfillcolor(RED);
  56. setlinecolor(RED);
  57. fillcircle(x, y, r);
  58. Sleep(10);
  59. setfillcolor(BLACK);
  60. setlinecolor(BLACK);
  61. fillcircle(x, y, r);
  62. }
  63. _getch();
  64. closegraph();
  65. return 0;
  66. }

输出结果:
test 2021-10-21 18-12-27.gif


案例:小球垂直弹跳

  1. #include<graphics.h>
  2. #include<conio.h>
  3. int main()
  4. {
  5. initgraph(600, 600);
  6. float y = 100; //小球y坐标
  7. float a = 0; //小球y方向速度
  8. float g = 0.5; //小球加速度,y方向
  9. while (1)
  10. {
  11. //这里的解释可以参考下图输出的数据
  12. //清屏操作
  13. cleardevice();
  14. //这行是小球下落的计算
  15. a = a + g;//利用加速度更新小球y方向的速度,形成小球加速的效果的关键
  16. y = y + a;//利用y方向的速度更新y轴坐标
  17. //当小球下落,碰到地面,开始执行语句
  18. if (y >= 580)
  19. {
  20. //这里让速度方向变为负数,让小球反向移动,这里的特性会让小球做往复运动,而不是只返回一次
  21. a = -0.98 * a;//乘上一个0.98,是阻尼,让小球更快静止下来
  22. }
  23. //防止小球穿过地面
  24. if (y > 580)
  25. {
  26. y = 580;
  27. }
  28. //绘制一个填充圆
  29. fillcircle(300, y, 20);
  30. //图像停留时间相当于图像消失前的延迟,决定图像保留多久
  31. Sleep(10);
  32. if(fabs(a) < 0.1 && y ==580) //等小球接近不动时跳出循环;fabs(a)是a的绝对值
  33. {
  34. break;
  35. }
  36. }
  37. _getch();
  38. closegraph();
  39. return 0;
  40. }

运行结果:
image.pngtest-2021-10-21-18-17-31.gif


案例:按键盘上的a或d控制小球的左右移动

  1. #include<graphics.h>
  2. #include<conio.h>
  3. int main()
  4. {
  5. initgraph(400, 400);
  6. int x = 200;
  7. int y = 200;
  8. char input = 0;
  9. while (1)
  10. {
  11. if (_kbhit()) //输入键盘
  12. {
  13. input = _getch(); //获取键盘字符
  14. //判断字符
  15. //a向左移
  16. if(input == 'a' || input == 'A')
  17. {
  18. x-=4;
  19. }
  20. //d向右移
  21. if(input == 'd' || input == 'D')
  22. {
  23. x+=4;
  24. }
  25. }
  26. cleardevice();
  27. setlinecolor(YELLOW);
  28. setfillcolor(GREEN);
  29. fillcircle(x, y, 20);
  30. //设置字体,并输出当前在输入的按键字符
  31. settextstyle(40, 0, _T("黑体"));
  32. outtextxy(50, 30, input);
  33. Sleep(20);
  34. }
  35. _getch();
  36. closegraph();
  37. return 0;
  38. }

输出结果:
test-2021-10-21-21-55-40.gif


案例:随机像素

#include<graphics.h>
#include<conio.h>
#include<iostream>
using namespace std;

int main()
{
    srand(time(0));//这个一定要写在rand前面

    initgraph(600, 400);

    while (!_kbhit())
    {
        //生成随机像素以及随机颜色
        int x = rand() % 600;
        int y = rand() % 400; 
        int r = rand() % 256;
        int g = rand() % 256;
        int b = rand() % 256;

        putpixel(x, y, RGB(r, g, b));
        Sleep(1);
    }

    closegraph();

    return 0;
}

输出结果
test-2021-10-21-21-01-21.gif


案例:别碰方块小游戏

#include <graphics.h>
#include <conio.h>
#include <stdio.h>

int main()
{
    float width, height, gravity;                           // 游戏画面宽高、重力加速度
    float ball_x, ball_y, ball_vy, radius;                  // 小球圆心坐标、y方向速度、半径
    float rect_left_x, rect_top_y, rect_width, rect_height, rect_vx; // 方块障碍物的相关参数

    int score = 0;                                          // 得分
    width = 600;                                            // 游戏画面高度
    height = 400;                                            // 游戏画面宽度
    gravity = 0.6;                                          // 重力加速度
    initgraph(width, height);                                // 新建画布

    radius = 20;                                            // 小球半径
    ball_x = width / 4;                                        // 小球x位置
    ball_y = height - radius;                               // 小球y位置
    ball_vy = 0;                                            // 小球初始y速度为0
    int isBallOnFloor = 1;                                  // 小球是否在地面上

    rect_height = 100;                                      // 方块高度
    rect_width = 20;
    rect_left_x = width * 3 / 4;                            // 方块坐标x坐标
    rect_top_y = height - rect_height;                      // 方块顶部y坐标
    rect_vx = -3;                                           // 方块x方向速度

    while (1)
    {
        if (_kbhit())                                       // 当按键时
        {
            char input = _getch();                          // 获得输入字符
            if (input == ' ' && isBallOnFloor == 1)         // 当按下空格键时
            {
                ball_vy = -18;                              // 给小球一个向上的初速度
                isBallOnFloor = 0;                          // 小球不在地面上了
            }
        }

        ball_vy += gravity;                  // 根据重力加速度更新小球y方向速度
        ball_y += ball_vy;                     // 根据小球y方向速度更新其y坐标
        if (ball_y >= height - radius)       // 如果小球落到地面上
        {
            ball_vy = 0;                     // y速度为0
            ball_y = height - radius;        // 避免落到地面下
            isBallOnFloor = 1;               // 小球回到地面上
        }

        rect_left_x = rect_left_x + rect_vx; // 方块向左移
        if (rect_left_x <= 0)                // 如果方块跑到最左边
        {
            rect_left_x = width;             // 在最右边重新出现
            score++;                         // 得分加1
            rect_height = rand() % int(height / 4) + height / 4;  // 设置随机高度
            rect_vx = rand() / float(RAND_MAX) * 4 - 7;           // 设置方块随机速度
        }

        if ((rect_left_x <= ball_x + radius)
            && (rect_left_x + rect_width >= ball_x - radius)
            && (height - rect_height <= ball_y + radius))         // 如果小球碰到方块
        {
            Sleep(100);
            score = 0;                       // 得分清零
        }

        cleardevice();                       // 清空画面
        fillcircle(ball_x, ball_y, radius);  // 绘制小球
        fillrectangle(rect_left_x, height - rect_height, rect_left_x + rect_width, height);  // 画方块

        TCHAR s[20];                         // 定义字符串数组
        swprintf_s(s, _T("%d"), score);       // 将score转换为字符串
        settextstyle(40, 0, _T("宋体"));     // 设置文字大小、字体
        outtextxy(50, 30, s);                // 输出得分文字
        Sleep(10);
    }
    closegraph();
    return 0;
}

输出结果:
test-2021-10-21-21-30-12.gif


案例:旋转蛇

#include <graphics.h>  
#include <conio.h>
#include <stdio.h>
#include <time.h> 
int main()
{
    float Pi = 3.14159;  // 圆周率Pi
    initgraph(800,600); // 打开一个窗口
    setbkcolor(RGB(128,128,128)); // 设置背景颜色为灰色
    cleardevice();  // 以背景颜色清空画布
    srand(time(0)); // 随机种子函数

    int centerX,centerY; // 圆心坐标
    int radius; // 圆半径    
    int i;
    float offset;  // 同一半径各组扇形之间的角度偏移量
    float totalOffset; // 不同半径之间的角度偏移量
    while(1)  // 重复执行
    {    
        for (centerX = 100;centerX<800;centerX=centerX+200) // 对圆心x坐标循环
        {
            for (centerY = 100;centerY<600;centerY=centerY+200) // 对圆心y坐标循环
            {
                totalOffset = 0; // 同一半径各组扇形之间的角度偏移量
                float h = rand()%180; // 随机色调
                COLORREF  color1 = HSVtoRGB(h,0.9,0.8); // 色调1生成的颜色1
                COLORREF  color2 = HSVtoRGB(h+180,0.9,0.8); // 色调2生成的颜色2
                for (radius=100;radius>0;radius=radius-20) // 半径从大到小绘制
                {
                    int left = centerX - radius; // 圆外切矩形左上角x坐标
                    int top = centerY - radius; // 圆外切矩形左上角y坐标
                    int right = centerX + radius; // 圆外切矩形右下角x坐标
                    int bottom = centerY + radius; // 圆外切矩形右下角y坐标    
                    for (i=0;i<20;i++) // 绕着旋转一周,绘制扇形区域
                    {
                        offset = i*Pi/10 + totalOffset; // 各组扇形之间偏移的角度
                        setfillcolor(color1); // 色调1生成的颜色1
                        solidpie(left,top,right,bottom,offset,2*Pi/60+offset); 
                        setfillcolor(RGB(255,255,255));// 设置填充颜色为白色
                        solidpie(left,top,right,bottom,2*Pi/60+offset,3*Pi/60+offset); 
                        setfillcolor(color2); // 色调2生成的颜色2
                        solidpie(left,top,right,bottom,3*Pi/60+offset,5*Pi/60+offset); 
                        setfillcolor(RGB(0,0,0));// 设置填充颜色为黑色
                        solidpie(left,top,right,bottom,5*Pi/60+offset,6*Pi/60+offset); 
                    }
                    totalOffset = totalOffset + Pi/20; // 不同半径间角度偏移量为Pi/20
                }
            }
        }
        _getch();  // 暂停,等待按键输入
    }    
    return 0;
}

输出结果:
image.png


案例:用三角形平铺屏幕并且做红绿渐变

#include<graphics.h>
#include<conio.h>

//用函数封装直线和颜色,使其成为一个三角形函数
void triangle(int x, int y, int color)
{
    setlinecolor(color);

    line(x, y, x + 10, y);
    line(x, y, x, y + 10);
    line(x, y + 10, x + 10, y);
}

int main()
{
    int pixel = 255 * 2;

    initgraph(pixel, pixel);

    //遍历输出三角形,并且更改颜色,让颜色分布到整个画布的方法c * 255 / 屏幕某边的像素
    for (int i = 0; i <= pixel; i += 10)
    {
        for (int j = 0; j <= pixel; j += 10)
        {
            //调用三角形函数
            triangle(0 + i, 0 + j, RGB(i * 255 / pixel, j * 255 / pixel, 0));
        }
    }

    _getch();

    closegraph();

    return 0;
}

输出结果:
image.png


案例:绘制一个的渐变圆

#include<graphics.h>
#include<conio.h>
#include<math.h>//载入这个头文件才能做数学公式的运算
#define PI 3.14    //定义一个PI的宏常量

int main()
{
    initgraph(640, 480);

    float a;//这个是弧度
    int x, y, r = 100, C;

    for (a = 0; a < PI * 2; a += 0.0001)
    {
        /*
         x = r * cos(a)
         y = r * sin(a)
         c = a * 255/(2 * PI)
        */
        x = int(r * cos(a) + 320 + 0.5);
        y = int(r * sin(a) + 240 + 0.5);
        C = int(a * 255 / (2 * PI) + 0.5);

        setlinecolor(RGB(C, 0, 0));

        line(320, 240, x, y);
    }

    _getch();

    closegraph();

    return 0;
}

输出结果:
image.png


案例:时钟

#include <graphics.h>
#include <conio.h>
#include <math.h>

#define    PI    3.1415926536

void DrawHand(int hour, int minute, int second)
{
    double a_hour, a_min, a_sec;                    // 时、分、秒针的弧度值
    int x_hour, y_hour, x_min, y_min, x_sec, y_sec;    // 时、分、秒针的末端位置

    // 计算时、分、秒针的弧度值    ,与y轴负半轴的夹角
    a_sec = second * 2 * PI / 60;        
    a_min = minute * 2 * PI / 60 + a_sec / 60;
    a_hour = hour * 2 * PI / 12 + a_min / 12;

    // 计算时、分、秒针的末端位置
    x_sec = int(120 * sin(a_sec));    y_sec = int(120 * cos(a_sec));        //秒针长度为120
    x_min = int(100 * sin(a_min));    y_min = int(100 * cos(a_min));        //分针长度为100
    x_hour = int(70 * sin(a_hour));    y_hour = int(70 * cos(a_hour));        // 时针长度为70

    // 画时针
    setlinestyle(PS_SOLID, 10);        //填充实线  线宽为10
    setcolor(WHITE);
    line(320 + x_hour, 240 - y_hour, 320 - x_hour / 7, 240 + y_hour / 7);        //中点(320,240)

    // 画分针
    setlinestyle(PS_SOLID, 6);        //填充实线  线宽为6
    setcolor(LIGHTGRAY);
    line(320 + x_min, 240 - y_min, 320 - x_min / 5, 240 + y_min / 5);

    // 画秒针
    setlinestyle(PS_SOLID, 2);        //填充实线  线宽为2
    setcolor(RED);
    line(320 + x_sec, 240 - y_sec, 320 - x_sec / 3, 240 + y_sec / 3);
}

void DrawDial()
{
    // 绘制一个简单的表盘
    circle(320, 240, 2);
    circle(320, 240, 60);
    circle(320, 240, 160);
    outtextxy(296, 310, _T("BestAns"));

    // 绘制刻度
    int x, y;
    for (int i = 0; i < 60; i++)
    {
        x = 320 + int(145 * sin(PI * 2 * i / 60));
        y = 240 + int(145 * cos(PI * 2 * i / 60));

        if (i % 15 == 0)
            rectangle(x - 5, y - 5, x + 5, y + 5);// 无边框填充矩形
        else if (i % 5 == 0)
            circle(x, y, 3);
        else
            putpixel(x, y, WHITE);//画点        
    }
}

void main()
{
    initgraph(640, 480);        // 初始化 640 x 480 的绘图窗口

    DrawDial();                    // 绘制表盘

    setrop2(R2_XORPEN);            // 设置 XOR 绘图模式    ,异或模式  
                                //屏幕颜色 XOR 当前颜色  如果两者相同则为 0,即黑色 若不同则为 1,采用当前颜色 

    // 绘制表针
    SYSTEMTIME ti;                // 定义变量保存当前时间

    while (!_kbhit())                // 按任意键退出钟表程序
    {

        GetLocalTime(&ti);        // 获取当前时间
        DrawHand(ti.wHour, ti.wMinute, ti.wSecond);    // 画表针

        Sleep(1000);            // 延时 1 秒

        DrawHand(ti.wHour, ti.wMinute, ti.wSecond);    // 擦表针(擦表针和画表针的过程是一样的)

    }
    EndBatchDraw();
    closegraph();                // 关闭绘图窗口
}

输出结果:
test-2021-10-23-09-26-13.gif


案例:绘制下雪效果

#include<graphics.h>
#include<conio.h>
#include<ctime>

int main()
{
    srand((unsigned)time(NULL));

    initgraph(600, 600);

    //定义点坐标的数组
    int x[100];  //x轴
    int y[100];  //y轴
    int i;

    //随机点的坐标
    for (i = 0; i < 100; i++)
    {
        x[i] = rand() % 600;
        y[i] = rand() % 600;
    }

    while (!_kbhit())
    {

        for (i = 0; i < 100; i++)
        {
            //擦掉前一个点
            putpixel(x[i], y[i], BLACK);

            //计算新坐标
            y[i] += 3;

            //达到条件绘制新的点
            if (y[i] >= 600) 
            {
                y[i] = 0;
            }
            putpixel(x[i], y[i], WHITE);
        }
        Sleep(10);
    }

    closegraph();
    return 0;
}

输出结果:

Project1-2021-10-25-13-08-15.gif


键鼠操作

getmessage(EM_MOUSE | EM_KEY);

#include <graphics.h>

int main()
{
    // 初始化图形窗口
    initgraph(640, 480);

    ExMessage m;        // 定义消息变量

    while(true)
    {
        // 获取一条鼠标或按键消息
        m = getmessage(EM_MOUSE | EM_KEY);

        switch(m.message)
        {
            case WM_MOUSEMOVE:
                // 鼠标移动的时候画红色的小点
                putpixel(m.x, m.y, RED);
                break;a

            case WM_LBUTTONDOWN:
                // 如果点左键的同时按下了 Ctrl 键
                if (m.ctrl)
                    // 画一个大方块
                    rectangle(m.x - 10, m.y - 10, m.x + 10, m.y + 10);
                else
                    // 画一个小方块
                    rectangle(m.x - 5, m.y - 5, m.x + 5, m.y + 5);
                break;

            case WM_KEYDOWN:
                if (m.vkcode == VK_ESCAPE)
                    return 0;    // 按 ESC 键退出程序
        }
    }

    // 关闭图形窗口
    closegraph();
    return 0;
}

输出结果:
Project1-2021-10-25-13-23-28.gif

peekmessage(&m,EM_MOUSE );

#include <graphics.h>

int main()
{
    initgraph(640, 480);

    int x[10] = { 0 }, y[10] = { 0 };
    ExMessage m;    //定义消息变量

    while (true)
    {
        //获取鼠标消息
        //注意,这里用了while而不是if,因为可能鼠标消息的产生速率会超过Sleep(20),如果用if,会造成鼠标消息堆积产生延时效果
        while (peekmessage(&m, EM_MOUSE))
        {
            if (m.message == WM_MOUSEMOVE)
            {
                putpixel(m.x, m.y, BLUE);
            }
        }

        //计算跟随点的坐标(同时擦掉最末尾一个点)
        setlinecolor(BLACK);
        circle(x[9], y[9], 5);
        for (int i = 9; i > 0; i--)
        {
            x[i] = x[i - 1];
            y[i] = y[i - 1];
        }

        //计算头节点坐标,向着鼠标当前位置移动
        x[0] += (m.x - x[0]) / 4;
        y[0] += (m.y - y[0]) / 4;
        setlinecolor(RED);
        circle(x[0], y[0], 5);

        Sleep(20);
    }

    closegraph();
    return 0;
}

查看-2021-10-25-19-25-48.gif


载入图像文件

载入外部图片

#undef UNICODE
#include<graphics.h>
#include<conio.h>

int main()
{
    initgraph(600, 600);

    IMAGE img;

    loadimage(&img, "在此输入文件路径,记得带上文件名和格式,如果是工程下的文件,只需要文件名和格式就行");

    putimage(0,0,&img);

    _getch();
    closegraph();
    return 0;
}

把绘制的内容截屏为图片使用

#undef UNICODE
#include<graphics.h>
#include<conio.h>

int main()
{
    initgraph(600, 600);

    IMAGE img;

    circle(100, 100, 20);
    line(70, 100, 130, 100);
    line(100, 70, 100, 130);

    getimage(&img, 70, 70, 100, 120);

    putimage(200,2000,&img);

    _getch();
    closegraph();
    return 0;
}

案例:三辆小车前进动画

//自己的写法,代码还不够灵活
#include<graphics.h>
#include<conio.h>
#include<ctime>

//画小车
void drawBus()
{
    setcolor(RED);
    rectangle(50, 50, 255, 155);
    fillcircle(205 / 5 + 41, 155, 15);
    fillcircle(205 / 5 + 45 * 4, 155, 15);
    for (int i = 0; i < 7; i++)
        rectangle(80 + i * 10 + 3, 80, 80 + 10 + i * 10, 80 + 7);
    rectangle(190, 100, 200, 155);
    rectangle(180, 100, 190, 155);
    circle(190, 120, 5);
}

//初始化
void init(IMAGE* p)
{
    initgraph(800, 600);
    drawBus();        //调用画车函数

    //(p是IMAGE对象,x和y是获取图像的起始点,后面两个是图像的长宽像素)
    getimage(p, 50, 50, 210, 120);//获取画车截屏
}

//读取截图,并做动画
void drive(int x, int y, IMAGE* p)
{
    putimage(x, y, p);
}

int main()
{
    //创建图片对象
    IMAGE img;

    //调用初始化函数
    init(&img);

    //这个函数是能让绘制的所有对象集中一起同时画,避免出现频闪的效果,而不是编译器编译到哪就画什么
    BeginBatchDraw();

    int a = -210;
    int b = -210;
    int c = -210;

    while (1)
    {
        //绘制道路
        for (int i = 1; i <= 3; i++)
        {
            setlinestyle(PS_SOLID | PS_ENDCAP_SQUARE, 20);
            line(0, 700 / 4 * i, 800, 700 / 4 * i);
        }

        //小车动画
        a += 5;
        drive(a, 700 / 4 * 1 - 130, &img);
        if (a >= 810)
        {
            a = -210;
        }
        b += 8;
        drive(b, 700 / 4 * 2 - 130, &img);
        if (b >= 810)
        {
            b = -210;
        }
        c += 2;
        drive(c, 700 / 4 * 3 - 130, &img);
        if (c >= 810)
        {
            c = -210;
        }

        //把上面绘制的图集中到这一步全部同时刷出来
        FlushBatchDraw();
        Sleep(20);
        cleardevice();
    }

    //结束刷屏操作
    EndBatchDraw();

    _getch();
    closegraph();
    return 0;
}
#undef UNICODE
#include <graphics.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>

// 声明需要使用的函数
void carstart(int x, int y, int z);
void drawbus();
void init();

// 定义全局变量
IMAGE img;


////////////////////////////////////////////
void main()
{
    init();
    int x = 0, y = 0, z = 0;
    BeginBatchDraw();

    while (!_kbhit())
    {
        x += 2;
        y++;
        z += 3;
        if (x > 600)    x = -200;
        if (y > 600)    y = -200;
        if (z > 600)    z = -200;

        carstart(x, y, z);
        FlushBatchDraw();
        Sleep(5);
    }

    EndBatchDraw();
    closegraph();
}


////////////////////////////////////////////
// 初始化函数,初始化窗口大小,获取所画图片
void init()
{
    // 初始化窗口大小
    initgraph(600, 600);

    outtextxy(70, 250, "大家好,新手来报到,希望大家多多指教");
    outtextxy(70, 270, "下面你们会看到我程序的效果,程序很简单");
    outtextxy(70, 290, "希望以后再跟大家的交流中学到更多,希望自己以后能编出更好的程序");
    outtextxy(70, 320, "请按任意键进观看程序执行效果");

    // 等待按键按下
    _getch();

    cleardevice();                        // 清除上面的文字进入运行效果画面
    drawbus();                            // 调用绘图函数,绘制 BUS
    getimage(&img, 80, 40, 180, 90);    // 获取 BUS 图片位置,保存在 img 变量中
}


//////////////////////////////////////////////////////////////
// 车辆行驶程序,通过 putimge 函数,改变移动的像素来达到图片移动
void carstart(int x, int y, int z)
{
    cleardevice();
    putimage(x, 40, &img);
    setlinestyle(PS_SOLID, 10);   //设置画线的大小
    line(0, 135, 600, 135);
    putimage(y, 220, &img);
    line(0, 315, 600, 315);
    putimage(z, 380, &img);
    line(0, 475, 600, 475);
}


//////////////////////////////////////////////////////////////
// 绘制 BUS 函数,通过画一些线条,组合它们的位置,组合成一辆小车
void drawbus()
{
    setcolor(RED);
    setfillstyle(BLUE);

    fillcircle(120, 120, 10);         // 画车的轮胎
    fillcircle(200, 120, 10);         // 画车的轮胎
    line(80, 120, 110, 120);        // 画车的底部车板
    line(80, 40, 80, 120);         // 画车的四周车板
    line(130, 120, 190, 120);        // 画车的底部车板
    line(210, 120, 250, 120);        // 画车的底部车板
    line(250, 40, 250, 120);         // 画车的四周车板
    line(80, 40, 250, 40);        // 画车的顶部车板

    // 画车窗
    for (int x = 90, y = 100; x < 190 && y < 190; x += 15, y += 15)
    {
        rectangle(x, 60, y, 70);
    }

    // 画车门
    rectangle(220, 60, 240, 120);
    line(230, 60, 230, 120);
    circle(230, 90, 5);
}

案例:灭灯游戏

#undef UNICODE     //VC6 默认使用的 MBCS 编码,而 VC2008 及高版本 VC 默认使用的 Unicode 编码 
//#undef _UNICODE    //取消 Unicode 编码的宏定义,让整个项目以 MBCS 编码编译,这2句话必须放在最上面

#include    <graphics.h>
#include    <conio.h>
#define        MaxNum                14        //单边最大格子数
#define        G_length            30        //格子边长
#define        USER_LBUTTONDOWN    101
#define        USER_RBUTTONDOWN    102
#define        USER_MBUTTONDOWN    103

#pragma warning(disable:4996)     //可以使用老版库中被废弃的函数


 ///////////////////////////////////////////////
void PaintGrid(int Mid_x, int Mid_y, int num, int color);    // 绘制游戏格子,初始化格子
//void OnLButtonDown(MOUSEMSG m, int num);            // 左键按下
void OnLButtonDown(ExMessage m, int num);            // 左键按下

void OnRButtonDown(int num);                // 右键按下
void OnMButtonDown();                    // 中键按下*暂无定义*
void welcome();                        // 显示游戏主界面
void goodbye(int num);                    // 显示结束画面
void NextLevel(int num);                    // 下一关
//int     GetMessage(MOUSEMSG m);                    // 获取鼠标信息
int     GetMessage(ExMessage m);                    // 获取鼠标信息

//int  DispatchMessage(MOUSEMSG m, int opt);                    // 分发鼠标信息
int  DispatchMessage(ExMessage m, int opt);                    // 分发鼠标信息
int  JudgeFull(int num, int array[MaxNum][MaxNum]);            // 格子是否填满

///////////////////////////////////////////////
// 定义游戏格子结构体
struct Grid
{
    int left;    // 游戏区域边界
    int right;
    int top;
    int bottom;
    int array[MaxNum][MaxNum];    // 记录格子状态
    int num;    // 记录边界格子数目
}grid;


///////////////////////////////////////////////
int main()
{
    int opt, end = 0;
    grid.num = 4;
    welcome();
    PaintGrid(320, 240, grid.num, RGB(0, 255, 0));
    //    MOUSEMSG m;
    ExMessage m;
    while (end != 1)
    {
        //        m = GetMouseMsg();
        m = getmessage();
        opt = GetMessage(m);

        end = DispatchMessage(m, opt);
    }
    goodbye(grid.num);
    closegraph();

    return 0;
}


///////////////////////////////////////////////
// 获取鼠标信息
//int GetMessage(MOUSEMSG m)
int GetMessage(ExMessage m)
{
    //鼠标循环
//    switch (m.uMsg)
    switch (m.message)
    {
    case WM_LBUTTONDOWN:
        return USER_LBUTTONDOWN;
    case WM_RBUTTONDOWN:
        return USER_RBUTTONDOWN;
    case WM_MBUTTONDOWN:
        return USER_MBUTTONDOWN;
    }
    return 0;
}


///////////////////////////////////////////////
// 分发消息
//int DispatchMessage(MOUSEMSG m, int opt)
int DispatchMessage(ExMessage m, int opt)

{
    switch (opt)
    {
    case USER_LBUTTONDOWN:
        // 左键填色
        OnLButtonDown(m, grid.num);
        // 判断是否填满
        if (JudgeFull(grid.num, grid.array) == 1)
        {
            grid.num++;
            // 格子数目超过最大值通关
            if (grid.num > MaxNum)
            {
                return 1;
                break;
            }
            else
                NextLevel(grid.num);
        }
        break;

    case USER_RBUTTONDOWN:
        // 右键清除
        OnRButtonDown(grid.num);
        break;

    case USER_MBUTTONDOWN:
        return 1;
        break;
    }

    return 0;
}


///////////////////////////////////////////////
// 左键按下
//void OnLButtonDown(MOUSEMSG m, int num)
void OnLButtonDown(ExMessage m, int num)

{
    int nx, ny, x, y;
    if (m.x > grid.left && m.x<grid.right && m.y>grid.top && m.y < grid.bottom)
    {
        // 计算位置
        nx = (int)(m.x - grid.left) / G_length;
        ny = (int)(m.y - grid.top) / G_length;
        // 转换格子状态
        grid.array[nx][ny] = -grid.array[nx][ny];
        if (nx >= 0 && nx < num - 1) grid.array[nx + 1][ny] = -grid.array[nx + 1][ny];
        if (nx > 0 && nx <= num - 1) grid.array[nx - 1][ny] = -grid.array[nx - 1][ny];
        if (ny >= 0 && ny < num - 1) grid.array[nx][ny + 1] = -grid.array[nx][ny + 1];
        if (ny > 0 && ny <= num - 1) grid.array[nx][ny - 1] = -grid.array[nx][ny - 1];
        // 扫描填色
        for (nx = 0; nx < num; nx++)
            for (ny = 0; ny < num; ny++)
            {
                if (grid.array[nx][ny] == 1)
                    setfillcolor(GREEN);
                else
                    setfillcolor(BLACK);
                x = nx * G_length + grid.left;
                y = ny * G_length + grid.top;
                solidrectangle(x + 1, y + 1, x + G_length - 1, y + G_length - 1);
            }
    }
}


///////////////////////////////////////////////
// 右键按下清空
void OnRButtonDown(int num)
{
    int x, y, nx, ny;

    for (x = 0; x < num; x++)
        for (y = 0; y < num; y++)
            grid.array[x][y] = -1;

    for (nx = 0; nx < num; nx++)
        for (ny = 0; ny < num; ny++)
        {
            setfillcolor(BLACK);
            x = nx * G_length + grid.left;
            y = ny * G_length + grid.top;
            solidrectangle(x + 1, y + 1, x + G_length - 1, y + G_length - 1);
        }
}


///////////////////////////////////////////////
// 显示下一关
// 参数:
//    num:    下一关的边界格子数
void NextLevel(int num)
{
    // 清屏
    BeginBatchDraw();
    for (int y = 0; y <= 480; y += 5)
    {
        setlinecolor(RGB(0, 255, 0));
        settextcolor(RGB(0, 255, 0));
        line(0, y, 640, y);
        line(0, 480 - y, 640, 480 - y);
        outtextxy(300, y, "下一关");
        FlushBatchDraw();
        Sleep(16);
        setfillcolor(BLACK);
        solidrectangle(0, y + 4, 640, y - 5);
        solidrectangle(0, 480 - y, 640, 480 - y + 5);
    }
    EndBatchDraw();

    // 绘制下一关格子
    PaintGrid(320, 240, num, RGB(0, 255, 0));
}


///////////////////////////////////////////////
// 判断格子是否填满
// 参数:
//    num:    单边格子数目
//    array:    生成数组接收实参
int JudgeFull(int num, int array[MaxNum][MaxNum])
{
    int c = -1;
    int nx = 0, ny = 0;
    while (nx < num && ny < num)
    {
        for (nx = 0; nx < num; nx++)
            for (ny = 0; ny < num; ny++)
                if (array[nx][ny] == 1)
                    continue;
                else
                    return c;
    }
    c = 1;
    return c;
}


///////////////////////////////////////////////
// 绘制游戏格子,初始化格子
// 参数:
//    Mid_x:    屏幕中心 x 坐标
//    Mid_y:    屏幕中心 y 坐标
//    num:    单边格子数目
//    color:    格子线条颜色
void PaintGrid(int Mid_x, int Mid_y, int num, int color)
{
    int x, y, nx, ny;
    // 游戏区域大小
    grid.left = Mid_x - num * G_length / 2;
    grid.right = Mid_x + num * G_length / 2;
    grid.top = Mid_y - num * G_length / 2;
    grid.bottom = Mid_y + num * G_length / 2;
    // 绘制格子
    setlinecolor(color);
    for (x = grid.left; x <= grid.right; x += G_length)
    {
        line(x, grid.top, x, grid.bottom);
        Sleep(10);
    }
    for (y = grid.top; y <= grid.bottom; y += G_length)
    {
        line(grid.left, y, grid.right, y);
        Sleep(10);
    }
    // 外边框
    for (x = 20; x > 10; x--)
    {
        line(grid.left - x, grid.top - x, grid.right + x, grid.top - x);
        line(grid.left - x, grid.bottom + x, grid.right + x, grid.bottom + x);
        line(grid.left - x, grid.top - x, grid.left - x, grid.bottom + x);
        line(grid.right + x, grid.top - x, grid.right + x, grid.bottom + x);
        Sleep(5);
    }
    // 清空单元格
    for (x = 0; x < num; x++)
        for (y = 0; y < num; y++)
            grid.array[x][y] = -1;
    for (nx = 0; nx < num; nx++)
        for (ny = 0; ny < num; ny++)
        {
            setfillcolor(BLACK);
            x = nx * G_length + grid.left;
            y = ny * G_length + grid.top;
            solidrectangle(x + 1, y + 1, x + G_length - 1, y + G_length - 1);
        }
}


///////////////////////////////////////////////
// 显示游戏主界面
void welcome()
{
    // 初始化窗口
    initgraph(640, 480);

    // 输出屏幕提示
    cleardevice();
    settextcolor(RGB(0, 255, 0));
    settextstyle(64, 0, "黑体");
    outtextxy(70, 50, "涂格子游戏(点灯)");
    settextcolor(WHITE);
    settextstyle(16, 0, "宋体");
    outtextxy(100, 200, "每点一个格子,上下左右的格子也会做出于现状相反的动作");
    outtextxy(100, 240, "总共11关,左键填色,右键重来,中键退出");
    outtextxy(100, 280, "只是一个功能演示版本,以后再改进");
    outtextxy(400, 320, "by:xxxxxxx");
    settextstyle(16, 0, "黑体");
    outtextxy(400, 340, "Ver 0.1");

    // 实现闪烁的"按任意键继续"
    int c = 255;
    while (!kbhit())
    {
        settextcolor(RGB(0, c, 0));
        outtextxy(280, 400, "按任意键继续");
        c -= 8;
        if (c < 0) c = 255;
        Sleep(20);
    }

    getch();
    cleardevice();
}


///////////////////////////////////////////////
// 显示结束画面
void goodbye(int num)
{
    int c = 255;

    // 清屏
    BeginBatchDraw();
    for (int y = 0; y <= 480; y += 5)
    {
        setlinecolor(RGB(0, 255, 0));
        line(0, y, 640, y);
        line(0, 480 - y, 640, 480 - y);
        FlushBatchDraw();
        Sleep(16);
        setfillcolor(BLACK);
        solidrectangle(0, y + 4, 640, y - 5);
        solidrectangle(0, 480 - y, 640, 480 - y + 5);
    }
    EndBatchDraw();

    //判断显示文字
    if (num == MaxNum + 1)
    {
        settextcolor(RGB(0, c, 0));
        settextstyle(48, 0, "黑体");
        outtextxy(280, 200, "通关");
        settextstyle(20, 0, "黑体");
    }
    else
    {
        settextcolor(RGB(0, c, 0));
        settextstyle(48, 0, "黑体");
        outtextxy(200, 200, "再接再厉");
        settextstyle(20, 0, "黑体");
    }

    while (!kbhit())
    {
        settextcolor(RGB(0, c, 0));
        outtextxy(400, 400, "QQ: xxxxxx");
        c -= 8;
        if (c < 0) c = 255;
        Sleep(20);
    }

    getch();
}

窗口句柄和弹窗

窗口句柄

#include <graphics.h>
#include <conio.h>

int main()
{
    initgraph(640, 480);

    // 获取窗口句柄
    HWND hwnd = GetHWnd();
    // 设置窗口标题文字
    SetWindowText(hwnd, L"Hello World!");

    _getch();
    closegraph();
    return 0;
}

输出结果:
image.png

弹窗效果

#undef UNICODE
#include<graphics.h>
#include<conio.h>

void NewGame()
{
    HWND wnd = GetHWnd();
    MessageBox(wnd, "您的系统版本太低,请升级系统", "警告", MB_OK | MB_ICONWARNING);
}

void Quit()
{
    HWND wnd = GetHWnd();
    MessageBox(wnd, "退出游戏", "提示", MB_OK | MB_ICONWARNING);
}

int main()
{
    HWND wnd = GetHWnd();
    if (MessageBox(wnd, "游戏结束。\n重来一局吗?", "询问", MB_YESNO | MB_ICONQUESTION) == IDYES)
        NewGame();
    else
        Quit();
}

输出结果:
image.pngimage.pngimage.png


十字消除

#pragma warning(disable : 4996)

#include <graphics.h>  
#include <conio.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

# define BlockSize 40 // 小方块的长宽大小
# define ColorTypeNum 9 // 除了空白方块外,其他方块的颜色的个数

struct Block // 小方块结构体
{
    int x, y; // x y坐标
    int colorId; // 对应颜色的下标
    int i, j;  // 小方块在二维数组中的i j下标
};

// 全局变量
int RowNum; // 游戏画面一共RowNum行小方块
int ColNum; // 游戏画面一共ColNum列小方块
Block** blocks = NULL; // 动态二维数组指针,存储所有方块数据
COLORREF  colors[ColorTypeNum + 1]; // 颜色数组,小方块可能的几种颜色
int score; // 得分数,也就是消去的方块的个数
float maxTime; // 这一关游戏的总时长
float totalTime; // 减去扣分项后的游戏总时长
float remainTime; // 剩余时间
clock_t start, finish; // 用于计时的变量
int level = 1; // 当前关卡序号
int noZeroBlockNum; // 非空白区域的砖块的个数

void drawBlockHint(int i, int j, COLORREF color, int isfill) // 绘制出一个提示线框出来
{
    setlinecolor(color);
    setfillcolor(color);
    if (isfill == 1) // 鼠标点击中的方块,画填充方块提示
        fillrectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);
    if (isfill == 0) // 上下左右四个方向找到的4个方块,画线框提示
        rectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);
}


void writeRecordFile(int recordScore)  //保存最高分数据文件
{
    FILE* fp;
    fp = fopen(".\\gameRecord.dat", "w");
    fprintf(fp, "%d", recordScore);
    fclose(fp);
}

int readRecordFile()  //读取最高分数据文件
{
    int recordScore;
    FILE* fp;
    fp = fopen(".\\gameRecord.dat", "r");

    // 如果打不开的话,就新建一个文件,其得分记录为0分
    if (fp == NULL)
    {
        writeRecordFile(0);
        return 0;
    }
    else // 能打开这个文件,就读取下最高分记录
    {
        fscanf(fp, "%d", &recordScore);
        fclose(fp);
        return recordScore;
    }
}

void startup() // 初始化函数
{
    int i, j;
    start = clock(); // 记录当前运行时刻

    if (level > 1) // 如果不是第1关,则先清除二维数组内存,再重新开辟内存空间
    {
        for (i = 0; i < RowNum; i++)
            free(blocks[i]);
        free(blocks);
    }

    // 根据是第几关,调整这一关对应的游戏画面的大小
    RowNum = 12 + level / 2;  // 行数添加的慢一些,是一个长方形的形状
    ColNum = 20 + level;

    // 开辟动态二维数组
    blocks = (Block**)malloc(RowNum * sizeof(Block*));
    for (i = 0; i < RowNum; i++)
        blocks[i] = (Block*)malloc(ColNum * sizeof(Block));

    maxTime = 200 + level * 10; // 这一关游戏设定的总时长,每关时长+10秒
    totalTime = maxTime; // 游戏总时长,每次出错,会扣10秒钟

    int width = BlockSize * ColNum;      // 设定游戏画面的大小
    int height = BlockSize * (RowNum + 3); // 最下面用来显示一些提示信息
    initgraph(width, height);
    setbkcolor(RGB(220, 220, 220));
    setlinestyle(PS_SOLID, 2);
    cleardevice();
    srand(time(0));
    BeginBatchDraw(); // 开始批量绘制

    score = 0; // 得分数,也就是消去的方块的个数
    noZeroBlockNum = 0; // 非空白区域的砖块的个数

    colors[0] = RGB(220, 220, 220); // 颜色数组第一种颜色为灰白色,表示空白小方块
    for (i = 1; i < ColorTypeNum + 1; i++) // 其他几种颜色为彩色
        colors[i] = HSVtoRGB((i - 1) * 40, 0.6, 0.8);

    // 对blocks二维数组进行初始化
    for (i = 0; i < RowNum; i++)
    {
        for (j = 0; j < ColNum; j++)
        {
            // 取随机数,1-6设为彩色色块,其他为空白色块,这样为空白色块的几率高一些
            // 初始化时,空白色块多一些,符合游戏的设定
            int t = rand() % (int(ColorTypeNum * 1.5));  // 取随机数
            if (t < ColorTypeNum + 1)
                blocks[i][j].colorId = t; // 小方块的颜色序号
            else // 其他情况,都为空白颜色方块
                blocks[i][j].colorId = 0; // 小方块的颜色序号
            blocks[i][j].x = j * BlockSize; // 小方块左上角坐标
            blocks[i][j].y = i * BlockSize; // 
            blocks[i][j].i = i;   // 存储当前小方块在二维数组中的下标
            blocks[i][j].j = j;
            if (blocks[i][j].colorId != 0)
                noZeroBlockNum++; // 统计随机产生的方块中,非零方块的个数
        }
    }
}

void show() // 绘制函数
{
    cleardevice(); // 清屏
    setlinecolor(RGB(255, 255, 255)); // 白色线条
    int i, j;
    for (i = 0; i < RowNum; i++)
    {
        for (j = 0; j < ColNum; j++)
        {
            // 以对应的颜色、坐标画出所有的小方块
            setfillcolor(colors[blocks[i][j].colorId]);
            fillrectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);
        }
    }

    // 根据剩余时间,绘制一个倒计时进度条,进度条按最大时间maxTime秒绘制
    setlinecolor(RGB(255, 0, 0));
    setfillcolor(RGB(255, 0, 0));
    fillrectangle(0, BlockSize * (RowNum + 0.2), remainTime * BlockSize * ColNum / maxTime, BlockSize * (RowNum + 0.8));

    // 输出得分文字
    TCHAR s[80];
    setbkmode(TRANSPARENT);
    _stprintf(s, _T("%d"), score);
    settextcolor(RGB(0, 0, 0));
    settextstyle(22, 0, _T("宋体"));
    outtextxy(BlockSize * (ColNum / 2 - 0.1), BlockSize * (RowNum + 0.2), s);
    // 输出一些游戏提示信息
    _stprintf(s, _T("点击空白方块,其十字区域有两个或以上相同颜色方块则消除;不能消除扣时间"));
    outtextxy(BlockSize * (ColNum / 15.0), BlockSize * (RowNum + 1.2), s);
    _stprintf(s, _T("目前第 %d 关,时间结束前得分达到 %d 可进入下一关"), level, int(noZeroBlockNum * 0.9));
    outtextxy(BlockSize * (ColNum / 5.0), BlockSize * (RowNum + 2.2), s);

    FlushBatchDraw(); // 批量绘制
}

void updateWithoutInput() // 和输入无关的更新
{
    // 倒计时减少
    finish = clock(); // 当前时刻
    // 从startup运行后,这一关游戏运行了多少秒
    double duration = (double)(finish - start) / CLOCKS_PER_SEC;
    remainTime = totalTime - duration; // 游戏剩余的时间

    // 如果时间到了
    if (remainTime <= 0)
    {
        // 读一下文件记录,如果当前得分超过记录
        if (score > readRecordFile())
        {
            // 更新下得分记录
            writeRecordFile(score);

            // 显示恭喜超过记录
            show();
            settextcolor(RGB(255, 0, 0));
            settextstyle(100, 0, _T("黑体"));
            outtextxy(BlockSize * (ColNum / 30.0), BlockSize * (RowNum / 3.0), _T("恭喜打破得分记录"));
            FlushBatchDraw(); // 批量绘制
            Sleep(2000);
        }

        if (score >= int(noZeroBlockNum * 0.9))
        {
            level++; // 如果得分达到要求,消除掉非空白方块数目的90%,关卡加1
        }
        startup(); // 调用初始化函数,重新开始游戏
        return;
    }
}

void updateWithInput() // 和输入有关的更新
{
    if (remainTime <= 0) // 时间到了,不要操作
        return;

    int i, j;
    ExMessage m;
    if (MouseHit())
    {
        m = getmessage();
        if (m.message == WM_LBUTTONDOWN) // 当按下鼠标左键时
        {
            // 获得点击的小方块的下标
            int clicked_i = int(m.y) / BlockSize;
            int clicked_j = int(m.x) / BlockSize;
            // 点击到下面提示部分了,不用处理,函数返回
            if (clicked_i >= RowNum)
                return;
            // 如果当前点击的不是空白方块,不需要处理,返回
            if (blocks[clicked_i][clicked_j].colorId != 0)
                return;

            show(); // 先显示其他方块,再绘制提示框,后绘制的在最前面
            // 被点击到的空白方块,绘制下填充灰色方块提示框
            drawBlockHint(clicked_i, clicked_j, RGB(100, 100, 100), 1);

            // 定义数组,存储上、下、左、右四个方向找到第一个不是空白的方块
            Block fourBlocks[4] = { blocks[clicked_i][clicked_j] }; // 初始化为这个空白的点击的方块
            int search; // 寻找下标

            // 向上找
            for (search = 0; clicked_i - search >= 0; search++)
            {
                if (blocks[clicked_i - search][clicked_j].colorId != 0) // 找到第一个颜色不是空白的方块
                {
                    fourBlocks[0] = blocks[clicked_i - search][clicked_j]; // 赋给这个存储的数组
                    break;
                }
            }
            // 向下找
            for (search = 0; clicked_i + search < RowNum; search++)
            {
                if (blocks[clicked_i + search][clicked_j].colorId != 0) // 找到第一个颜色不是空白的方块
                {
                    fourBlocks[1] = blocks[clicked_i + search][clicked_j]; // 赋给这个存储的数组
                    break;
                }
            }
            // 向左找
            for (search = 0; clicked_j - search >= 0; search++)
            {
                if (blocks[clicked_i][clicked_j - search].colorId != 0) // 找到第一个颜色不是空白的方块
                {
                    fourBlocks[2] = blocks[clicked_i][clicked_j - search]; // 赋给这个存储的数组
                    break;
                }
            }
            // 向右找
            for (search = 0; clicked_j + search < ColNum; search++)
            {
                if (blocks[clicked_i][clicked_j + search].colorId != 0) // 找到第一个颜色不是空白的方块
                {
                    fourBlocks[3] = blocks[clicked_i][clicked_j + search]; // 赋给这个存储的数组
                    break;
                }
            }

            // 统计fourBlocks的四个小方块,有没有同样颜色数目大于等于2的
            int colorStatistics[ColorTypeNum + 1] = { 0 }; // 初始化个数为0
            int isBadClick = 1; // 假设点击的方块不合适,十字区域没有有效消除的方块
            for (i = 1; i < ColorTypeNum + 1; i++) // i=0是空白颜色,不要统计
            {
                for (j = 0; j < 4; j++) // 遍历fourBlocks
                {
                    if (fourBlocks[j].colorId == i)
                        colorStatistics[i]++; // 方块颜色为非零的i的话,把对应的统计个数+1
                }
                if (colorStatistics[i] >= 2) // 如果这种颜色方块个数大于等于2
                {
                    isBadClick = 0; // 能消除了,这次点击是好的操作
                    // 把对应十字区域要消除的方块颜色改成空白颜色
                    for (j = 0; j < 4; j++) // 遍历fourBlocks
                    {
                        if (fourBlocks[j].colorId == i)
                        {
                            // 要消除的方块区域绘制提示框                            
                            drawBlockHint(fourBlocks[j].i, fourBlocks[j].j, RGB(0, 0, 0), 0);
                            // 颜色序号设为0,也就是空白的灰白色
                            blocks[fourBlocks[j].i][fourBlocks[j].j].colorId = 0;
                        }
                    }
                    score += colorStatistics[i]; // 得分加上消除的方块数
                }
            }

            // 点击的方块,十字区域没有能消除的方块,为错误点击,减去10秒钟时间
            if (isBadClick == 1)
                totalTime -= 10;

            FlushBatchDraw(); // 批量绘制
            Sleep(300); // 绘制好提示框后暂停300毫秒

        } // while 当按下鼠标左键时
    }
}

int main() // 主函数运行
{
    startup();
    while (1)
    {
        show();
        updateWithoutInput();
        updateWithInput();

    }
    closegraph();
    return 0;
}