动态爱心(C/C++)

首先来看效果

C/C++动态爱心

源代码(代码思路主要参考了b站up主码农天高)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<math.h>
#include<time.h>
#include<windows.h>
#include<graphics.h>
#include<mmsystem.h>//要调用mciSendString必须包含这个头文件
#pragma comment(lib,"WINMM.LIB");//及这个预处理
#define SIZE 9
#define CANVAS_WIDTH 640
#define CANVAS_HEIGHT 480
#define CANVAS_CEBTER_X CANVAS_WIDTH / 2
#define CANVAS_CEBTER_Y CANVAS_HEIGHT / 2
void scatter_inside(int xo, int yo, double beta = 0.1)
{
	//随机内部扩散
	double ratio_x = -beta * log(rand());
	double ratio_y = beta * log(rand());
	double x, y;
	x = ratio_x * xo;
	y = ratio_y * yo;
	putpixel(x, y, RGB(245,145,247));
}
void heart(int particle,double ratio,COLORREF color)
{
	double x, y;//记录直角坐标
	double i;//控制循环和心的精细程度
	//笛卡尔爱心
	//for (i = 0; i <= 2 * size; i += 0.1)
	//{
	//	m = i;
	//	n = -size * (((sin(i) * sqrt(fabs(cos(i)))) / (sin(i) + 1.4142)) - 2 * sin(i) + 2);
	//	x = n * cos(m) + xo;
	//	y = n * sin(m) + yo;
	//	putpixel(x, y, color);
	//}
	for (i = 0; i <= 2 * particle; i += 0.001)
	{
		//关键,画爱心的公式
		x = 16 * (sin(i) * sin(i)* sin(i));
		y = -(13 * cos(i) - 5 * cos(2 * i) - 2 * cos(3 * i) - cos(4 * i));
		//控制爱心的大小
		x = x * ratio;
		y = y * ratio;
		putpixel(x, y, color);
		//扩散
		if((int)(i*10000)% 7 == 0)//扩散粒子太多了,控制粒子产生量
		scatter_inside(x, y);
		if ((int)(i * 10000) % 107 == 0)
		scatter_inside(x, y, 0.07);
		//爱心里面加字
		settextcolor(RGB(91, 176, 179));//设置爱心字体颜色
		settextstyle(40, 0, L"楷体");
		outtextxy(0, 0, L"喵");
	}

}

int main()
{
	srand(time(0));
	initgraph(CANVAS_WIDTH, CANVAS_HEIGHT);
	//添加音乐
	mciSendString(L"open youhebuke.mp3 alias music", 0, 0, 0);
	mciSendString(L"play music repeat",0,0,0);//+repeat循环播放
-----------------------------------------------------------------------------------------
             //开头界面,可删除
		settextcolor(RGB(245,152,173));//颜色参数调配,画图板查看颜色参数
		settextstyle(15, 0, L"宋体");
		outtextxy(300, 300, L"----被虐的喵");
		settextcolor(RGB(91, 176, 179));//颜色参数调配,画图板查看颜色参数
		settextstyle(40, 0, L"楷体");
		outtextxy(175, 180, L"C/C++版跳动爱心");
		fflush(stdout);
		Sleep(10000);

		cleardevice();//清画布,重新画
-----------------------------------------------------------------------------------------
	setorigin(CANVAS_CEBTER_X, CANVAS_CEBTER_Y);
	//循环播放
	while (1)
	{

		double ratio;//控制粒子频率和图像大小
		for (int i = 140; i <= 250; i++)
		{
			ratio = 16 * sin(i / 360.0 * 3.1415926535);
		}
		
		if (ratio < 0)
		{
			ratio *= -1;
     	}
		//Sleep(10);
		heart(80, ratio, RED);
		cleardevice();
		
	}
	mciSendString(L"close music", 0, 0, 0);
	getchar();
	closegraph();
	return 0;
}

 这次写的代码有点臭,耦合度太高了,以至于修改一个参数会导致整体改变。于是就没实现爱心跳动了。

一,下载一个可视化库,推荐easyx

直接去官网下载https://easyx.cn/

下载好后会有这个exe文件

打开文件,点下一步到这个界面

 选择你要配置的编译器,它就会自动帮你将库配置好。

第二步 将所要的头文件,画布大小设置好

第三步 初始化画布,并画一个普通的爱心

最初我用的笛卡尔公式。画出来的爱心并不是很好看。我在网上不断找也找不到满意的公式,最终还是借用了b站up码农天高找的这个公式

 

 为什么要手动控制呢?因为最初创建窗口位置默认坐标为

四 爱心渲染

接下来要对这个爱心渲染,就要不断在它每个点的周围随机渲染一些点, 这里就需要获取每个点的坐标,但是由于函数只能返回一个值,我也没用类。所以直接在heart函数内部写了个渲染函数

又因为随机所以用到rand(),产生随机数,至于这个scatter_inside函数实现思路我依旧是参考up主码农天高的。

参数我没控制好,就变成这样了。反正自己根据画布和画的爱心大小,慢慢调去

对了,这里颜色是可以控制的 

使用RGB(xxx,xxx,xxx)红绿蓝的参数,而如果像按照自己喜欢的颜色调,打开画图板

点击编辑颜色,里面就有颜色参数、

 

 第五步 让爱心按一定频率波动起来

也就是画n张大小不同的连续图,循环播放,这里频率控制我用的是正选函数sin,这里就是我自己找到公式实现了,

我选的是这个频率段,这样既可以让爱心收缩也放大,但是由于我写的耦合性太高,导致不能轻易改频率,会导致改变爱心大小。以及如果每次爱心动起来,缩放,周围粒子坐标也要有一定改变,但由于我能力有限,再加上耦合度高,全用函数实现,难以获得坐标,所以我就没实现了。

将sin函数公式转为代码 

 

这时我也不用size控制大小了,直接用ratio,反正这个爱心大小自己慢慢调。

基本上这就是我的爱心实现流程了。

补:添加音乐和汉字

添加音乐用到的函数有     mciSendString();

要包含

这两个,不然会出现链接错误

我来解释一下怎么使用

 首先将你要加入的xxx.mp3音乐放入所在路径

右键这里,打开所在文件夹,将音乐放入其中

然后使用mciSendString(L"open xxx.mp3 alias music",0,0,0)

这些字符串意思是open打开音乐文件(open是系统调用接口),给它命名music. 传3个000参数过去。

然后再调用mciSendString(L"play music repeat",0,0,0);

播放music 后面repeat可以不加,不加只播放一次,加了就是重复播放。

 添加汉字

这个数easyx提供的函数接口,具体使用参考EasyX 文档 - 文字输出相关函数

这里仅提供在爱心里插入文字

将他们放入heart函数里,在爱心和随机散射粒子画出来后,在执行这三行代码

outtextxy(坐标,坐标,L"文本内容");

这里坐标参考第一步画的爱心位置来估计大概范围

outtextxy可多次调用,多次输入。 

这是鄙人第一次学习使用eaxyx,若有错误,请以斧正

谢谢阅读!!!!!

  • 57
    点赞
  • 274
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
``` <!DOCTYPE html> <html> <head> <title></title> </head> <style> * { padding: 0; margin: 0; } html, body { height: 100%; padding: 0; margin: 0; background: #000; } canvas { position: absolute; width: 100%; height: 100%; } .aa { position: fixed; left: 50%; bottom: 10px; color: #ccc; } </style> <body> <canvas id="pinkboard"></canvas> <script> /* * Settings */ var settings = { particles: { length: 500, // maximum amount of particles duration: 2, // particle duration in sec velocity: 100, // particle velocity in pixels/sec effect: -0.75, // play with this for a nice effect size: 30 // particle size in pixels } }; /* * RequestAnimationFrame polyfill by Erik M?ller */ (function () { var b = 0; var c = ["ms", "moz", "webkit", "o"]; for (var a = 0; a < c.length && !window.requestAnimationFrame; ++a) { window.requestAnimationFrame = window[c[a] + "RequestAnimationFrame"]; window.cancelAnimationFrame = window[c[a] + "CancelAnimationFrame"] || window[c[a] + "CancelRequestAnimationFrame"]; } if (!window.requestAnimationFrame) { window.requestAnimationFrame = function (h, e) { var d = new Date().getTime(); var f = Math.max(0, 16 - (d - b)); var g = window.setTimeout(function () { h(d + f); }, f); b = d + f; return g; }; } if (!window.cancelAnimationFrame) { window.cancelAnimationFrame = function (d) { clearTimeout(d); }; } })(); /* * Point class */ var Point = (function () { function Point(x, y) { this.x = typeof x !== "undefined" ? x : 0; this.y = typeof y !== "undefined" ? y : 0; } Point.prototype.clone = function () { return new Point(this.x, this.y); }; Point.prototype.length = function (length) { if (typeof length == "undefined") return Math.sqrt(this.x * this.x + this.y * this.y); this.normalize(); this.x *= length; this.y *= length; return this; }; Point.prototype.normalize = function () { var length = this.length(); this.x /= length; this.y /= length; return this; }; return Point; })(); /* * Particle class */ var Particle = (function () { function Particle() { this.position = new Point(); this.velocity = new Point(); this.acceleration = new Point(); this.age = 0; } Particle.prototype.initialize = function (x, y, dx, dy) { this.position.x = x; this.position.y = y; this.velocity.x = dx; this.velocity.y = dy; this.acceleration.x = dx * settings.particles.effect; this.acceleration.y = dy * settings.particles.effect; this.age = 0; }; Particle.prototype.update = function (deltaTime) { this.position.x += this.velocity.x * deltaTime; this.position.y += this.velocity.y * deltaTime; this.velocity.x += this.acceleration.x * deltaTime; this.velocity.y += this.acceleration.y * deltaTime; this.age += deltaTime; }; Particle.prototype.draw = function (context, image) { function ease(t) { return --t * t * t + 1; } var size = image.width * ease(this.age / settings.particles.duration); context.globalAlpha = 1 - this.age / settings.particles.duration; context.drawImage( image, this.position.x - size / 2, this.position.y - size / 2, size, size ); }; return Particle; })(); /* * ParticlePool class */ var ParticlePool = (function () { var particles, firstActive = 0, firstFree = 0, duration = settings.particles.duration; function ParticlePool(length) { // create and populate particle pool particles = new Array(length); for (var i = 0; i < particles.length; i++) particles[i] = new Particle(); } ParticlePool.prototype.add = function (x, y, dx, dy) { particles[firstFree].initialize(x, y, dx, dy); // handle circular queue firstFree++; if (firstFree == particles.length) firstFree = 0; if (firstActive == firstFree) firstActive++; if (firstActive == particles.length) firstActive = 0; }; ParticlePool.prototype.update = function (deltaTime) { var i; // update active particles if (firstActive < firstFree) { for (i = firstActive; i < firstFree; i++) particles[i].update(deltaTime); } if (firstFree < firstActive) { for (i = firstActive; i < particles.length; i++) particles[i].update(deltaTime); for (i = 0; i < firstFree; i++) particles[i].update(deltaTime); } // remove inactive particles while ( particles[firstActive].age >= duration && firstActive != firstFree ) { firstActive++; if (firstActive == particles.length) firstActive = 0; } }; ParticlePool.prototype.draw = function (context, image) { // draw active particles if (firstActive < firstFree) { for (i = firstActive; i < firstFree; i++) particles[i].draw(context, image); } if (firstFree < firstActive) { for (i = firstActive; i < particles.length; i++) particles[i].draw(context, image); for (i = 0; i < firstFree; i++) particles[i].draw(context, image); } }; return ParticlePool; })(); /* * Putting it all together */ (function (canvas) { var context = canvas.getContext("2d"), particles = new ParticlePool(settings.particles.length), particleRate = settings.particles.length / settings.particles.duration, // particles/sec time; // get point on heart with -PI <= t <= PI function pointOnHeart(t) { return new Point( 160 * Math.pow(Math.sin(t), 3), 130 * Math.cos(t) - 50 * Math.cos(2 * t) - 20 * Math.cos(3 * t) - 10 * Math.cos(4 * t) + 25 ); } // creating the particle image using a dummy canvas var image = (function () { var canvas = document.createElement("canvas"), context = canvas.getContext("2d"); canvas.width = settings.particles.size; canvas.height = settings.particles.size; // helper function to create the path function to(t) { var point = pointOnHeart(t); point.x = settings.particles.size / 2 + (point.x * settings.particles.size) / 350; point.y = settings.particles.size / 2 - (point.y * settings.particles.size) / 350; return point; } // create the path context.beginPath(); var t = -Math.PI; var point = to(t); context.moveTo(point.x, point.y); while (t < Math.PI) { t += 0.01; // baby steps! point = to(t); context.lineTo(point.x, point.y); } context.closePath(); // create the fill context.fillStyle = "#ea80b0"; context.fill(); // create the image var image = new Image(); image.src = canvas.toDataURL(); return image; })(); // render that thing! function render() { // next animation frame requestAnimationFrame(render); // update time var newTime = new Date().getTime() / 1000, deltaTime = newTime - (time || newTime); time = newTime; // clear canvas context.clearRect(0, 0, canvas.width, canvas.height); // create new particles var amount = particleRate * deltaTime; for (var i = 0; i < amount; i++) { var pos = pointOnHeart(Math.PI - 2 * Math.PI * Math.random()); var dir = pos.clone().length(settings.particles.velocity); particles.add( canvas.width / 2 + pos.x, canvas.height / 2 - pos.y, dir.x, -dir.y ); } // update and draw particles particles.update(deltaTime); particles.draw(context, image); } // handle (re-)sizing of the canvas function onResize() { canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; } window.onresize = onResize; // delay rendering bootstrap setTimeout(function () { onResize(); render(); }, 10); })(document.getElementById("pinkboard")); </script> </body> </html> ``` ![示例图片](https://devbit-static.oss-cn-beijing.aliyuncs.com/devbit-static/img/heart.png)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值