07.绘制卡通头像

#include <easyx.h>
#include <stdio.h>

#define PI 3.14

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

    //  设置背景色为白色
    setbkcolor(WHITE);
    //  使用当前背景色清空窗体
    cleardevice();

    //  设置描边颜色为黑色,描边线形为实线,粗细为10
    setlinecolor(BLACK);
    setlinestyle(PS_SOLID, 10);

    //  绘制头部
    //  设置填充颜色为蓝色
    setfillcolor(BLUE);
    fillellipse(118, 125, 990, 931);
    Sleep(1000);

    //  绘制脸
    //  设置填充颜色为白色
    setfillcolor(WHITE);
    fillellipse(189, 271, 919, 931);
    Sleep(1000);

    //  绘制一对眼睛
    fillellipse(375, 170, 555, 420);
    fillellipse(555, 170, 735, 420);
    Sleep(1000);

    //  绘制一对瞳孔
    setfillcolor(BLACK);
    solidcircle(484, 333, 25);
    solidcircle(617, 333, 25);
    Sleep(1000);

    //  绘制一对高光
    setfillcolor(WHITE);
    solidcircle(484, 333, 10);
    solidcircle(617, 333, 10);
    Sleep(1000);


    //  绘制鼻子及竖线
    setfillcolor(RED);
    fillcircle(554, 420, 35);
    line(554, 460, 554, 828);
    Sleep(1000);

    //  嘴巴
    arc(320, 510, 789, 827, PI, 2 * PI);
    Sleep(1000);

    //  胡须
    line(125, 313, 296, 410);
    line(83, 444, 270, 474);
    line(83, 595, 262, 527);
    line(819, 414, 990, 320);
    line(845, 478, 1029, 448);
    line(853, 542, 1029, 660);

    getchar();
    closegraph();
    return 0;
}

 09.绘制显示器

#include <easyx.h>
#include <stdio.h>

int main()
{
    initgraph(800, 600);
    setbkcolor(WHITE);
    cleardevice();

    //  1.银色圆角矩形
    setfillcolor(RGB(232, 235, 240));
    solidroundrect(100, 50, 700, 450, 20, 20);

    //  2.蓝黑色矩形
    setfillcolor(RGB(71, 78, 94));
    solidrectangle(100, 390, 700, 410);

    //  3.蓝黑色圆角矩形
    solidroundrect(100, 50, 700, 410, 20, 20);

    //  4.天蓝色矩形屏幕
    setfillcolor(RGB(115, 199, 235));
    solidrectangle(120, 70, 680, 390);

    //  5.银色圆形摄像头
    setfillcolor(RGB(232, 235, 240));
    solidcircle(400, 60, 5);

    //  6.蓝黑色圆形开机键
    setfillcolor(RGB(71, 78, 94));
    solidcircle(400, 430, 12);

    //  7.深灰色椭圆底座
    setfillcolor(RGB(218, 219, 224));
    solidellipse(275, 515, 525, 545);

    //  8.银色梯形支架
    setfillcolor(RGB(232, 235, 240));
    POINT bigTrapezoid[4] = { {345, 450}, {455, 450}, {475, 530}, {325, 530} };
    solidpolygon(bigTrapezoid, 4);

    //  9.深灰色梯形阴影
    setfillcolor(RGB(218, 219, 224));
    POINT smallTrapezoid[4] = { {345, 450}, {455, 450}, {460, 470}, {340, 470} };
    solidpolygon(smallTrapezoid, 4);

    getchar();
    closegraph();
    return 0;
}

 11.绘制卡通熊

#include <stdio.h>
#include <easyx.h>

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

    //  背景
    setbkcolor(RGB(169, 92, 10));
    cleardevice();

    //  耳朵阴影
    setfillcolor(RGB(130, 69, 4));
    solidcircle(200, 130, 90);
    solidcircle(600, 130, 90);
    //  留出月牙状阴影
    setfillcolor(RGB(255, 178, 50));
    solidcircle(200, 120, 90);
    solidcircle(600, 120, 90);

    //  耳朵剪切区域
    HRGN leftEarClip = CreateEllipticRgn(110, 30, 290, 210);
    HRGN rightEarClip = CreateEllipticRgn(510, 30, 690, 210);
    HRGN earsClip = CreateRectRgn(0, 0, 0, 0);
    CombineRgn(earsClip, leftEarClip, rightEarClip, RGN_OR);
    setcliprgn(earsClip);

    //  留出耳朵高光
    setfillcolor(RGB(243, 154, 2));
    solidcircle(200, 130, 90);
    solidcircle(600, 130, 90);

    //  耳朵里面
    setfillcolor(RGB(255, 178, 50));
    solidcircle(200, 210, 90);
    solidcircle(600, 210, 90);

    //  释放区域
    DeleteObject(leftEarClip);
    DeleteObject(rightEarClip);
    DeleteObject(earsClip);
    //  禁用剪切区域
    setcliprgn(NULL);

    //  头
    setfillcolor(RGB(255, 178, 50));
    solidcircle(400, 300, 250);

    //  头剪切区域
    HRGN headClip = CreateEllipticRgn(150, 50, 650, 550);
    setcliprgn(headClip);

    //  留出头高光
    setfillcolor(RGB(243, 154, 2));
    solidcircle(400, 320, 250);

    //  释放区域
    DeleteObject(headClip);
    //  禁用剪切区域
    setcliprgn(NULL);

    //  眼睛
    setfillcolor(RGB(51, 34, 8));
    solidcircle(275, 300, 25);
    solidcircle(525, 300, 25);

    //  白色椭圆阴影
    setfillcolor(RGB(130, 69, 4));
    solidellipse(310, 385, 490, 485);

    //  白色椭圆
    setfillcolor(WHITE);
    solidellipse(310, 380, 490, 480);

    //  鼻子
    setfillcolor(RGB(51, 34, 8));
    solidcircle(400, 420, 15);

    //  胡须
    setlinestyle(PS_SOLID, 5);
    setlinecolor(RGB(51, 34, 8));
    line(400, 420, 370, 450);
    line(400, 420, 430, 450);


    getchar();
    closegraph();
    return 0;
}

14.直线运动

#include <easyx.h>
#include <math.h>
#include <stdio.h>

void LinearMotion(int x1, int y1, int x2, int y2, int v)
{
    //  速度分量
    double vy;
    double vx;

    //  根据运动类型,计算速度分量大小
    if (y2 == y1)
    {
        //  水平运动
        vx = v;
        vy = 0;
    }
    else if (x2 == x1)
    {
        //  垂直运动
        vx = 0;
        vy = v;
    }
    else
    {
        //  其他运动
        //  计算角度θ的正切tanTheta
        double tanTheta = (double)abs(y2 - y1) / (double)abs(x2 - x1);
        //  已知tanTheta,根据反三角函数计算角度θ
        double theta = atan(tanTheta);

        //  计算速度分量
        vy = sin(theta) * v;
        vx = cos(theta) * v;
    }

    //  根据速度方向的正负,求得速度分量的符号
    int vxFlag = 0;
    int vyFlag = 0;

    if (x2 - x1 > 0)
        vxFlag = 1;
    else if (x2 - x1 < 0)
        vxFlag = -1;

    if (y2 - y1 > 0)
        vyFlag = 1;
    else if (y2 - y1 < 0)
        vyFlag = -1;
    if (vxFlag == 0 && vyFlag == 0)
        return;

    vx = vx * vxFlag;
    vy = vy * vyFlag;

    //  从起始点(x1, y1)开始
    double x, y;
    x = x1;
    y = y1;
    //  循环绘制每一帧
    while (1)
    {
        cleardevice();
        solidcircle(x, y, 25);
        FlushBatchDraw();
        Sleep(40);
        x += vx;
        y += vy;

        if (vxFlag == 1)
        {
            //  符号为正,直到大于等于终止点x2坐标为止
            if (x >= x2)
                break;
        }
        else if (vxFlag == -1)
        {
            //  符号为负,直到小于等于终止点x2坐标为止
            if (x <= x2)
                break;
        }
        if (vyFlag == 1)
        {
            //  符号为正,直到大于等于终止点y2坐标为止
            if (y >= y2)
                break;
        }
        else if (vyFlag == -1)
        {
            //  符号为负,直到小于等于终止点y2坐标为止
            if (y <= y2)
                break;
        }
    }
}

int main()
{
    initgraph(800, 600);
    //  坐标系原点在窗体中心,X轴正方向向右,Y轴正方向向上
    setorigin(400, 300);
    setaspectratio(1, -1);
    //  设置背景色
    setbkcolor(RGB(164, 225, 202));
    //  使用背景色清空窗体
    cleardevice();
    //  设置填充颜色为白色WHITE
    setfillcolor(WHITE);

    //  三角形(P1, P2, P3)
    //  P1(0, 200)->P2(200, -200)->P3(-200, -200)->P1(0, 200)
    LinearMotion(0, 200, 200, -200, 5);
    LinearMotion(200, -200, -200, -200, 5);
    LinearMotion(-200, -200, 0, 200, 5);

    //  三角形(P4, P5, P6)
    //  P4(0, -200)->P5(-200, 200)->P6(200, 200)->P4(0, -200)
    LinearMotion(0, -200, -200, 200, 5);
    LinearMotion(-200, 200, 200, 200, 5);
    LinearMotion(200, 200, 0, -200, 5);

    //  矩形(P5, P6, P2, P3)
    //  P5(-200, 200)->P6(200, 200)->P2(200, -200)->P3(-200, -200)->P5(-200, 200)

    LinearMotion(-200, 200, 200, 200, 5);
    LinearMotion(200, 200, 200, -200, 5);
    LinearMotion(200, -200, -200, -200, 5);
    LinearMotion(-200, -200, -200, 200, 5);

    getchar();
    closegraph();
    return 0;
}

 15.弹球小游戏

#include <easyx.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>

typedef struct {
    //  圆心坐标
    int x, y;
    //  速度分量
    int vx, vy;
    //  小球半径
    int r;
    //  挡板左边、顶边、右边、底边坐标
    int barLeft, barTop, barRight, barBottom;
}GameData;

void reset(GameData* gdata)
{
    gdata->x = rand() % (400 + 1) - 200;
    gdata->y = rand() % (300 + 1) - 150;
    gdata->vx = 5;
    gdata->vy = 5;
    if (rand() % 2 == 0)
    {
        gdata->vy = -gdata->vy;
    }
    if (rand() % 2 == 0)
    {
        gdata->vx = -gdata->vx;
    }
    gdata->r = 40;
    gdata->barLeft = -150;
    gdata->barRight = 150;
    gdata->barTop = -280;
    gdata->barBottom = -300;
}

int main()
{
    initgraph(800, 600);
    //  坐标系原点在窗体中心,X轴正方向向右,Y轴正方向向上
    setorigin(400, 300);
    setaspectratio(1, -1);
    //  设置背景色
    setbkcolor(RGB(164, 225, 202));
    //  使用背景色清空窗体
    cleardevice();

    //  当前时间作为随机数种子
    srand((unsigned int)time(NULL));

    //  游戏数据
    GameData gdata;
    //  初始化游戏数据
    reset(&gdata);

    while (1)
    {
        cleardevice();
        //  绘制小球
        solidcircle(gdata.x, gdata.y, gdata.r);
        //  绘制挡板
        solidrectangle(gdata.barLeft, gdata.barTop, gdata.barRight, gdata.barBottom);

        //  每帧之间休眠40ms
        Sleep(40);

        //  撞击或越过顶边反弹
        if (gdata.y >= 300 - gdata.r)
        {
            gdata.vy = -gdata.vy;
        }
        //  撞击或越过左、右边反弹
        if (gdata.x <= -400 + gdata.r || gdata.x >= 400 - gdata.r)
        {
            gdata.vx = -gdata.vx;
        }

        //  撞击或越过挡板后反弹
        if (gdata.barLeft <= gdata.x && gdata.x <= gdata.barRight && gdata.y <= gdata.barTop + gdata.r)
        {
            gdata.vy = -gdata.vy;
        }

        //  小球位置变化
        gdata.x += gdata.vx;
        gdata.y += gdata.vy;

        //  控制挡板移动
        if (_kbhit() != 0)
        {
            char c = _getch();
            if (c == 'a')
            {
                if (gdata.barLeft > -400)
                {
                    gdata.barLeft -= 20;
                    gdata.barRight -= 20;
                }
            }
            else if (c == 'd')
            {
                if (gdata.barRight < 400)
                {
                    gdata.barLeft += 20;
                    gdata.barRight += 20;
                }
            }
        }

        if (gdata.y <= -300)
        {
            //  重置游戏初始数据
            reset(&gdata);
        }
    }

    closegraph();
    return 0;
}

16.贪吃蛇

#include <easyx.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>

#define NODE_WIDTH 40

//  节点
typedef struct {
    int x;
    int y;
}node;

//  绘制网格
//  横线(0, y), (800, y)   0 <= y <= 600
//  竖线(x, 0),(x, 600)    0 <= x <= 800
void paintGrid()
{
    //  横线
    for (int y = 0; y < 600; y += NODE_WIDTH)
    {
        line(0, y, 800, y);
    }
    //  竖线
    for (int x = 0; x < 800; x += NODE_WIDTH)
    {
        line(x, 0, x, 600);
    }
}

void paintSnake(node* snake, int n)
{
    int left, top, right, bottom;
    for (int i = 0; i < n; i++)
    {
        //  左上角:【网格x坐标 * 网格宽度, 网格y坐标 * 网格宽度】
        left = snake[i].x * NODE_WIDTH;
        top = snake[i].y * NODE_WIDTH;
        //  右下角:【(网格x坐标 + 1) * 网格宽度, (网格y坐标 + 1) * 网格宽度】
        right = (snake[i].x + 1) * NODE_WIDTH;
        bottom = (snake[i].y + 1) * NODE_WIDTH;
        //  通过左上角与右下角坐标绘制矩形
        solidrectangle(left, top, right, bottom);
    }
}

//  方向枚举
enum direction
{
    eUp,
    eDown,
    eLeft,
    eRight
};


//  蛇身体移动
node snakeMove(node* snake, int length, int direction)
{
    //for (int i = 0; i < length; i++)
    //    printf("(%d, %d)\n", snake[i].x, snake[i].y);

    //  记录尾节点
    node tail = snake[length - 1];

    //  从尾结点开始,前一个节点覆盖后一个节点
    //  0 1 2 3 4      0 1 2 3 4
    //  E D C B A ---> E E D C B
    for (int i = length - 1; i > 0; i--)
    {
        snake[i] = snake[i - 1];
    }

    //  下一个头节点
    node newHead;
    newHead = snake[0];
    if (direction == eUp)
    {
        newHead.y--;
    }
    else if (direction == eDown)
    {
        newHead.y++;
    }
    else if (direction == eLeft)
    {
        newHead.x--;
    }
    else //  right
    {
        newHead.x++;
    }

    //  更新头节点
    //  E D C B A ---> F E D C B
    snake[0] = newHead;

    //for (int i = 0; i < length; i++)
    //    printf("(%d, %d)\n", snake[i].x, snake[i].y);

    //  返回尾节点
    return tail;
}

//  键盘输入改变direction
void changeDirection(enum direction* pD)
{
    //  检查输入缓存区中是否有数据
    if (_kbhit() != 0)
    {
        //  _getch函数获取输入缓存区中的数据
        char c = _getch();
        //  判断输入并转向
        switch (c)
        {
        case 'w':
            //  向上移动
            if (*pD != eDown)
                *pD = eUp;
            break;
        case 's':
            //  向下移动
            if (*pD != eUp)
                *pD = eDown;
            break;
        case 'a':
            //  向左移动
            if (*pD != eRight)
                *pD = eLeft;
            break;
        case 'd':
            //  向右移动
            if (*pD != eLeft)
                *pD = eRight;
            break;
        }
    }
}

//  绘制食物
/*

(x * NODE_WIDTH, y * NODE_WIDTH)
@-----------
|          |
|          |
|          |
|          |
|          |
-----------@ ((x + 1) * NODE_WIDTH, (y + 1) * NODE_WIDTH)

*/
void paintFood(node food)
{
    int left, top, right, bottom;
    left = food.x * NODE_WIDTH;
    top = food.y * NODE_WIDTH;
    right = (food.x + 1) * NODE_WIDTH;
    bottom = (food.y + 1) * NODE_WIDTH;
    setfillcolor(YELLOW);
    solidrectangle(left, top, right, bottom);
    setfillcolor(WHITE);
}


//  随机创建食物
node createFood(node* snake, int length)
{
    node food;
    while (1)
    {
        food.x = rand() % (800 / NODE_WIDTH);
        food.y = rand() % (600 / NODE_WIDTH);

        int i;
        for (i = 0; i < length; i++)
        {
            if (snake[i].x == food.x && snake[i].y == food.y)
            {
                break;
            }
        }
        if (i < length)
            continue;
        else
            break;
    }
    return food;
}

bool isGameOver(node* snake, int length)
{
    //  是否撞墙
    if (snake[0].x < 0 || snake[0].x > 800 / NODE_WIDTH)
        return true;

    if (snake[0].y < 0 || snake[0].y > 600 / NODE_WIDTH)
        return true;

    //  是否吃到蛇身
    for (int i = 1; i < length; i++)
    {
        if (snake[0].x == snake[i].x && snake[0].y == snake[i].y)
            return true;
    }
    return false;
}

void reset(node* snake, int* pLength, enum direction* d)
{
    snake[0] = node{ 5, 7 };
    snake[1] = node{ 4, 7 };
    snake[2] = node{ 3, 7 };
    snake[3] = node{ 2, 7 };
    snake[4] = node{ 1, 7 };
    *pLength = 5;
    *d = eRight;
}

int main()
{
    initgraph(800, 600);
    //  设置背景色
    setbkcolor(RGB(164, 225, 202));
    //  使用背景色清空窗体
    cleardevice();

    //  蛇节点坐标
    node snake[100] = { {5, 7}, {4, 7}, {3, 7}, {2, 7}, {1, 7} };
    //  蛇节点长度
    int length = 5;
    enum direction d = eRight;

    //  食物
    srand(unsigned int(time(NULL)));
    node food = createFood(snake, length);

    while (1)
    {
        //  清空整个窗体
        cleardevice();
        //  绘制网格
        paintGrid();
        //  绘制蛇节点
        paintSnake(snake, length);
        //  绘制食物
        paintFood(food);
        //  休眠500ms
        Sleep(500);
        //  获取键盘输入并将方向存储到变量d
        changeDirection(&d);

        node lastTail = snakeMove(snake, length, d);
        //  新的蛇头节点是否与食物节点重合
        if (snake[0].x == food.x && snake[0].y == food.y)
        {
            //  限制snake节点最大长度
            if (length < 100)
            {
                //  已经吃到食物, 长度+1
                snake[length] = lastTail;
                length++;
            }
            //  重新生成新的食物
            food = createFood(snake, length);
        }

        //  游戏是否结束
        if (isGameOver(snake, length) == true)
        {
            //  游戏结束,复位设置,重新生成食物
            reset(snake, &length, &d);
            food = createFood(snake, length);
        }
    }

    getchar();
    closegraph();
    return 0;
}

17.多物体运动

#include <easyx.h>
#include <stdio.h>
#include <math.h>

#define NUM_OF_BALLS 1000
#define PI 3.14

typedef struct {
    int x;
    int y;
    int vx;
    int vy;
    COLORREF color;
}ball;

int main()
{
    initgraph(800, 600);
    //  坐标系原点在窗体中心,X轴正方向向右,Y轴正方向向上
    setorigin(400, 300);
    setaspectratio(1, -1);
    //  设置背景色
    setbkcolor(WHITE);
    //  设置描边颜色
    setlinecolor(BLACK);
    //  使用背景色清空窗体
    cleardevice();

    int r = 10;

    ball* balls = (ball*)malloc(sizeof(ball) * NUM_OF_BALLS);
    if (balls == NULL)
    {
        return -1;
    }

    for (int i = 0; i < NUM_OF_BALLS; i++)
    {
        int m, n;

        //  圆心x坐标区间:[-400 + r, 400 - r]
        m = -400 + r;
        n = 400 - r;
        balls[i].x = rand() % (n - m + 1) + m;

        //  圆心y坐标区间:  [-300 + r, 300 - r]
        m = -300 + r;
        n = 300 - r;
        balls[i].y = rand() % (n - m + 1) + m;

        //  随机颜色,色相随机,饱和度为80%,明度为90%
        balls[i].color = HSVtoRGB((float)(rand() % 360), 0.8f, 0.9f);

        //  随机速度大小[3, 8],速度方向与x方向夹角[0, 359]
        m = 3;
        n = 8;
        int v = rand() % (n - m + 1) + m;
        double theta;
        theta = rand() % 360;
        balls[i].vx = v * cos(theta * PI / 180);
        balls[i].vy = v * sin(theta * PI / 180);
    }

    while (1)
    {
        //  清空画面
        cleardevice();

        //  绘制多个小球
        for (int i = 0; i < NUM_OF_BALLS; i++)
        {
            setfillcolor(balls[i].color);
            fillcircle(balls[i].x, balls[i].y, r);
        }

        Sleep(40);

        //  遍历所有小球,若碰到或越过边界,则反弹
        for (int i = 0; i < NUM_OF_BALLS; i++)
        {
            //  碰到或越过上下边界反弹
            if (balls[i].y >= 300 - r || balls[i].y <= -300 + r)
            {
                balls[i].vy = -balls[i].vy;
            }
            //  碰到或越过左右边界反弹
            if (balls[i].x <= -400 + r || balls[i].x >= 400 - r)
            {
                balls[i].vx = -balls[i].vx;
            }
            //  小球移动位置
            balls[i].x += balls[i].vx;
            balls[i].y += balls[i].vy;
        }
    }

    closegraph();
    return 0;
}

18.批量绘图

#include <easyx.h>
#include <stdio.h>
#include <math.h>

#define NUM_OF_BALLS 1000
#define PI 3.14

typedef struct {
    int x;
    int y;
    int vx;
    int vy;
    COLORREF color;
}ball;

int main()
{
    initgraph(800, 600);
    //  坐标系原点在窗体中心,X轴正方向向右,Y轴正方向向上
    setorigin(400, 300);
    setaspectratio(1, -1);
    //  设置背景色
    setbkcolor(WHITE);
    //  设置描边颜色
    setlinecolor(BLACK);
    //  使用背景色清空窗体
    cleardevice();

    int r = 10;

    ball* balls = (ball*)malloc(sizeof(ball) * NUM_OF_BALLS);
    if (balls == NULL)
    {
        return -1;
    }

    for (int i = 0; i < NUM_OF_BALLS; i++)
    {
        int m, n;

        //  圆心x坐标区间:[-400 + r, 400 - r]
        m = -400 + r;
        n = 400 - r;
        balls[i].x = rand() % (n - m + 1) + m;

        //  圆心y坐标区间:  [-300 + r, 300 - r]
        m = -300 + r;
        n = 300 - r;
        balls[i].y = rand() % (n - m + 1) + m;

        //  随机颜色,色相随机,饱和度为80%,明度为90%
        balls[i].color = HSVtoRGB((float)(rand() % 360), 0.8f, 0.9f);

        //  随机速度大小[3, 8],速度方向与x方向夹角[0, 359]
        m = 3;
        n = 8;
        int v = rand() % (n - m + 1) + m;
        double theta;
        theta = rand() % 360;
        balls[i].vx = v * cos(theta * PI / 180);
        balls[i].vy = v * sin(theta * PI / 180);
    }

    //  开始批量绘图
    BeginBatchDraw();

    while (1)
    {
        //  清空画面
        cleardevice();

        //  绘制多个小球
        for (int i = 0; i < NUM_OF_BALLS; i++)
        {
            setfillcolor(balls[i].color);
            fillcircle(balls[i].x, balls[i].y, r);
        }

        //  显示累积的1000个小球,为一帧画面
        FlushBatchDraw();
        Sleep(40);

        //  遍历所有小球,若碰到或越过边界,则反弹
        for (int i = 0; i < NUM_OF_BALLS; i++)
        {
            //  碰到或越过上下边界反弹
            if (balls[i].y >= 300 - r || balls[i].y <= -300 + r)
            {
                balls[i].vy = -balls[i].vy;
            }
            //  碰到或越过左右边界反弹
            if (balls[i].x <= -400 + r || balls[i].x >= 400 - r)
            {
                balls[i].vx = -balls[i].vx;
            }
            //  小球移动位置
            balls[i].x += balls[i].vx;
            balls[i].y += balls[i].vy;
        }
    }

    //  结束批量绘图
    EndBatchDraw();

    closegraph();
    return 0;
}

19.图片

#include <easyx.h>
#include <stdio.h>

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

    IMAGE img;
    loadimage(&img, "background.jpg");
    putimage(0, 0, &img);

    IMAGE imgBear;
    loadimage(&imgBear, "bear.png");
    putimage(530, 180, &imgBear);

    getchar();
    closegraph();

}

20.透明图片

#include <easyx.h>
#include <stdio.h>

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

    //  背景图片
    IMAGE imgBackground;
    loadimage(&imgBackground, "./background.jpg");

    //  白背景的黑剪影
    IMAGE imgMask;
    loadimage(&imgMask, "./mask.jpg");

    //  黑背景的熊本体
    IMAGE imgBear;
    loadimage(&imgBear, "./bear.jpg");

    //  背景图片绘制到窗体上
    putimage(0, 0, &imgBackground);

    //  mask.jpg与窗体中图像进行与运算
    putimage(530, 180, &imgMask, SRCAND);

    //  bear.jpg与窗体中图像进行与运算
    putimage(530, 180, &imgBear, SRCPAINT);

    getchar();
    closegraph();
}

21.让熊跑起来

#define _CRT_SECURE_NO_WARNINGS

#include <easyx.h>
#include <stdio.h>
#include <math.h>

#define BEAR_FRAMES 11

void putTransparentImage(int x, int y, const IMAGE* mask, const IMAGE* img)
{
    putimage(x, y, mask, SRCAND);
    putimage(x, y, img, SRCPAINT);
}

int main()
{
    initgraph(1200, 480);
    //  设置背景色
    setbkcolor(WHITE);
    //  使用背景色清空窗体
    cleardevice();

    IMAGE imgBackground;
    loadimage(&imgBackground, "background.jpg");

    // load images
    IMAGE imgArrBearFrames[BEAR_FRAMES];
    for (int i = 0; i < BEAR_FRAMES; i++)
    {
        char strImgPath[100];
        sprintf(strImgPath, "bear/frames/bear%d.png", i);
        loadimage(&imgArrBearFrames[i], strImgPath);
    }

    // load masks
    IMAGE imgArrBearMasks[BEAR_FRAMES];
    for (int i = 0; i < BEAR_FRAMES; i++)
    {
        char strImgPath[100];
        sprintf(strImgPath, "bear/masks/bearmask%d.png", i);
        loadimage(&imgArrBearMasks[i], strImgPath);
    }

    int frame = 0;
    int x = -150;

    BeginBatchDraw();

    while (1)
    {
        putimage(0, 0, &imgBackground);
        putTransparentImage(x, 180, &imgArrBearMasks[frame], &imgArrBearFrames[frame]);
        FlushBatchDraw();

        frame++;
        x += 10;

        if (frame >= BEAR_FRAMES)
            frame = 0;
        if (x >= 1200 + 150)
            x = -150;

        Sleep(50);
    }
    EndBatchDraw();

    getchar();
    closegraph();
    return 0;
}

23.精确帧率控制

#include <easyx.h>
#include <stdio.h>

int main()
{
    //  提高系统定时器时钟分辨率为1毫秒
    timeBeginPeriod(1);

    initgraph(800, 600);
    setbkcolor(RGB(164, 225, 202));
    cleardevice();
    setfillcolor(WHITE);

    //  开始时间、结束时间、频率F
    LARGE_INTEGER startCount, endCount, F;

    //  获取频率F
    QueryPerformanceFrequency(&F);

    int x = 0, y = 300;
    int vx = 5;

    BeginBatchDraw();
    while (1)
    {
        //  获取起始计数
        QueryPerformanceCounter(&startCount);

        //  准备画面
        cleardevice();
        solidcircle(x, y, 50);

        x = x + vx;
        if (x <= 0 || x >= 800)
            vx = -vx;

        //  获取结束计数
        QueryPerformanceCounter(&endCount);

        //  计算时差
        long long elapse = (endCount.QuadPart - startCount.QuadPart)
            / F.QuadPart * 1000000;

        //  时差若小于40000,则一直循环,直到时差大于等于40000
        //  注意这里的单位是微秒
        while (elapse < 40000)
        {
            //  先休眠一小会,再检查是否超时
            Sleep(1);

            //  重新获取结束时间
            QueryPerformanceCounter(&endCount);
            //  更新时差
            elapse = (endCount.QuadPart - startCount.QuadPart)
                * 1000000 / F.QuadPart;
        }

        //  绘制画面
        FlushBatchDraw();
    }

    EndBatchDraw();
    closegraph();

    //  timeBeginPeriod与timeEndPeriod必须成对存在,并且传一样的值
    timeEndPeriod(1);
    return 0;
}

25.打气球

#include <easyx.h>
#include <stdio.h>
#include <math.h>

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define MAX_IN_WINDOW 5
#define BALLOON_RADIUS 30

typedef struct {
    int x;
    int y;
    int r;
    int v;
    COLORREF color;
}balloon;

balloon generateBalloon()
{
    balloon b;
    //  x坐标在区间[100, 700]之间
    int m, n;
    m = 100;
    n = 700;
    b.x = rand() % (n - m + 1) + m;
    //  y坐标在窗口底部
    b.y = WINDOW_HEIGHT;
    //  半径为符号常量BALLOON_RADIUS
    b.r = BALLOON_RADIUS;
    //  速度在区间[1, 3]之间
    m = 1;
    n = 3;
    b.v = rand() % (n - m + 1) + m;
    //  颜色RGB值随机
    b.color = RGB(rand() % 256, rand() % 256, rand() % 256);
    return b;
}

int main()
{
    //  创建一个宽度为WINDOW_WIDTH、高度为WINDOW_HEIGHT的窗体,并用白色背景色刷新窗体。
    initgraph(WINDOW_WIDTH, WINDOW_HEIGHT);
    setbkcolor(WHITE);
    cleardevice();

    //  气球数组
    balloon arrBalloons[MAX_IN_WINDOW];

    //  给气球数组赋值
    for (int i = 0; i < MAX_IN_WINDOW; i++)
        arrBalloons[i] = generateBalloon();

    //  当前出现的气球数
    int current = MAX_IN_WINDOW;

    //  鼠标位置
    int mouseX = 0, mouseY = 0;

    timeBeginPeriod(1);
    LARGE_INTEGER startCount, endCount, F;
    QueryPerformanceFrequency(&F);
    BeginBatchDraw();
    while (1)
    {
        QueryPerformanceCounter(&startCount);

        //  清空窗体
        cleardevice();
        //  绘制并移动气球
        for (int i = 0; i < MAX_IN_WINDOW; i++)
        {
            //  绘制气球
            setfillcolor(arrBalloons[i].color);
            solidcircle(arrBalloons[i].x, arrBalloons[i].y, arrBalloons[i].r);
        }

        //  移动气球
        for (int i = 0; i < MAX_IN_WINDOW; i++)
            arrBalloons[i].y -= arrBalloons[i].v;

        //  删除已飞出窗体外的气球
        int i = 0;
        while (i < current)
        {
            int y = arrBalloons[i].y;
            //  是否已飞出窗体外
            if (y < -BALLOON_RADIUS)
            {
                //  依次使用后续元素覆盖前驱元素,直到最后一个有效元素为止
                for (int j = i; j < current - 1; j++)
                    arrBalloons[j] = arrBalloons[j + 1];
                //  当前气球数减1
                current--;
            }
            else
            {
                //  数组元素未被删除,i才能自增1
                i++;
            }
        }

        //  增加新气球
        if (current < MAX_IN_WINDOW)
        {
            //  气球数组中追加一个气球
            arrBalloons[current] = generateBalloon();
            //  当前气球数加1
            current++;
        }

        //  绘制准心
        //  设置描边颜色为RGB(237, 178, 29)
        setlinecolor(RGB(237, 178, 29));
        //  线段样式为实线、线段宽度为3
        setlinestyle(PS_SOLID, 3);
        //  绘制半径为20的描边圆
        circle(mouseX, mouseY, 20);
        //  绘制十字
        line(mouseX - 20, mouseY, mouseX + 20, mouseY);
        line(mouseX, mouseY - 20, mouseX, mouseY + 20);

        QueryPerformanceCounter(&endCount);
        long long elapse = (endCount.QuadPart - startCount.QuadPart)
            * 1000000 / F.QuadPart;
        //  每秒帧率设置为60,因此最长等待时间为1000000 / 60
        while (elapse < 1000000 / 60)
        {
            Sleep(1);

            //  获取鼠标消息
            ExMessage msg;
            bool isOk = peekmessage(&msg, EX_MOUSE);
            //  是否有新消息,没有则无需处理消息
            if (isOk == true)
            {
                //  如果是鼠标移动消息,则更新鼠标位置
                if (msg.message == WM_MOUSEMOVE)
                {
                    mouseX = msg.x;
                    mouseY = msg.y;
                }
                //  如果是鼠标点击消息,则判断是否点击到气球,点击到将气球删除
                else if (msg.message == WM_LBUTTONDOWN)
                {
                    //  检查哪个气球被点击到
                    int i = 0;
                    while (i < current)
                    {
                        int ballX = arrBalloons[i].x;
                        int ballY = arrBalloons[i].y;
                        int distance = (int)sqrt(pow(ballY - msg.y, 2) + pow(ballX - msg.x, 2));
                        //  是否鼠标与气球的圆心距离小于半径
                        if (distance < BALLOON_RADIUS)
                        {
                            //  依次使用后续元素覆盖前驱元素,直到移动完最后一个有效元素为止
                            for (int j = i; j < current - 1; j++)
                                arrBalloons[j] = arrBalloons[j + 1];

                            //  当前气球数减1
                            current--;
                        }
                        else
                        {
                            //  数组元素未被删除,i才能自增1
                            i++;
                        }
                    }
                }
            }

            QueryPerformanceCounter(&endCount);
            elapse = (endCount.QuadPart - startCount.QuadPart)
                * 1000000 / F.QuadPart;
        }

        //  批量显示
        FlushBatchDraw();
    }
    EndBatchDraw();
    timeEndPeriod(1);
    closegraph();
    return 0;
}

26.音频

#include <windows.h>
#include <stdio.h>

int main()
{
    // 打开音乐
    mciSendString("open 起床歌.mp3", NULL, 0, NULL);
    printf("打开音乐");
    getchar();

    // 开始播放
    mciSendString("play 起床歌.mp3", NULL, 0, NULL);
    printf("开始播放");
    getchar();

    // 暂停播放
    mciSendString("pause 起床歌.mp3", NULL, 0, NULL);
    printf("暂停播放");
    getchar();

    // 继续播放
    mciSendString("resume 起床歌.mp3", NULL, 0, NULL);
    printf("继续播放");
    getchar();

    // 停止播放
    mciSendString("stop 起床歌.mp3", NULL, 0, NULL);
    printf("停止播放");
    getchar();

    // 关闭音乐
    mciSendString("close 起床歌.mp3", NULL, 0, NULL);
    printf("关闭音乐");
    getchar();
}

27

(1)封装

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct student {
    void (*setStudentId)(struct student* s, int year, int classNum, int serialNum);
    const char* (*getGender)(struct student* s);
    void (*setGender)(struct student* s, const char* strGender);

    int id;         //  学号
    char name[20];  //  姓名
    int gender;     //  性别
    int mark;       //  分数
};

void setStudentId(struct student* s, int year, int classNum, int serialNum)
{
    char buffer[20];
    sprintf(buffer, "%d%d%d", year, classNum, serialNum);
    int id = atoi(buffer);
    s->id = id;
}

const char* getGender(struct student* s)
{
    if (s->gender == 0)
    {
        return "女";
    }
    else if (s->gender == 1)
    {
        return "男";
    }
    return "未知";
}

void setGender(struct student* s, const char* strGender)
{
    int numGender;
    if (strcmp("男", strGender) == 0)
    {
        numGender = 1;
    }
    else if (strcmp("女", strGender) == 0)
    {
        numGender = 0;
    }
    else
    {
        numGender = -1;
    }
    s->gender = numGender;
}

void initStudent(struct student* s)
{
    s->setStudentId = setStudentId;
    s->getGender = getGender;
    s->setGender = setGender;
}

int main()
{
    struct student stu;
    //  初始化student
    initStudent(&stu);

    //  学号:202212326
    //  姓名:小明
    //  性别: 男
    //  分数:98
    stu.setStudentId(&stu, 2022, 123, 26);
    strcpy(stu.name, "小明");
    stu.setGender(&stu, "男");
    stu.mark = 98;

    //  打印这些数值
    printf("学号:%d\n", stu.id);
    printf("姓名:%s\n", stu.name);
    const char* gender = stu.getGender(&stu);
    printf("性别:%s\n", gender);
    printf("分数:%d\n", stu.mark);
    return 0;
}

(2)继承

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct person {
    int id;             //  编号
    char name[20];      //  姓名
    int gender;         //  性别

    //  设置性别
    void (*setGender)(struct person* s, const char* strGender);
    //  获取性别
    const char* (*getGender)(struct person* s);
};

struct teacher {
    struct person super;
    char subject[20];   //  任课科目
};

struct student {
    struct person super;
    int mark;       //  分数

    //  设置学号
    void (*setStudentId)(struct student* s, int year, int classNum, int serialNum);
};

const char* getGender(struct person* p)
{
    if (p->gender == 0)
    {
        return "女";
    }
    else if (p->gender == 1)
    {
        return "男";
    }
    return "未知";
}

void setGender(struct person* p, const char* strGender)
{
    int numGender;
    if (strcmp("男", strGender) == 0)
    {
        numGender = 1;
    }
    else if (strcmp("女", strGender) == 0)
    {
        numGender = 0;
    }
    else
    {
        numGender = -1;
    }
    p->gender = numGender;
}

void setStudentId(struct student* s, int year, int classNum, int serialNum)
{
    char buffer[20];
    sprintf(buffer, "%d%d%d", year, classNum, serialNum);
    int id = atoi(buffer);
    s->super.id = id;   //  由s->id = id 修改为 s->super.id = id
}

void initPerson(struct person* p)
{
    p->getGender = getGender;
    p->setGender = setGender;
}

void initStudent(struct student* s)
{
    initPerson(&(s->super));
    s->setStudentId = setStudentId;
}

void initTeacher(struct teacher* t)
{
    initPerson(&(t->super));
}

int main()
{
    struct student stu;

    //  初始化student
    initStudent(&stu);

    //  学号:202212326
    //  姓名:小明
    //  性别: 男
    //  分数:98
    stu.setStudentId(&stu, 2022, 123, 26);
    strcpy(stu.super.name, "小明");
    stu.super.setGender(&stu.super, "男");
    stu.mark = 98;

    //  打印这些数值
    printf("学号:%d\n", stu.super.id);
    printf("姓名:%s\n", stu.super.name);
    const char* gender = stu.super.getGender(&stu.super);
    printf("性别:%s\n", gender);
    printf("分数:%d\n", stu.mark);

    putchar('\n');

    struct teacher t;

    //  初始化teacher
    initTeacher(&t);

    //  工号:12345
    //  姓名:林老师
    //  性别: 男
    //  科目:C语言
    t.super.id = 12345;
    strcpy(t.super.name, "林老师");
    t.super.setGender(&t.super, "男");
    strcpy(t.subject, "C语言");

    //  打印这些数值
    printf("学号:%d\n", t.super.id);
    printf("姓名:%s\n", t.super.name);
    gender = t.super.getGender(&t.super);
    printf("性别:%s\n", gender);
    printf("科目:%s\n", t.subject);

    return 0;
}

28.多态

#include <easyx.h>
#include <stdio.h>

struct Shape {
    void (*draw)(struct Shape*);
};

struct Rect {
    struct Shape super;

    int left;
    int top;
    int right;
    int bottom;
};

struct Circle {
    struct Shape super;

    int x;
    int y;
    int r;
};

struct Triangle {
    struct Shape super;

    POINT p1;
    POINT p2;
    POINT p3;
};

void drawRect(struct Rect* r)
{
    rectangle(r->left, r->top, r->right, r->bottom);
}

void drawCircle(struct Circle* c)
{
    circle(c->x, c->y, c->r);
}

void drawTriangle(struct Triangle* t)
{
    line(t->p1.x, t->p1.y, t->p2.x, t->p2.y);
    line(t->p2.x, t->p2.y, t->p3.x, t->p3.y);
    line(t->p3.x, t->p3.y, t->p1.x, t->p1.y);
}

void initRect(struct Rect* r)
{
    r->super.draw = (void (*)(struct Shape*))drawRect;
}

void initCircle(struct Circle* c)
{
    c->super.draw = (void (*)(struct Shape*))drawCircle;
}

void initTriangle(struct Triangle* t)
{
    t->super.draw = (void (*)(struct Shape*))drawTriangle;
}

int main()
{
    initgraph(800, 600);
    setaspectratio(1, -1);
    setorigin(400, 300);

    setbkcolor(WHITE);
    setlinecolor(BLACK);
    cleardevice();

    struct Rect r = { {}, -200, 200, 200, 0 };
    struct Circle c = { {}, 0, 0, 100 };
    struct Triangle t = { {},  {0, 200}, {-200, 0}, {200, 0} };

    initRect(&r);
    initCircle(&c);
    initTriangle(&t);

    struct Shape* arrShape[3] = {
    (struct Shape*)&r, (struct Shape*)&c, (struct Shape*)&t };

    for (int i = 0; i < 3; i++)
    {
        arrShape[i]->draw(arrShape[i]);
    }

    getchar();
    closegraph();

    return 0;
}

30.动态数组

main.c

#define _CRT_SECURE_NO_WARNINGS

#include "vector.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct student {
    int id;         //  学号
    char name[20];  //  姓名
    int gender;     //  性别
    int mark;       //  成绩
};

int main()
{
    struct vector vec;
    vectorInit(&vec);

    //  append
    struct student* s1 = (struct student*)malloc(sizeof(struct student));
    s1->id = 1;
    strcpy(s1->name, "小明");
    s1->gender = 1;
    s1->mark = 90;
    vec.append(&vec, s1);

    for (int i = 0; i < vec.size; i++)
    {
        struct student* s = (struct student*)vec.get(&vec, i);
        printf("%d %s %d %d\n", s->id, s->name, s->gender, s->mark);
    }

    printf("size:%d\n", vec.size);
    printf("capacity:%d\n", vec.capacity);
    getchar();

    //  append追加
    struct student* s2 = (struct student*)malloc(sizeof(struct student));
    s2->id = 2;
    strcpy(s2->name, "小红");
    s2->gender = 0;
    s2->mark = 95;
    vec.append(&vec, s2);

    for (int i = 0; i < vec.size; i++)
    {
        struct student* s = (struct student*)vec.get(&vec, i);
        printf("%d %s %d %d\n", s->id, s->name, s->gender, s->mark);
    }

    printf("size:%d\n", vec.size);
    printf("capacity:%d\n", vec.capacity);
    getchar();

    //  remove
    //  别忘记销毁小明的数据
    free(vec.get(&vec, 0));
    vec.remove(&vec, 0);

    for (int i = 0; i < vec.size; i++)
    {
        struct student* s = vec.get(&vec, i);
        printf("%d %s %d %d\n", s->id, s->name, s->gender, s->mark);
    }
    printf("size:%d\n", vec.size);
    printf("capacity:%d\n", vec.capacity);

    for (int i = 0; i < vec.size; i++)
    {
        struct student* s = vec.get(&vec, i);
        free(s);
    }
    getchar();

    //  clear
    vec.clear(&vec);

    for (int i = 0; i < vec.size; i++)
    {
        struct student* s = vec.get(&vec, i);
        printf("%d %s %d %d\n", s->id, s->name, s->gender, s->mark);
    }
    printf("size:%d\n", vec.size);
    printf("capacity:%d\n", vec.capacity);
    getchar();

    //  销毁数组
    vectorDestroy(&vec);
    
    return 0;
}

vector.h

#pragma once

#include <stdbool.h>

#define VECTOR_INIT_CAPACITY 10

struct vector {
    bool (*append)(struct vector* pVec, void* data);
    void* (*get)(struct vector* pVec, int index);
    void (*clear)(struct vector* pVec);
    void (*remove)(struct vector* pVec, int index);

    void** pData;
    int size;
    int capacity;
};

void vectorInit(struct vector*);
void vectorDestroy(struct vector* pVec);

vector.c

#include "vector.h"
#include <stdlib.h>

bool vectorAppend(struct vector* pVec, void* data)
{
	if (pVec == NULL || data == NULL)
		return false;

	//  是否超长
	if (pVec->size >= pVec->capacity)
	{
		//  加长到两倍
		void** newData = (void**)realloc(pVec->pData, pVec->capacity * sizeof(void*) * 2);
		if (newData == NULL)
		{
			return false;
		}
		pVec->pData = newData;
		pVec->capacity = 2 * pVec->capacity;
	}

	pVec->pData[pVec->size] = data;
	pVec->size++;
	return true;
}

void* vectorGet(struct vector* pVec, int index)
{
	if (index >= pVec->size)
		return NULL;
	return pVec->pData[index];
}

void vectorRemove(struct vector* pVec, int index)
{
	for (int i = index; i < pVec->size - 1; i++)
		pVec->pData[i] = pVec->pData[i + 1];
	pVec->size -= 1;
}

void vectorClear(struct vector* pVec)
{
	if (pVec->pData != NULL)
		free(pVec->pData);

	pVec->pData = (void**)malloc(sizeof(void*) * VECTOR_INIT_CAPACITY);
	pVec->capacity = VECTOR_INIT_CAPACITY;
	pVec->size = 0;
}

void vectorInit(struct vector* pVec)
{
	pVec->get = vectorGet;
	pVec->append = vectorAppend;
	pVec->remove = vectorRemove;
	pVec->clear = vectorClear;

	//  初始情况下申请VECTOR_INIT_CAPACITY个element
	pVec->pData = (void**)malloc(sizeof(void*) * VECTOR_INIT_CAPACITY);
	pVec->capacity = VECTOR_INIT_CAPACITY;
	pVec->size = 0;
}

void vectorDestroy(struct vector* pVec)
{
	if (pVec->pData == NULL)
		return;
	free(pVec->pData);
	pVec->pData = NULL;
	pVec->size = 0;
	pVec->capacity = 0;
}

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐