1.创建图形化窗口

图形化处理不支持C语言输入输出函数

可以通过打印函数在控制台调试错误

1.1头文件:

graphics.h(包含已经被淘汰的函数)

easyx.h(只包含最新的函数)

1.2创建窗口:

initgraph(int x,int y,int style);打开,x,y表示窗口大小,style表示打开方式(不写style则只打开图形化处理窗口)

closegraph();关闭窗口,前一句要加while(1)防止闪屏

1.3窗口坐标:

两点确认一条线,横x,纵y

1.4设置窗口属性:

1.4.1颜色设置:setbkcolor,分为两种,分别是颜色宏和RGB配置,颜色宏是英语大写的单词,右键可以查看库里的颜色函数,RGB配置就是三原色R G B的参数(类似调色板)

颜色宏:setbkcolor(RED);

RGB配置:setbkcolor(RGB(0,0,0)),则是黑色

1.5窗口刷新:

不设置窗口刷新是不会显示的

cleardevice()

2.绘图函数(int不用写)

2.1画线line(int x,int y,int xx,int yy);两个坐标,确定一条线

2.2画圆circle(int x,int y,int r);坐标,半径

2.3矩形rectangle(int x,int y,int xx,int yy);两个坐标,确定一个矩形

2.4填充圆和填充矩形颜色:setfillcolor();改变线的颜色:setlinecolor();

2.4.1圆带线填充:fillcircle(int x,int y,int r);

不带线填充:solidcircle(int x,int y,int r);

2.4.2矩形带线填充:fillrectangle(int x,int y,int xx,int yy);

矩形不带线填充:solidrectangle(int x,int y,int xx,int yy);

2.5窗口绘图可以使用for等函数进行绘图,比如画棋盘

1
2
3
4
5
6
7
8
9
10
11
void qipan()
{
initgraph(400, 400);
for (int i = 0; i <= 400; i += 20)
{
line(0, i, 400, i);
line(i, 0, i, 400);
}
while (1);
closegraph();
}

2.6显示贴图双缓冲,解决一闪一闪的刷新率问题:

在创建窗口initgraph函数下加BeginBatchDraw();在结尾closegraph函数上加EndBatchDraw();在循环里最后加上显示每一帧FlushBatchDraw();

3.贴图

3.1原式贴图

3.1.1IMAGE变量表示图片

加载图像:loadimage(IMAGE* img,URL);

缩放加载:loadimage(IMAGE* img,URL,int width,int height);width表示宽,height表示高

3.1.2显示图像:putimage(int x,int y,IMAGE* img);

例如加载一张名为tcs.jpg的图片

1
2
3
IMAGE img;
loadimage(&img,"./Res/tcs.jpg");
putimage(0,0,&img);

3.2 透明贴图

3.2.1通过图像的颜色二进制运算达到去背景图的效果

3.2.2素材:掩码图,背景图

3.2.3按照特定步骤贴图:

SRCAND 掩码图

SRCPAINT 背景图

1
2
3
4
5
IMAGE test[2];
loadimage(test+0,"./Res/test.jpg");
loadimage(test+1,"./Res/testbk.jpg");
putimage(100,100,test+0,SRCAND);
putimage(100,100,test+1,SRCPAINT);

4.按键交互

4.1阻塞按键交互:C++写的函数几乎都是阻塞,例如写一个小球移动和反弹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
struct Ball
{
int x;
int y;
int r;
int dx;
int dy;
};
struct Ball ball = { 400,400,15,6,-5 };

void DrawBall()
{
setfillcolor(RED);
solidcircle(ball.x, ball.y, ball.r);
}


void MoveBall()
{
if (ball.x - ball.r <= 0 || ball.x + ball.r >= 800)
{
ball.dx = -ball.dx;
}
if (ball.y - ball.r <= 0 || ball.y + ball.r >= 800)
{
ball.dy = -ball.dy;
}
ball.x += ball.dx;
ball.y += ball.dy;
}
int main()
{
initgraph(800, 800);
int a = 1;
while (1)
{
cleardevice();
DrawBall();
MoveBall();
Sleep(20);
}
closegraph();
return 0;
}

用结构体封装小球的数据,声明小球的绘图和移动方式,Sleep()是标准库里的移动速度函数

4.2用户输入按键对图像进行操控

4.2.1头文件

#include <conio.h>(getch()不需要回车确认输入)

4.2.2创建操控框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void keydown()
{
int userkey = _getch();
switch (userkey)
{
case 'w':
case'W':
case 72:
myball.y -= 5;
break;
case's':
case'S':
case 80:
myball.y += 5;
break;
case'a':
case'A':
case 75:
myball.x -= 5;
break;
case'd':
case'D':
case 77:
myball.x += 5;
break;
}
}

调用这个框架后如果发现其他图像在你不操控时也不动,那就是因为阻塞的原因,需要加上判断存在按键操作再处理

1
2
3
4
if(_kbhit())
{
keydown();
}

Sleep也是阻塞函数,想流畅运行要用定时器函数

4.3定时器函数

4.3.1定时器要用到时间函数,要加上#include<time.h>头文件

4.3.2定时器输入时间间隔和定时器id,用静态变量记录每一次的结果

1
2
3
4
5
6
7
8
9
10
11
int Time(int sjjg,int id)
{
static int startTime[10];
int endTime=clock();//clock统计程序运行到当前代码时间
if(endTime-startTime[id]>sjjg)//时间间隔大于定时器时间间隔触发定时器
{
startTime[id]=endTime;//开始时间改为上一次结束时间
return 1;
}
return 0;
}

调用到图像移动函数处,例如

1
2
if(Time(20,0))
MoveBall();

4.4异步交互:

4.4.1非阻塞函数,比上面所写的更流畅,但要控制好定时器速度比如Time(20,1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void keydown2()
{
if(GetAsyncKeyState(VK_UP))
{
myball.y-=5;
}
if(GetAsyncKeyState(VK_DOWN))
{
myball.y+=5;
}
if(GetAsyncKeyState(VK_LEFT))
{
myball.x-=5;
}
if(GetAsyncKeyState(VK_RIGHT))
{
myball.x+=5;
}
}

5.鼠标交互

5.1写一个ExMessage类型变量去存储鼠标消息

5.2获取鼠标消息peekmessage(&变量)

5.3讨论鼠标消息

msg.message(区分鼠标消息类型)

msg.x msg.y(鼠标当前坐标)

5.4框架示例(鼠标左键画圆,右键画方)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ExMessage msg;
while(1)
{
while(peekmessage(&msg))
{
switch(msg.message)
{
case WM_LBUTTONDOWN:
circle(msg.x,msg.y,10);
break;
case WM_RBUTTONDOWN:
rectangle(msg.x-10,msg.y-10,msg.x+10,msg.y+10);
break;
}
}
}

实战项目后面会发一个贪吃蛇和AI寻路贪吃蛇