C语言手写爱心-还原最新热剧撩妹代码

78 篇文章 1 订阅
62 篇文章 0 订阅

需求分析

最近这个爱心桥段火了!一个帅气高冷的学霸小哥,写了一个爱心代码,直接碾压了所有同学,并获得班花的迷之爱恋!这样的故事,不论真假,对于我们程序员而言,想想就觉得美滋滋... 

 是不是满满的青春感?荷尔蒙和胶原蛋白在代码中肆意飞溅!我们现在来复刻一下这个爱心撩妹代码吧!

代码效果

多说无益,直接上效果:

原理分析

看到不停奔涌而出的爱心,有经验的小伙伴,可能马上就会想到“粒子喷射器”,这个和粒子喷射器,确实有相似之处。不过游戏开发中的粒子效果,一般都使用已有的粒子模型,然后去修改参数和粒子素材。这里的话,我们就只有手动实现整个过程了,但是基础原理是相同的,产生新粒子(爱心),修改粒子的属性,粒子的渲染,粒子的消亡。
爱心轨迹分析

不要被小心心干扰我们的视线哦,很多人说,开发中架构大于代码细节。不论这话对不对,直觉告诉我,先分析出爱心的整体轨迹,然后再去实现其中的万点繁星。

怎样实现这个爱心轨迹呢?374年前,也就是公元1648年,52岁的大数学家笛卡尔,遇见了自己的白月光-瑞典公主克里斯汀,因为阶级差距不敢表白。其实也就是没有钱。没有钱,真的是万万不能的啊。通过各种机缘和努力,笛卡尔成为了公主的家庭数学教师,和白月光朝夕相处。数学家的智慧让公主无比崇拜,很快他们就相爱了。说实话,整日面对这样的公主,也许只有我们的韦神能够控制自己吧。

幸福和甜蜜总是那么短暂,瑞典国王很快发现他们的恋情。国王很生气,他只是请笛卡尔做家庭教师,万万没想到...国王处死了笛卡尔。笛卡尔在临刑前,写了最后一封情书。公主在情书中,发现了一个公式。公主毕竟没有白学,通过公式,绘制了一个图案,这就是传说中的“笛卡尔心形曲线”:

 好了,故事说完了,该写代码了。问题是我们很多人数学并不好,很多程序员老鸟的数学也不好,如果因为这个东西,就要去重学数学,那这个撩妹成本也太了。所以直接“借鉴”方便的公式使用。笛卡尔曲线公式演变出很多公式,我选择了这个(注意感觉这个公式绘制的心形比较苗条,有些公式绘制的效果像个大馒头,影响B格和效果)

这是一个极坐标公式。我们来复习一下极坐标的基本概念:

在极坐标中,任意一点的位置,由r和θ决定,r表示这个点到“极点”O之间的距离,θ表示如上图所示的夹角。根据这个公式,我们可以直接写出如下代码:.

// angle表示角度θ,r表示ρ
double r = sin(angle) * sqrt(fabs(cos(angle))) / (sin(angle) + 1.4142) - 2 * sin(angle) + 2;

 但是我们在使用代码进行绘制的时候,使用的都是直角坐标系,所以还需要把这个极坐标,转换成直角坐标系。直接查百度百科,得知:
 

 现在我们就的到了完整的曲线公式:

r = sin(angle) * sqrt(fabs(cos(angle))) / (sin(angle) + 1.4142) - 2 * sin(angle) + 2;
x = r * cos(angle);
y = r * sin(angle);

 轨迹测试

#include <stdio.h>
#include <graphics.h> 
#include <math.h>
 
int main(void) {
	initgraph(1920, 900);
	int R = 100;
	double angle = 0;
	for (angle = 0; angle <= 3.14 * 2; angle += 0.1) {
		double r = (sin(angle) * sqrt(fabs(cos(angle))) / (sin(angle) + 1.4142)
			- 2 * sin(angle) + 2);
		int x = R * r * cos(angle);
		int y = R * r * sin(angle); 
		char str[8];
		setbkmode(TRANSPARENT);
		sprintf_s(str, sizeof(str), "%.1f", angle);
		outtextxy(x, y, str);
	}
 
	system("pause");
	return 0;
}

 执行效果:

心形不完整,加偏移量:

#include <stdio.h>
#include <graphics.h> 
#include <math.h>
 
int main(void) {
	initgraph(1920, 900);
	int R = 100;
	double angle = 0;
	for (angle = 0; angle <= 3.14 * 2; angle += 0.1) {
		double r = (sin(angle) * sqrt(fabs(cos(angle))) / (sin(angle) + 1.4142)
			- 2 * sin(angle) + 2);
		int x = R * r * cos(angle) + 400;
		int y = R * r * sin(angle) + 400;
		char str[8];
		setbkmode(TRANSPARENT);
		sprintf_s(str, sizeof(str), "%.1f", angle);
		outtextxy(x, y, str);
	}
 
	system("pause");
	return 0;
}

 

效果发现这个心形式反着的,我们在来一个“垂直镜像”(把y坐标加一个负号反向即可):

#include <stdio.h>
#include <graphics.h> 
#include <math.h>
 
int main(void) {
	initgraph(1920, 900);
	int R = 100;
	double angle = 0; 
	for (angle = 0; angle <= 3.14 * 2; angle += 0.1) {
		double r = (sin(angle) * sqrt(fabs(cos(angle))) / (sin(angle) + 1.4142)
			- 2 * sin(angle) + 2);
		int x = R * r * cos(angle) + 400;
		int y = -R * r * sin(angle) + 400;
		char str[8];
		setbkmode(TRANSPARENT);
		sprintf_s(str, sizeof(str), "%.1f", angle);
		outtextxy(x, y, str);
	}
 
	system("pause");
	return 0;
}

 

 最后调整一下偏移量,完美!

心形实现

到现在,我们已经把心形轨迹模拟出来了,但是每个轨迹点的“爱心”还没有实现。其实最简单的办法就是直接使用一个心形小图片,但是这样子不方便表白活动的展开,总不能给学妹分享你的B格代码时,还要额外附送一个心形图片,这样子就没有神秘感,B格维度直接降低到零点。

其实也很简单,只要把字体调整一下就可以了,把字体设置为“Webdings”,再直接输出字符Y即可得到一个心形,但是代码中可以不要直接输出Y, 可以在代码中输出Y的ASCII码值89, 这样就更神秘了:-)

 再做一个测试:

#include <stdio.h>
#include <graphics.h> 
#include <math.h>
 
int main(void) {
	initgraph(600, 500);
	int R = 100;
	double angle = 0;
	for (angle = 0; angle <= 3.14 * 2; angle += 0.1) {
		double r = (sin(angle) * sqrt(fabs(cos(angle))) / (sin(angle) + 1.4142)
			- 2 * sin(angle) + 2);
		int x = R * r * cos(angle) + 260;
		int y = -R * r * sin(angle) + 80; //垂直翻转
		char str[8];
		setbkmode(TRANSPARENT);
		settextcolor(RED);
		settextstyle(40, 0, "Webdings");
		setbkmode(TRANSPARENT);
		outtextxy(x, y, 89); //89 就是 'Y'
	}
	system("pause");
	return 0;
}

 

 动态心形分析

让心形不断的奔涌而出,怎么实现呢?直接使用粒子喷射器的原理来做,假设每次喷射20个小心心,然后每隔一定时间(比如30毫秒),再次喷射20个小心心。同时在每次更新的时候,把每个小信息的size调大一个像素,每个小心心经历20轮之后,就消亡(消失)。

代码实现:

#include <stdio.h>
#include<graphics.h>
#include<time.h>
#include<math.h>
 
struct love {
    int height;  
    double angle;
    double r; //极坐标的r(0..1)
    double curR;
    int x;
    int y;
};
 
struct love mylove[400];
int offX = 260;
int offY = 180;
double R = 60;
 
void init() {
    initgraph(600, 480);
    memset(mylove, 0, sizeof(mylove));
    srand(time(NULL));
}
 
void getRandAngles(int* buf, int count) {
    int rangle = 314 * 2 * 2;
    for (int i = 0; i < count; i++) {
        int randTmp = 0;
        while (1) {
            randTmp = rand() % rangle;
            int j;
            for (j = 0; j < i && buf[j] != randTmp; j++);
            if (j >= i) break;
        }
        buf[i] = randTmp;
    }
}
 
void xiugaiData() {
    for (int i = 0; i < 400; i++) {
        if (mylove[i].curR == 0) continue;
        mylove[i].curR++;
        if (mylove[i].curR > 80) {
            memset(&mylove[i], 0, sizeof(struct love));
        }
        mylove[i].height++;
        mylove[i].x = (int)(-mylove[i].curR * mylove[i].r * cos(mylove[i].angle) + offX);
        mylove[i].y = -mylove[i].curR * mylove[i].r * sin(mylove[i].angle) + offY  - mylove[i].curR;
    }
}
 
void addNewHeart() {
    int buf[20];
    getRandAngles(buf, 20);
    int k;
    for (k = 0; k < 400 && mylove[k].curR > 0; k++);
 
    for (int i = k; i < k+20; i++) {
        double angle = mylove[i].angle = buf[i-k] * 0.01;
        mylove[i].r = sin(angle) * sqrt(fabs(cos(angle))) / (sin(angle) + 1.4142) - 2 * sin(angle) + 2;
        mylove[i].curR = R;
        mylove[i].height = 0;
        mylove[i].x = mylove[i].curR * mylove[i].r * cos(mylove[i].angle) + offX;
        mylove[i].y = -mylove[i].curR * mylove[i].r * sin(mylove[i].angle) + offY - mylove[i].curR;
    }
}
 
void updateWindow()
{
    BeginBatchDraw();
    cleardevice();
    settextcolor(RED);
    for (int i = 0; i < 400; i++) {
        if (mylove[i].curR == 0)continue;
        settextstyle(mylove[i].height + 10, 0, "Webdings");
        setbkmode(TRANSPARENT);
        outtextxy(mylove[i].x + 20, mylove[i].y + 20,  'Y'); //89
    }
    EndBatchDraw(); 
}
 
void mySleep(int delay) {
    unsigned long long start = GetTickCount();
    if (GetTickCount() < start + delay) Sleep(1);
}
 
int main() {
    init();
    while (1) {
        addNewHeart();
        updateWindow();
        xiugaiData();
        mySleep(30);
    }
    return 0;
}

 【公众号】:奇牛编程

 【C语言】五小时快速入门C语言:【C语言】五小时快速入门C语言

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值