写在前面的话
这是刚学C的蒟蒻第一次挑战控制台程序以外的程序设计因为要做课设。第一次自己敲出黑框框之外程序的本蒟蒻肥肠兴奋,就根据视频自学(视频链接),总结视频内容和自己查阅的资料,写出了下面的笔记,希望它可以帮到大家。由于作者水平有限,难免有遗漏和不足之处,望神犇们多多包涵指正。
EasyX是一个适合像我这样的蒟蒻编程初学者操作的图形渲染库。
本质上,EasyX是将Windows繁琐的图形绘制操作封装在头文件中,从而实现用函数简单的调用。
百度EasyX官网,从官网中即可下载安装程序。它可以将EasyX直接安装在VS中。
使用EasyX需要在程序中添加头文件 include
。
EasyX帮助文档:EasyX在线文档
和数学的坐标系不同,EasyX中坐标的y轴正方向应该是向下的。
简单来讲,设备就是绘图表面;
在EasyX中,设备分两种:
1.默认的绘图窗口;
2.Image对象。
通过 SetWorkingImage()
函数可以设置当前用于绘图的设备。
设置当前用于绘图的设备后,所有的绘图函数都会绘制在该设备上。
默认是在绘图窗口绘图.
EasyX有四种表示颜色的方法:预定义常量,十六进制数字,RGB宏,使用HSLtoRGB
或HSVtoRGB
颜色转换其他色彩模型到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.用HSLtoRGB
,HSVtoRGB
转换其他色彩模型到RGB颜色
EasyX文档——HSLtoRGB
EasyX文档——HSVtoRGB
窗口函数用于对窗口的一些操作。
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(IMAGE *pDstImg,LPCTSTR pImgFile,int nWidth=0,int nHeight=0,bResize=false)
参数的含义为:
pDstImg
保存图像的IMAGE对象指针;
pImgFile
图片文件名
一般表示方法为 ./文件名
//./
表示项目文件夹的根目录, ../
表示项目文件夹根目录的上一级。这两个是相对路径。
这里需要把文件放在对应的目录中才能使用。如果文件夹中不存在加载的文件,编译器不会报错,但也无法加载出来图片
或者使用绝对路径:C:\\.........
即盘符
注意若使用反斜杠需要两个才表示反斜杠,或者干脆直接使用正斜杠。
nWidth
图片的拉伸宽度
nHeight
图片的拉伸高度
bResize
是否调整IMAGE的大小以适应图片,可以不写
需要根据不同情况灵活使用。
这么长一大串参数怎么可能死背记住啊
PS:.png格式的图片不支持背景透明
putimage(int dstX,int dstY,IMAGE *pSrcImg,DWORD dwRop=SRCCOPY)
参数的含义为:
dstX
绘制位置左上角的X轴坐标
dstY
绘制位置左上角的Y轴坐标
pSrcImg
要绘制的IMAGE对象指针
dwRop
三元光栅操作码别问,问就死背
可以直接省掉
双倍快乐
鼠标消息需要使用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; // 鼠标滚轮滚动值
};
常用的成员主要有uMsg
,x
和y
。
uMsg
:指定鼠标消息类型,即判断用户用鼠标作出了哪种操作。
使用MoustHit()
函数判断是否有鼠标消息。
如果有就可以直接拿MOUSEMSG
类变量用GetMouseMsg()
函数接收消息了。
画图极简版:随着鼠标的移动画线,单击左右键更换颜色
呜呜呜你不要再迫害小长萌了
我是彩笔,这种问题居然想了很久都没想明白
我们在控制台写譬如扫雷,连连看,推箱子一类需要用到地图的游戏,会用一个二维数组存放地图,再用数组里的变量switch 指向图片来渲染画面。
然而,点击的位置反馈是不能直接反馈到数组里的。显然,我们不可能把单元格的大小设置成1px*1px,也就是说不能直接用点击返回的坐标数据去放入数组下标。
那么就创建一个规则,比如获取到的像素值/每个单元格的像素,就可以从0开始精确定位到每个单元格的数组下标了。
瓦片地图yyds
形象一点,就是划分若干个形状给二维数组,这若干个形状相当于“按钮”,点击“按钮”所在的区域就会反馈到这个“按钮”所属的数组。就像我们经常接触的“扫雷”游戏那样。
可这并不全是EasyX库里的函数啊!
管它是哪的函数,只要有用莽就完事了。
键盘消息函数用于获取键盘按键的消息。
getch();
需要包含头文件conio.h
;
事实上是个读取字符的函数,和getchar()
和getche()
是一个作用:从控制台(标准O/I流)读取一个字符并返回。并且它们都是阻断函数:当没有读取到字符(getchar()是回车)时,它会让程序停止在这一步等待命令,阻碍程序的继续。
那为什么选择getch()
呢?
相比于getch()
,getche()
的作用同样是从控制台读取一个字符。但它在读入字符的同时会将字符回显在显示屏幕(控制台)上。
而getchar()
需要在输入后按回车才会输出返回值。getch()
读取即返回,无需回车。
这个函数需要用返回值(如果有ASKII码就输出ASKII码)来判断动作:
方向键 | 键值 |
---|---|
上 | 72 |
下 | 80 |
左 | 75 |
右 | 77 |
这都什么鸟玩意
如图所见,每个方向键会输出两行值。
第一行是什么东西我也不知道,直接无视掉就好(也许是方向键的特征码…之类的?)
四个键的区别就在第二行,所以可以用第二行的四个值来区分方向键。
还是老实用wasd的好
需要注意的是,getch()
并不是标准库函数,使用时需要考虑到兼容性。
GetAsyncKeyState(键值)
需要头文件windows.h
,但由于EasyX包含了windows头文件,所以无需自己包含,部分其他windows头文件的函数也一样。
这个函数需要传入一个键值,如果按下这个键,返回值为真。
方向键 | 键值 |
---|---|
上 | VK_UP |
下 | VK_DOWN |
左 | VK_LEFT |
右 | VK_RIGHT |
kbhie()
无参函数,如果有键盘消息,返回真。
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.h
和mmsystem.h
。(windows.h
已经被包含在EasyX的头文件graphics.h
里了,所以在这里我们无需再声明一次)
2.然后需要加载静态库winmm.lib
。
3.最后就可以使用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值作为用户的选择。可以通过这个值来判断用户的操作。
从对话框每次只弹一个而不是疯狂的叮叮叮然后迅速霸占整个屏幕的情况来看,它也是一个阻断函数。
#include //我把万能头塞进vs了2333,vs并没有自带stdc++.h
#include //EasyX,yyds
#include //使用getch()/_getch()
#include //包含多媒体设备接口头文件(放歌)
#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