EasyX入门笔记

写在前面的话

这是刚学C的蒟蒻第一次挑战控制台程序以外的程序设计因为要做课设。第一次自己敲出黑框框之外程序的本蒟蒻肥肠兴奋,就根据视频自学(视频链接),总结视频内容和自己查阅的资料,写出了下面的笔记,希望它可以帮到大家。由于作者水平有限,难免有遗漏和不足之处,望神犇们多多包涵指正。

什么是EasyX

EasyX是一个适合像我这样的蒟蒻编程初学者操作的图形渲染库。
本质上,EasyX是将Windows繁琐的图形绘制操作封装在头文件中,从而实现用函数简单的调用。

使用EasyX

百度EasyX官网,从官网中即可下载安装程序。它可以将EasyX直接安装在VS中。
使用EasyX需要在程序中添加头文件 include<graphics.h>

EasyX帮助文档:EasyX在线文档

EasyX中的坐标和设备

坐标

和数学的坐标系不同,EasyX中坐标的y轴正方向应该是向下的。

在这里插入图片描述

设备

简单来讲,设备就是绘图表面;
在EasyX中,设备分两种:
1.默认的绘图窗口;
2.Image对象。
通过 SetWorkingImage() 函数可以设置当前用于绘图的设备。
设置当前用于绘图的设备后,所有的绘图函数都会绘制在该设备上。
默认是在绘图窗口绘图.

颜色

EasyX有四种表示颜色的方法:预定义常量,十六进制数字,RGB宏,使用HSLtoRGBHSVtoRGB颜色转换其他色彩模型到RGB颜色。

1.使用预定义常量:

常量			值			颜色
--------		--------	--------
BLACK			0			黑
BLUE			0xAA0000	蓝
GREEN			0x00AA00	绿
CYAN			0xAAAA00	青
RED				0x0000AA	红
MAGENTA			0xAA00AA	紫
BROWN			0x0055AA	棕
LIGHTGRAY		0xAAAAAA	浅灰
DARKGRAY		0x555555	深灰
LIGHTBLUE		0xFF5555	亮蓝
LIGHTGREEN		0x55FF55	亮绿
LIGHTCYAN		0xFFFF55	亮青
LIGHTRED		0x5555FF	亮红
LIGHTMAGENTA	0xFF55FF	亮紫
YELLOW			0x55FFFF	黄
WHITE			0xFFFFFF

2.使用16进制数表示颜色
表示规则为:0xbbggrr
bb=蓝 gg=绿 rr=红

3.用RGB宏合成颜色
EasyX文档——RGB

4.用HSLtoRGBHSVtoRGB转换其他色彩模型到RGB颜色
EasyX文档——HSLtoRGB
EasyX文档——HSVtoRGB

EasyX的函数

窗口函数

窗口函数用于对窗口的一些操作。

initgraph(int width,int height,[int flag=NULL]) 用于初始化绘图窗口(创建绘图窗口);
三个参数分别为:宽度,高度和窗口样式(默认为NULL,可以不写)

窗口样式的设定有:
SHOWCONSOLE 显示控制台;
NOCLOSE 没有右上角的关闭按钮;
NOMINIMIZE 没有右上角的最小化按钮。
如果需要同时使用他们中的多个,可以用按位或|间隔。

closegraph() 关闭绘图窗口;

cleardevice() 清空绘图设备。
(设置背景中 cleardevice() 要和 setbkcolor() 联用,先后者再前者)

样式设置函数

格式为 操作类型+ 对象 + 操作名称不管对不对但我是这么理解的
该函数针对的是当前的绘图设备。

操作类型

get 获取
set 设置

对象

所有的图形
背景 bk
填充 fill
画线 line
多边形(填充) poly(fill)

操作名称

模式 mode(背景和多边形)
样式 style(画线和填充)
颜色 color

setlinecolor(0xff0000);
setlinecolor(BLUE);
setlinecolor(RGB(0, 0, 255));
setlinecolor(HSLtoRGB(240, 1, 0.5));

图形绘制函数

图形绘制函数用于在窗口上绘制各种图形.

填充样式分类

从填充样式分类,绘图函数可分为无填充,有边框填充,无边框三种.
以画圆为例:

circle 无填充
fillcircle 有边框填充
solidcircle 无边框填充

主要区别就是形状的前缀。

形状分类

从形状分类,常用的有八种(以下均为无填充)
circle(int x,int y,int radius) 画圆
x,y分别为圆心的x,y坐标;
radiu 为圆的半径。

ellipse(int x1,int y1,int x2,int y2) 画椭圆
四个坐标是椭圆的左上端点和右下端点的坐标。

pie(int x1,int y1,int x2,int y2,int stangle,int endangle) 画扇形
四个坐标是扇形左上端点和右下端点的坐标。
stangle扇形起始角的弧度endangle扇形终止角的弧度
PS:起始角和终止角的定义
经过圆心画一条水平线和垂直线,水平线以圆心向右为0度,顺着圆逆时针转动.即水平线向右经过0度,垂直向上为90度,水平线向左为180度,垂直线向下为270度。

polygon(POINT points[],int num) 画多边形
points[] 存储多边形的各个顶点位置。函数会自动连接这些点。注意,不是int类型!
num 是顶点的数量。

rectangle(int x1,int y1,int x2,int y2) 画矩形
四个坐标同样是矩形左上顶点和右下顶点的坐标。

roundrect(int x1,int y1,int x2,int y2,int ellipsewidth,int ellipseheight) 画圆角矩形
四个坐标值同样是左上顶点和右下顶点的坐标。
ellipsewidth 是构成圆角矩形的圆角的椭圆的宽度;
ellipseheight 是构成圆角矩形的圆角的椭圆的高度。

line(int x1,int y1,int x2,int y2) 画线
四个坐标是直线两个端点的坐标。

putpixel(int x,int y,COLORREF color) 画点
x和y是点的坐标, color 是点的颜色。

举个栗子

在这里插入图片描述

效果如图
在这里插入图片描述

……对不起我的长萌萌

如图可见,如果两个图案的位置有冲突,后绘制的图案会覆盖在先绘制的图案上。

文字绘制函数

文字绘制函数用于在窗口上绘制文字。

在指定位置输出字符串

outtextxy(int x,int y,LPCTSTR str)
x,y是待输出字符串头字母的x,y坐标值;str是待输出的字符串的指针。
由于字符集问题直接把字符串""进函数会报错,解决方法为:
1.在字符串前加上大写’L’;
2.用TEXT(str)/_T(str)形式;
3.进入“项目→属性→配置属性→常规”,将字符集改为“使用多字符字符集”。
最好用第三个。

设置当前文字颜色

settextcolor(COLORREF color)

settextstyle(int nHeight,int nWidth,LPCTSTR lpszFace)设置字体样式
nHeight 指定高度;
nWidth 字符的平均宽度;
lpszFace 字体名称。

设置背景模式

setbkmode
文字是有背景的!
setbkmode(TRANSPARENT) 把文字背景设置成透明;
setbkmode(OPAQUE) 设置成不透明。
(还有一个宏定义值一模一样的BKMODE_LAST也是不透明…)

设置文字居中显示

需要用到这两个函数:
textheight(LPCTSTR str) 获取字符串实际占用的像素高度;
textwidth(LPCTSTR str) 获取字符串实际占用的像素宽度。

居中的原理

先求出字符串的宽度和需要居中的窗口的左端坐标和宽度
再算出它们的一半
那么字符串输出函数应该填写的x轴坐标就是:

窗 口 左 端 坐 标 + 窗 口 长 度 的 一 半 − 字 符 串 长 度 的 一 半 窗口左端坐标+窗口长度的一半-字符串长度的一半 +

即左端窗口坐标+窗口和字符串之间的距离,但由于字符串的宽度是随着字符串内容的不同而变化的,所以不可以直接写常数。

宽度同理:

窗 口 上 端 坐 标 + 窗 口 宽 度 的 一 半 − 字 符 串 宽 度 的 一 半 窗口上端坐标+窗口宽度的一半-字符串宽度的一半 +

然后就可以套进去愉快的输出啦~

具体操作
fillrectangle(x1,y1,x2,y2);//画一个有边框填充矩形当背景(不画也行
char arr[]={输出的文本};//声明一个字符数组设置要输出的文本
int width=textwidth(arr);//获取字体的像素长度
int height=textheight(arr);//获取字体的像素宽度
outtextxy(x1+(x2-x1)/2-width/2,y1+(y2-y1)/2-height/2,arr)//输出文本框
举个栗子

在窗口居中输出文字
在这里插入图片描述

在这里插入图片描述
在图形中居中输出文字

在这里插入图片描述

在这里插入图片描述

呜呜呜长萌萌好可怜为什么要这么迫害她

图像处理函数

图像处理函数用于在窗口上显示图片。
在使用图像之前,需要定义一个对象(变量),然后把图片加载进对象才可以进行使用。
需要使用EasyX提供给我们的类型: IMAGE

loadimage——从文件中读取图像

loadimage(IMAGE *pDstImg,LPCTSTR pImgFile,int nWidth=0,int nHeight=0,bResize=false)

参数的含义为:
pDstImg 保存图像的IMAGE对象指针;
pImgFile 图片文件名
一般表示方法为 ./文件名//./表示项目文件夹的根目录, ../表示项目文件夹根目录的上一级。这两个是相对路径。
这里需要把文件放在对应的目录中才能使用。如果文件夹中不存在加载的文件,编译器不会报错,但也无法加载出来图片
或者使用绝对路径:C:\\.........即盘符
注意若使用反斜杠需要两个才表示反斜杠,或者干脆直接使用正斜杠。
nWidth 图片的拉伸宽度
nHeight图片的拉伸高度
bResize 是否调整IMAGE的大小以适应图片,可以不写

需要根据不同情况灵活使用。
这么长一大串参数怎么可能死背记住啊

PS:.png格式的图片不支持背景透明

putimage——在当前设备上绘制图像

putimage(int dstX,int dstY,IMAGE *pSrcImg,DWORD dwRop=SRCCOPY)

参数的含义为:
dstX 绘制位置左上角的X轴坐标

dstY 绘制位置左上角的Y轴坐标

pSrcImg 要绘制的IMAGE对象指针

dwRop 三元光栅操作码别问,问就死背
可以直接省掉

举个栗子

在这里插入图片描述

在这里插入图片描述

双倍快乐

鼠标消息函数

MOUSEMSG

鼠标消息需要使用MOUSEMSG类型,这是一个用于保存鼠标消息的结构体。
它的定义如下:

struct MOUSEMSG
{
	UINT uMsg;			// 当前鼠标消息
	bool mkCtrl;		// Ctrl 键是否按下
	bool mkShift;		// Shift 键是否按下
	bool mkLButton;		// 鼠标左键是否按下
	bool mkMButton;		// 鼠标中键是否按下
	bool mkRButton;		// 鼠标右键是否按下
	int x;				// 当前鼠标 x 坐标(物理坐标)
	int y;				// 当前鼠标 y 坐标(物理坐标)
	int wheel;			// 鼠标滚轮滚动值
};

常用的成员主要有uMsgxy

uMsg:指定鼠标消息类型,即判断用户用鼠标作出了哪种操作。

在这里插入图片描述
xy:当前鼠标的x,y坐标。

鼠标消息的判断与接收

使用MoustHit()函数判断是否有鼠标消息。
如果有就可以直接拿MOUSEMSG类变量用GetMouseMsg()函数接收消息了。

举个栗子

画图极简版:随着鼠标的移动画线,单击左右键更换颜色

在这里插入图片描述
效果如图:
在这里插入图片描述

呜呜呜你不要再迫害小长萌了

实战案例:鼠标点击确定下标

我是彩笔,这种问题居然想了很久都没想明白

我们在控制台写譬如扫雷,连连看,推箱子一类需要用到地图的游戏,会用一个二维数组存放地图,再用数组里的变量switch 指向图片来渲染画面。

然而,点击的位置反馈是不能直接反馈到数组里的。显然,我们不可能把单元格的大小设置成1px*1px,也就是说不能直接用点击返回的坐标数据去放入数组下标。

那么就创建一个规则,比如获取到的像素值/每个单元格的像素,就可以从0开始精确定位到每个单元格的数组下标了。

瓦片地图yyds

形象一点,就是划分若干个形状给二维数组,这若干个形状相当于“按钮”,点击“按钮”所在的区域就会反馈到这个“按钮”所属的数组。就像我们经常接触的“扫雷”游戏那样。

键盘消息函数

可这并不全是EasyX库里的函数啊!
管它是哪的函数,只要有用莽就完事了。

键盘消息函数用于获取键盘按键的消息。

用于获取键盘消息的函数

getch()

getch(); 需要包含头文件conio.h

事实上是个读取字符的函数,和getchar()getche()是一个作用:从控制台(标准O/I流)读取一个字符并返回。并且它们都是阻断函数:当没有读取到字符(getchar()是回车)时,它会让程序停止在这一步等待命令,阻碍程序的继续。
那为什么选择getch()呢?
相比于getch()getche()的作用同样是从控制台读取一个字符。但它在读入字符的同时会将字符回显在显示屏幕(控制台)上。
getchar()需要在输入后按回车才会输出返回值。getch()读取即返回,无需回车。

这个函数需要用返回值(如果有ASKII码就输出ASKII码)来判断动作:

  • 与非ASCII表字符的按键比较,需要使用虚拟键值。
    比如:
方向键键值
72
80
75
77
做个实验:

在这里插入图片描述

输入上下左右,输出如下:
在这里插入图片描述

这都什么鸟玩意
如图所见,每个方向键会输出两行值。
第一行是什么东西我也不知道,直接无视掉就好(也许是方向键的特征码…之类的?)
四个键的区别就在第二行,所以可以用第二行的四个值来区分方向键。
还是老实用wasd的好

在这里插入图片描述

在这里插入图片描述

  • 如果是与字母比较,直接写字母。

需要注意的是,getch()并不是标准库函数,使用时需要考虑到兼容性。

GetAsyncKeyState

GetAsyncKeyState(键值) 需要头文件windows.h ,但由于EasyX包含了windows头文件,所以无需自己包含,部分其他windows头文件的函数也一样。
这个函数需要传入一个键值,如果按下这个键,返回值为真。

方向键键值
VK_UP
VK_DOWN
VK_LEFT
VK_RIGHT

检测键盘消息的函数

kbhie()
无参函数,如果有键盘消息,返回真。

借助EasyX实现的船新操作

控制物体移动

getch()实现

因为太长截长图不太好使就直接放源码了QwQ

   int x = 50, y = 50, r = 10;//设定圆心和半径
	setfillcolor(GREEN);//要想生活过得去,头上总得......
	while (1)
	{
		cleardevice();//桌面清理大师
		putimage(0, 0,&bk);//由于我们使用的图片背景并不是程序定义上的背景,而是遮罩于背景之上,覆盖了整个绘图窗口的一张图片,所以在清理绘图窗口的时候图片也会被清除掉。所以清理完窗口的第一件事就是把背景找回来。
		//可怜的长萌萌还要被清理,屑指挥官.jpg
		solidcircle(x, y, r);//这句和while之前那句看不懂的自觉往回翻(恼
		char key=_getch();//获取键盘消息,声明字符变量key并把键盘消息的值赋值给它
		//相比于getch(),_getch()的兼容性更好
		//printf("%d %c\n", key, key);//打印键值
		switch (key)
		{
		case 72://方向键上
		case 'w':
		case 'W'://大小写的	情况都要考虑到,方向可是不分大小写的。
			y -= 10;
			cout << "向上!" << endl;
			break;
		case 80:
		case 's':
		case 'S':
			y += 10;
			cout << "向下!" << endl;
			break;
		case 75:
		case 'a':
		case 'A':
			x -= 10;
			cout << "向左!" << endl;
			break;
		case 77:
		case 'd':
		case 'D':
			x += 10;
			cout << "向右!" << endl;
			break;
		}
	}

正常情况下还需要写边界检查的,但我太懒了0_o这样图形可以穿出边界,无法显示在绘图窗口中。但它实质上还是存在的,可以通过移动再拉回来。

这样写虽然可以连续移动,但第一次移动与第二次移动之间有明显的延迟
并且不能同时按下两个按键以实现斜向移动

更常用:GetAsyncKeyState实现

double x = 50, y = 50, r = 10;
double d = 0.2;
setfillcolor(GREEN);
while(1)
{
		cleardevice();
		BeginBatchDraw();
		putimage(0, 0, &bk);
		solidcircle(x, y, r);
		EndBatchDraw();//前面的绘图步骤都一样
		if(GetAsyncKeyState(VK_UP))
		{
			y -= d;
			cout << "向上! " << x << " " << y << endl;
		}
		if (GetAsyncKeyState(VK_DOWN))
		{
			y += d;
			cout << "向下! " << x << " " << y << endl;
		}
		if (GetAsyncKeyState(VK_LEFT))
		{
			x -= d;
			cout << "向左! " << x << " " << y << endl;
		}
		if (GetAsyncKeyState(VK_RIGHT))
		{
			x += d;
			cout << "向右! " << x << " " << y << endl;
		}
}

在这里插入图片描述

为什么要拿这么大一片青青草原在小长萌的脸前晃啊喂!

这种方法的优缺点单从控制台我写的调试文本就可以看出大半。
相比于getch(),它的执行效率体感至少要高几倍。反应灵敏,丝毫没有拖泥带水,没有键位冲突(因为上下/左右的加减幅度是一样的,一起按=一起执行=效果相互抵消=没有该方向的相对运动),可以自由的上下左右反复横跳。球:我免费了!

但高效的执行效率带来的尴尬问题就是单位时间内执行命令的次数也多了同样的级别,导致若是想要达到基本相同的移动速率,每个指令的移动幅度要比getch()小很多很多,否则仅仅是轻轻移动,小球就会像炮弹一样飞出屏幕外。

由于最小的幅度1仍然过快,我不得不把位移的精度降到了1e-1。理论告诉我这种方法应该是行不通的才对,因为绘制函数中坐标的参数类型明明是int。但事实上我把一堆double放进函数,仍然编译运行通过并且达到了我的目的。

但屏幕的像素点显然是不会存在浮点型这一说的,不可能把1px再无限细分成一大堆小px。

所以我猜测:函数只取了数据的整数部分,直接舍去小数部分来设置坐标。

然后我就修改了幅度:
在这里插入图片描述
在这里插入图片描述

在程序运行中已经可以明显的看到小球的运动并不圆滑,一段时间才会移动一个像素。算是证实了这个猜想吧。

至于为什么能把double类型直接放进函数而不会产生任何错误……我猜是在输入到渲染之间将double类型强制转换成了int(正好直接舍去了小数),也可以解释运行过程中输出的x,y仍是浮点型的现象。这个我就没有追究那么多了……不报错就是成功

闪屏问题的解决方法——批量绘图

在设备上不断进行绘图操作是,有时会发生闪屏现象。为了保护用户的24K钛合金狗眼,需要使用批量绘图(双缓冲绘图)进行处理。

//双缓冲绘图,需要放在绘图代码之前和之后
BeginBatchDraw();//开始批量绘图
/*放置绘图代码*/
EndBatchDraw();//结束批量绘图

在帮助文档中:我们可以看到它的概念:
在这里插入图片描述

使用FlushBatchDraw()或者EndBatchDraw()对我们来说都可以。它们都会执行未完成的绘制任务,区别在于FlushBatchDraw()并不会结束批量绘制。

但出于运行的效果等原因,使用FlushBatchDraw()会更稳一些。

如使用EndBatchDraw()BeginBatchDraw()务必写到循环体内。

播放音乐

实现播放音乐需要使用windows的一个API。
1.首先需要包含头文件windows.hmmsystem.h。(windows.h已经被包含在EasyX的头文件graphics.h里了,所以在这里我们无需再声明一次)
2.然后需要加载静态库winmm.lib
3.最后就可以使用mciSendString函数来播放音乐了。

mciSendString函数

mciSendString(LPCSTR lpstrCommand,LPSTR lpstrReturnString,UINT uReturnLength,HWND hwndCallback)
参数:
lpstrCommand:命令字符串:“命令 设备[参数]”
lpstrReturnString:接收返回信息的缓冲区,为NULL时不返回信息。
uReturnLength:上述缓冲区的大小。
hwndCallback我也没看懂啥意思 一般为NULL。

实际操作

首先要把需要使用的音乐文件放置在解决方案的根目录下。除非你想用盘符
然后就可以代码实现了。
在这里插入图片描述

这个字符串就是命令+设备的形式。甚至可以在这个字符串里给文件起别名…

循环洗脑

需要注意的是,这个音乐播放完成后会自动停止的。如果想进行循环播放,需要在play BGM后加repeat

标题与对话框

事实上和EasyX有关的函数只有GetHWnd(),可这有什么关系呢

相关函数

GetHWnd();:获取绘图窗口句柄(一个用来标识对象或者项目的标识符,可以用来描述窗体,文件等,相当于一种特殊的智能指针),获取之后可以用来操作窗口。

SetWindowText(HWND hwnd,LPCTSTR str):改变指定窗口标题栏(如果存在)的文本内容。它并不改变其他应用程序中的控件的文本内容。
参数:
hwnd是要改变文本内容的窗口/控件的句柄
str是指向一个空结束字符串的指针(不带下标的字符数组,string,“”)。

MessageBox(HWND hwnd,LPCTSTR text,LPCTSTR title,MB_)
参数:
hwnd是弹出提示框窗口的句柄,可以为NULL。
但写作NULL时窗口是非模态的,反之是模态。直接体现就是模态窗口的层级和优先级很高,不处理那个弹窗你就无法对窗口进行任何操作。

text是窗口内的内容。
title是窗口的标题。
MB_指提示框中的按钮类型,如下表

参数作用
MB_ABORTRETRYIGNORE消息框含有三个按钮:Abort,Retry和Ignore
MB_OK消息框含有一个按钮:OK。这是缺省值
MB_OKCANCEL消息框含有两个按钮:OK和Cancel
MB_RETRYCANCEL消息框含有两个按钮:Retry和Cancel
MB_YESNO消息框含有两个按钮:Yes和No
MB_YESNOCANCEL消息框含有三个按钮:Yes,No和Cancel

从作用上可以很容易的看出参数写法的来由,再反向记忆就很方便。

HWND hWnd = GetHWnd();//获取窗口句柄
SetWindowText(hWnd,"love");//修改窗口标题
MessageBox(hWnd,"我是消息框","我是标题",MB_OKCANCEL);//设置模态对话框

在这里插入图片描述

这次终于没有迫害可爱的小长萌了QwQ

获取用户操作

MessageBox函数会返回一个int值作为用户的选择。可以通过这个值来判断用户的操作。
在这里插入图片描述
在这里插入图片描述

从对话框每次只弹一个而不是疯狂的叮叮叮然后迅速霸占整个屏幕的情况来看,它也是一个阻断函数。

Talk is cheap,show me the code.

#include<bits/stdc++.h>//我把万能头塞进vs了2333,vs并没有自带stdc++.h  
#include<graphics.h>//EasyX,yyds
#include<conio.h>//使用getch()/_getch()
#include<mmstream.h>//包含多媒体设备接口头文件(放歌)
#pragma comment(lib,"winmm.lib")//加载静态库(也是放歌的)
using namespace std;

int main()
{
	//绘制背景和窗口控制
	IMAGE bk;//设定图形变量
	//SHOWCONSOLE;//保留控制台显示
	//NOCLOSE;//没有关闭功能
	//NOMINIMIZE;//没有最小化功能
	//这三个函数要放在initgraph中的第三个参数才能生效,可用或预算符' | '并列使用
	initgraph(640, 480,SHOWCONSOLE/*|NOCLOSE|NOMINIMIZE*/);//绘制绘图窗口
	loadimage(&bk, "background.jpg", 640, 480);//加载图像到bk
	//图像应该存放在解决方案的根目录。对于ctrl c+v的代码,如果想让这条语句产生作用,需要自行放一张名为“background”的jpg类型文件到解决方案根目录里。
	putimage(0, 0, &bk);//绘制背景

	//播放音乐
	//mciSendString("open bgm.mp3 alias BGM", NULL, 0, NULL);//载入音乐,把这个文件取别名叫做BGM
	//mciSendString("play BGM", NULL, 0, NULL);//播放音乐
	//直接写成这样也可以
	mciSendString("open bgm.mp3", NULL, 0, NULL);
	mciSendString("play bgm.mp3 repeat", NULL, 0, NULL);

	//线条和图形绘制
	//setlinecolor(RED);//设定线条颜色
	//setlinestyle(PS_SOLID,5);//设置线条风格为直线,宽度为5
	//setfillcolor(GREEN);//设置填充颜色,下面好几个同
	//solidellipse(10, 100, 400, 200);//画一个无边框填充椭圆
	//setfillcolor(RED);
	//solidcircle(50, 50, 100);//画一个无边框填充圆形
	//setfillcolor(YELLOW);
	//fillpie(500, 400, 600, 300, 0, 90);//画一个有边框填充扇形
	//POINT points[] = { {200,100},{200,200},{300,100},{250,50} };
	声明一个点集合,用于构成多边形的顶点
	//fillpolygon(points, 4);//画一个有边框填充多边形,有四个顶点,包含在这个集合里
	//setfillcolor(BLUE);
	//solidrectangle(300, 20, 400, 60);//画一个无边框矩形
	//setfillcolor(BLACK);
	//fillroundrect(300, 200, 500, 300, 10, 10); //画一个有边框圆角矩形
	//setlinecolor(WHITE);
	//line(0, 400, 300, 300);//画一条线
	
	//字符串的输出和居中操作
	//setlinestyle(PS_SOLID,5);
	//LPCSTR str;
	//str = "Hello World!";//存放用于输出的文本
	//LPCSTR word;
	//word = "微软雅黑";//存放字体
	//settextcolor(RED);//设置字体颜色
	//settextstyle(50, 20, word);//设置字体样式和规格
	//setbkmode(TRANSPARENT);//设置背景为透明
	//int width = textwidth(str)/2;//为了省事我就直接/2了
	//int height = textheight(str)/2;
	//outtextxy(320-width, 240-height, str);//输出一个文本框

	//鼠标控制函数和相关操作
	//MOUSEMSG m;//声明鼠标信息变量
	//int color = 0xffffff;//设置初始颜色为白色
	//m = GetMouseMsg();//初始化鼠标信息,否则刚开始的时候鼠标信息并没有赋值给m
	//while (1)
	//{
	//	if (MouseHit())//如果检测到鼠标有操作
	//	{
	//		m = GetMouseMsg();//更新鼠标信息。这个必须有,否则m存放的仍是程序开始时的鼠标信息,将导致下面的操作统统无法进行
	//		switch (m.uMsg)
	//		{
	//		case WM_LBUTTONDOWN://如果单击左键
	//			cout << "你按下了左键!鼠标指针的位置是:" << m.x << " " << m.y << endl;//获取鼠标的x,y坐标信息并打印
	//			if(color!=0x55ff55)//如果此时画线颜色不是绿色
	//				cout << "画线的颜色改变了!" << endl;//提示
	//			color = 0x55ff55;//改变颜色
	//			break;
	//		case WM_RBUTTONDOWN://如果单击了右键,下方的操作都一样
	//			cout << "你按下了右键!鼠标指针的位置是:" << m.x << " " << m.y << endl;
	//			if(color!=0x0000aa)
	//				cout << "画线的颜色改变了!" << endl;
	//			color = 0x0000aa;//红色!
	//			break;
	//		};
	//	}
	//	putpixel(m.x, m.y, color);//画一个像素点,相当于打点连线
	//	//因为鼠标的移动也算作操作,所以即使没有按下按键也会跟随鼠标的移动画点
	//}

	//在图案中居中输出文本
	//setbkmode(OPAQUE);//把背景颜色换成不透明
	setbkmode(BKMODE_LAST);//同上,一个效果
	//setbkcolor(GREEN);
	//settextcolor(WHITE);
	//char arr[] = "已退出绘图!" ;
	//width = textwidth(arr)/2;
	//height = textheight(arr)/2;
	outtextxy(320-width, 240-height,arr );//这是直接窗口居中输出的写法
	来试试在任意一个图案中居中输出
	//setfillcolor(YELLOW);
	//setlinecolor(RED);//不要关注我奇怪的审美
	//fillroundrect(100, 50, 540, 170, 50, 50);//绘制一个圆角矩形,我故意没让它居中
	//outtextxy(320 - width,110-height,arr );//x轴因为相对居中和之前一样不用变,但y轴需要根据窗口计算啦

	//输出图片文件
	//IMAGE img;//定义一个图形对象
	//loadimage(&img, "./background.jpg", 320, 240);//加载图片文件到图形对象中
	//putimage(160, 120,&img);//输出图形对象

	//获取键盘消息和物体移动操作
	//1.getch()
	//int x = 50, y = 50, r = 10, d = 5;//设定圆心,半径和每次移动的单位
	//setfillcolor(GREEN);//要想生活过得去,头上总得......
	//while (1)
	//{
	//	cleardevice();//桌面清理大师
	//	//由于我们使用的图片背景并不是程序定义上的背景,而是遮罩于背景之上,覆盖了整个绘图窗口的一张图片,所以在清理绘图窗口的时候图片也会被清除掉。所以清理完窗口的第一件事就是把背景找回来。
	//	BeginBatchDraw();//双缓冲绘图,放在绘图代码的前后
	//	putimage(0, 0, &bk);//绘制背景
	//	//可怜的长萌萌还要被清理,屑指挥官.jpg
	//	solidcircle(x, y, r);//这句和while之前那句看不懂的自觉往回翻(恼
	//	EndBatchDraw();//结束批量绘图
	//	char key=_getch();//获取键盘消息,声明字符变量key并把键盘消息的值赋值给它
	//	//相比于getch(),_getch()的兼容性更好
	//	//printf("%d %c\n", key, key);//打印键值
	//	switch (key)
	//	{
	//	case 72://方向键上
	//	case 'w':
	//	case 'W'://大小写的	情况都要考虑到,方向可是不分大小写的。
	//		y -= d;
	//		cout << "向上!" << endl;
	//		break;
	//	case 80:
	//	case 's':
	//	case 'S':
	//		y += d;
	//		cout << "向下!" << endl;
	//		break;
	//	case 75:
	//	case 'a':
	//	case 'A':
	//		x -= d;
	//		cout << "向左!" << endl;
	//		break;
	//	case 77:
	//	case 'd':
	//	case 'D':
	//		x += d;
	//		cout << "向右!" << endl;
	//		break;
	//	}
	//}

//2.GetAsyncKeyState实现
//double x = 50, y = 50, r = 10;
//double d = 0.2;
//setfillcolor(GREEN);
//while(1)
//{
//		cleardevice();
//		BeginBatchDraw();
//		putimage(0, 0, &bk);
//		solidcircle(x, y, r);
//		EndBatchDraw();//前面的绘图步骤都一样
//		if(GetAsyncKeyState(VK_UP))
//		{
//			y -= d;
//			cout << "向上! " << x << " " << y << endl;
//		}
//		if (GetAsyncKeyState(VK_DOWN))
//		{
//			y += d;
//			cout << "向下! " << x << " " << y << endl;
//		}
//		if (GetAsyncKeyState(VK_LEFT))
//		{
//			x -= d;
//			cout << "向左! " << x << " " << y << endl;
//		}
//		if (GetAsyncKeyState(VK_RIGHT))
//		{
//			x += d;
//			cout << "向右! " << x << " " << y << endl;
//		}
//}

	//修改窗口标题和弹出文本框
	//HWND hWnd = GetHWnd();//获取窗口句柄
	//SetWindowText(hWnd, "love");//修改窗口标题
	//while(1)
	//{
	//	int ok = MessageBox(NULL, "我是消息框", "我是标题", MB_OKCANCEL);//设置模态对话框,获取用户的选择
	//	if (ok == IDOK)
	//		cout << "OK!" << endl;
	//	else if (ok = IDCANCEL)
	//	{
	//		cout << "Cancel." << endl;
	//	}
	//}

	//getchar();
	//cleardevice();//清理绘图窗口
	//getchar();
	//setbkcolor(RED);
	getchar();
	closegraph();//关闭绘图窗口

	return 0;
}

由于刚开始学就没有打包成函数,全挤在主函数里显得有点乱233333

除了绘制绘图窗口和播放音乐的部分,其他部分都被注释掉了,大家可以选择需要的部分ctrl+k/ctrk+u解除注释运行。

运行时记得要先去安装Easyx库!否则一定会报错。另外如果直接复制我的源码也需要安装stdc++.h,要不就换成其他VS自带的头文件。

BGM我使用的是.mp3格式周传雄先生的《冬天的秘密》吹爆小刚修改文件名为bgm。这个其实比较自由的,随便一个.mp3格式的音频文件都可以用。

使用的背景是:
在这里插入图片描述

可是为什么要迫害那么可爱的长萌萌呢,自己另找一张背景吧求求了QwQ

  • 114
    点赞
  • 608
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值