用C++写个简单的程序表白老妈

2023-10-25 19:12

本文主要是介绍用C++写个简单的程序表白老妈,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

后天就是老妈的生日了,我打算写一个简单的程序表白老妈子,来肉麻一下她。在实现的过程中,有不少我没学过的知识,这些知识我都会予以补充。

创建图形窗口

创建图形窗口要包头文件:

#include<easyx.h>

这是简单的图形库,只要会写c语言就能用。

注意:只有先去官网下载这个图形库,再包才会生效!下载方法c站一搜就有。

包了这个图形库,我们以前运行程序出现的那个黑框窗口,就被图形窗口所取代了。

ok,现在要怎么创建图形窗口呢?用initgraph函数:初始化图形窗口。

#include<iostream>
#include<easyx.h>
​
int main() {initgraph(1000, 800);  //两个参数分别是 while(1){}return 0;
}

这里的while(1){}只是为了让图形窗口停留,不然它会一闪而过。

创建出来的图形窗口:

🚩补充:initgraph函数

initgraph(w,h,f);

用于初始化图形窗口。

三个参数分别为: width 绘图环境的宽度 height 绘图环境高度 flag 绘图环境样式(可省略)

播放音乐

🚩这里要介绍一个用于播放音乐的函数mciSendString(),它是用来播放多媒体文件的API指令,可以播放mp3、wma、wav、mid等文件。

我先来介绍一下函数名,帮助大家理解。mci媒体控制接口:media control interface

mciSendString可以理解为:向mci发送命令字符串

它在使用时一般按这个格式写:

mciSendString("open XX.mp3",NULL,0,NULL);

如果这样写编译不过去,就用这个格式:

mciSendString(_T("open XX.mp3"),NULL,0,NULL);   //注意XX.mp3要写明它的路径

只需要记忆第一个参数,后面三个就按照格式的来。

第一个参数重点记忆三个:open、play、close,分别对应打开、播放、关闭。

使用mciSendString()前要包含头文件:#include<mmsystem.h>

并导入库:#pragma comment<lib."winmm.lib">

实现:

#include<iostream>
#include<easyx.h>
#include<mmsystem.h>  
#pragma comment(lib,"winmm.lib")  
​
void Display() {//播放背景音乐   mciSendString(_T("open ./source/别看我只是一只羊.mp3 alias bgm "), NULL,0, NULL);   //alias给文件取别名,叫bgm,便于后续操作mciSendString(_T("play bgm "), NULL, 0, NULL);
}
int main() {initgraph(1000, 800);Display(); while(1){}return 0;
}

输出文字

🚩补充:

1.设置字体样式settextstyle()

我们在vs下是能看到这个函数的参数的,分别为:高度、宽度、样式。

2.设置字体颜色settextcolor()

settextcolor(BLUE);  //将字体设为蓝色
settextcolor(RGB(223,234,100));   //自选字体颜色

如何自选字体颜色?

打开画图软件,选择你喜欢的颜色,然后记住这三个参数:

因为所有颜色都是由红绿蓝(RGB) 三原色合成的,所以输入这三个参数就可以合成对应的颜色。

3.输出文字outtextxy()

outtextxy()函数,可以这样理解:out text x y,在坐标(x,y)输出文本信息。它是C++中的一个绘图函数,可以在屏幕上输出文本信息。它使用起来也很简单:

void outtextxy(int x,int y,const char* str);  //前两个参数是坐标信息,第三个参数是要输出的文本

图形窗口中的坐标轴,原点在左上角,x轴向右,y轴向下。

实现:

void Display() {mciSendString(_T("open ./source/别看我只是一只羊.mp3 alias bgm "), NULL,0, NULL);mciSendString(_T("play bgm "), NULL, 0, NULL);
​//设置字体样式settextstyle(40, 20, _T("仿宋"));//设置颜色settextcolor(RGB(100,216,234));//输出文字outtextxy(50, 50, _T("妈妈,我是宝宝!"));outtextxy(50, 100, _T("明天就是你的生日了,"));outtextxy(50, 150, _T("祝你生日快乐!"));outtextxy(50, 200, _T("我写了首诗,献给你:"));outtextxy(50, 250, _T("“鹅鹅鹅,红掌拨清波”"));
}

emmmm,挺丑的。现在我们来把它变好看一点。

如何做出颜色闪动效果

刚刚的颜色太单调了,只有一种。我们想要的效果是,每过几秒,它就能随机变幻颜色。要想生成随机值,就用rand()。

让颜色随机

🚩生成随机数rand():

rand()不需要参数,它会返回一个从0到最大随机数的任意整数,最大随机数的大小通常是固定的一个大整数。

如果你要产生0~99这100个整数中的一个随机整数,可以表达为:int num = rand() %100; 这样,num的值就是一个0~99中的一个随机数了。

而RGB的参数值范围是0~255,所以就用rand()%256。

在用rand()的过程中,我遇到的几个问题:

1.连续生成的颜色都比较相近,不够随机!

这是因为没有设置种子。什么是种子?请听我说~

rand()产生的是 伪随机数,并不是真正的随机数。这个伪随机数 是根据种子推导得到的。

所谓种子,就是初值。打个比方,我给的初值是100,那这个100作为种子,推出的伪随机数是99。这个99再作为种子,推出的伪随机数是102。102再作为种子,……

现在,你能知道为啥rand()连续产生的数值都比较相近了吧!

只有初值变化,伪随机数才变。如果不涉及密码学,那用时间来当种子完全够了,因为时间是时时刻刻在变化的。

在rand()之前,用srand()播种:

srand((unsigned)time(NULL));   //用srand()设置种子,叫“播种”。以时间作为种子

但要注意:srand不能写在循环里,因为循环一次的时间间隔太短了,time十分相近,产生的种子就是相同的了。

srand写在循环外(前面),只设置一次就可以了。

对了,记得引头文件<time.h>

2.闪动得太快了!一秒变好几个颜色。

要想延迟,用Sleep()函数,注意S大写。

Sleep(1000);  //延迟1000ms

实现:

#include<iostream>
#include<easyx.h>
#include<time.h>
#include<mmsystem.h>   
#pragma comment(lib,"winmm.lib")  
​
void Display() {//每次循环开始前,要清屏cleardevice(); //播放背景音乐  mciSendString(_T("open ./source/别看我只是一只羊.mp3 alias bgm "), NULL,0, NULL);mciSendString(_T("play bgm "), NULL, 0, NULL);
​//设置字体样式settextstyle(40, 29, _T("仿宋"));//设置文字颜色//srand((unsigned)time(NULL));settextcolor(RGB(rand()%256, rand() % 256, rand() % 256));//输出文字outtextxy(50, 50, _T("妈妈,我是宝宝!"));outtextxy(50, 100, _T("明天就是你的生日了,"));outtextxy(50, 150, _T("祝你生日快乐!"));outtextxy(50, 200, _T("我写了首诗,献给你:"));outtextxy(50, 250, _T("“鹅鹅鹅,红掌拨清波”"));//再插入点图案for (int i = 0; i < 8; i++) {      settextcolor(RGB(rand() % 256, rand() % 256, rand() % 256));outtextxy(rand() % 1001, rand() % 651, _T("🤍"));outtextxy(rand() % 1001, rand() % 651, _T("🎈"));}Sleep(1000);
}
int main() {//创建图形窗口initgraph(1000, 650);srand((unsigned)time(NULL));while (1) {Display();}return 0;
}

让图案背景透明

但此时,我们会发现,字被图案遮挡了:

 

这是因为,图案的背景被填充上了颜色,这种颜色是不透明的。而此时我们希望透过图案背景看到下面的字。

这就需要我们在输出文字之前,设置背景为透明。

setbkmode函数(设置背景模式):

setbkmode(TRANSPARENT);

来看效果:

最终效果:

插入背景图

流程是这样的:

Step1.先创建一个IMAGE类型的数组,将你准备的几张背景图按个放进数组。

Step2.在Display函数中,选一张图片插入图形窗口。

🚩补充:

1.从图片文件获取图像loadimage

void loadimage(
IMAGE* p,     // 保存图像的 IMAGE 对象指针
LPCTSTR pImgFile,     // 图片文件名
int nWidth = 0,    // 图片的拉伸宽度
int nHeight = 0,     // 图片的拉伸高度
bool bResize = false     // 是否调整 IMAGE 的大小以适应图片
);

2.输出图像putimage(int left,int right,void*buf,int ops);

参数(left,top)为输出屏幕图像的左上角,即输出图像的起始位置。buf指向要输出的内存中图像。参数ops控制图像以何种方式输出到屏幕上(可省略)。

实现:

IMAGE img[2];   //创建全局的数组。注:IMAGE是一个类型
​
int main() {//创建图形窗口initgraph(1000, 650);//将图片放进数组loadimage(img, _T("./source/1.jpg"), 1000, 650);loadimage(img+1, _T("./source/2.png"), 1000, 650);
​//展示效果srand((unsigned)time(NULL));while (1) {Display();}return 0;
}
oid Display() {//每次循环开始前,要清屏cleardevice();//插入背景putimage(0, 0, img+1);//播放背景音乐 mciSendString(_T("open ./source/别看我只是一只羊.mp3 alias bgm "), NULL,0, NULL);mciSendString(_T("play bgm "), NULL, 0, NULL);……
}

效果:

如果没看到效果,那可能是你图片的格式不行,我一开始那张图是.webp,不行。后来改属性变成.jpg或者.png,就可以了。

按任意键退出

为了展示效果,我们当前把程序写成了死循环。现在,我要达到 按任意键就能退出页面 的效果。这要用到函数_kbhit()。

包头文件:

#include<conio.h>

_kbhit()是用来检测有没有按键的,没有按键返回假。

那我们这样写,就可以让程序顺利运行,按键退出:

int main() {//创建图形窗口initgraph(1000, 650);//将图片放进数组loadimage(img, _T("./source/1.jpg"), 1000, 650);loadimage(img+1, _T("./source/2.png"), 1000, 650);
​//展示效果srand((unsigned)time(NULL));while (!_kbhit()) {     //没有按键返回真Display();}return 0;
}

那么最终效果呈现为:

(此处有bgm)

总代码

#include<iostream>
#include<easyx.h>
#include<conio.h>
#include<time.h>
#include<mmsystem.h>   
#pragma comment(lib,"winmm.lib")  
​
IMAGE img[2];
​
void Display() {//每次循环开始前,要清屏cleardevice();//插入背景putimage(0, 0, img+1);//播放背景音乐 mciSendString(_T("open ./source/别看我只是一只羊.mp3 alias bgm "), NULL,0, NULL);mciSendString(_T("play bgm "), NULL, 0, NULL);
​//设置字体样式settextstyle(40, 29, _T("仿宋"));//设置文字颜色settextcolor(RGB(rand()%256, rand() % 256, rand() % 256));//设置背景为透明setbkmode(TRANSPARENT);//输出文字outtextxy(50, 50, _T("妈妈,我是宝宝!"));outtextxy(50, 100, _T("明天就是你的生日了,"));outtextxy(50, 150, _T("祝你生日快乐!"));outtextxy(50, 200, _T("我写了首诗,献给你:"));outtextxy(50, 250, _T("“鹅鹅鹅,红掌拨清波”"));
​for (int i = 0; i < 8; i++) {settextcolor(RGB(rand() % 256, rand() % 256, rand() % 256));outtextxy(rand() % 1001, rand() % 651, _T("🤍"));outtextxy(rand() % 1001, rand() % 651, _T("🎈"));}Sleep(1000);
}
int main() {//创建图形窗口initgraph(1000, 650);//将图片放进数组loadimage(img, _T("./source/1.jpg"), 1000, 650);loadimage(img+1, _T("./source/2.png"), 1000, 650);
​//展示效果srand((unsigned)time(NULL));while (!_kbhit()) {Display();}return 0;
}

这篇关于用C++写个简单的程序表白老妈的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/284638

相关文章

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C

C++链表的虚拟头节点实现细节及注意事项

《C++链表的虚拟头节点实现细节及注意事项》虚拟头节点是链表操作中极为实用的设计技巧,它通过在链表真实头部前添加一个特殊节点,有效简化边界条件处理,:本文主要介绍C++链表的虚拟头节点实现细节及注... 目录C++链表虚拟头节点(Dummy Head)一、虚拟头节点的本质与核心作用1. 定义2. 核心价值二

C++ 检测文件大小和文件传输的方法示例详解

《C++检测文件大小和文件传输的方法示例详解》文章介绍了在C/C++中获取文件大小的三种方法,推荐使用stat()函数,并详细说明了如何设计一次性发送压缩包的结构体及传输流程,包含CRC校验和自动解... 目录检测文件的大小✅ 方法一:使用 stat() 函数(推荐)✅ 用法示例:✅ 方法二:使用 fsee

Windows下C++使用SQLitede的操作过程

《Windows下C++使用SQLitede的操作过程》本文介绍了Windows下C++使用SQLite的安装配置、CppSQLite库封装优势、核心功能(如数据库连接、事务管理)、跨平台支持及性能优... 目录Windows下C++使用SQLite1、安装2、代码示例CppSQLite:C++轻松操作SQ