关注「实验楼」,每天分享一个项目教程
谁说程序员只有代码和枸杞,今天让你们看看什么是程序员的浪漫……
正文共:3618 字
预计阅读时间:7 分钟
如果我是代码,那么你就是我的main函数,没有你,什么都做不了。
昨天是520,一年一度的秀恩爱大会,又是各种大招乱放的节奏,单身狗们表示受到一万点暴击。
说什么愿得一人心,一往而情深……但对于程序员们……
520也不过是周末加班的平凡一天。
不过,真的不是程序员们不浪漫,是忙啊!忙!
铺天盖地的代码,临到头要交的项目……晚上匆匆吃个饭继续埋头通宵敲代码不过是日常。
但这绝对不会成为程序员们的借口,相反,尽管工作很忙他们也会想尽办法为女朋友准备惊喜。
比如这样:
只要我人生的程序不终止,你的名字一直我的心事。
自从那天与你邂逅,我愿往后生命的每一天里都有你的烙印,至死方休。
若你不爱,默默守护,不打扰是我的温柔;若你倾心,爱你是我一生的荣光。
或者这样:
再或者设计一个小游戏
@ LA pike 第一关两人相遇 第二关两人第一次约会 第三关第一次出门旅游…… 最后一关打败疯狂粉丝,成功回家甚至设计一款产品也不在话下
@泡泡
虽然520过了,但技术还是要学起来的
下面给大家分享一个超浪漫的程序员表白方式
烟花
@王兴欣
1.属性设计
烟花应有的三个状态状态:
升空
等待炸裂
炸裂后
烟花:发射点(x,y),爆炸点(xEnd,yEnd),升空后等待炸裂时间(wait),炸裂后微粒个数(count),烟花半径(radius)
烟花炸裂后微粒:自身位置(x,y),自身大小(size),自身速度(rate),最大烟花半径(radius)。
config:为全局变量,以及控制参数,包括画布宽高,设定烟花属性等。
2. 设定全局变量
1. class Particle{
2. //默认值写法
3. constructor({x, y, size = 1, radius = 1.2} = {}){
4. this.x = x;
5. this.y = y;
6. this.size = size;
7.
8. this.rate = Math.random(); //每个微粒移动的速度都是随机不同的
9. this.angle = Math.PI * 2 * Math.random(); //每个微粒的偏移角度
10.
11. //每次微粒移动速度分解为横纵坐标的移动。
12. this.vx = radius * Math.cos(this.angle) * this.rate;
13. this.vy = radius * Math.sin(this.angle) * this.rate;
14. }
15.
16. go(){
17. this.x += this.vx;
18. this.y += this.vy;
19. this.vy += 0.02; //重力影响 y越大实际越偏下
20.
21. //空气阻力
22. this.vx *= 0.98;
23. this.vy *= 0.98;
24. }
25.
26. //画出微粒的位置
27. render(ctx){
28. this.go();
29. ctx.beginPath();
30. ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false);
31. ctx.fill();
32. }
33. }
3. 构建烟花类
1. class Firework{
2. constructor({x, y = config.height, xEnd, yEnd, count = 300, wait} = {}){
3. //烟花自身属性
4. this.x = x || config.width / 8 + Math.random() * config.width * 3 / 4;
5. this.y = y;
6. this.xEnd = xEnd || this.x;
7. this.yEnd = yEnd || config.width / 8 + Math.random() * config.width * 3 / 8;
8. this.size = 2;
9. this.velocity = -3;
10.
11. this.opacity = 0.8;
12. this.color = `hsla(${360 * Math.random() | 0},80%,60%,1)`;
13. this.wait = wait || 30 + Math.random() * 30;
14. //微粒个数等
15. this.count = count;
16. this.particles = [];
17. this.createParticles();
18.
19. this.status = 1;
20. }
21. //创建微粒
22. createParticles(){
23. for(let i = 0;i < this.count; ++i){
24. this.particles.push(new Particle({x:this.xEnd, y:this.yEnd}));
25. }
26. }
27. //升空
28. rise(){
29. this.y += this.velocity * 1;
30. this.velocity += 0.005; //升空时产生的阻力
31. //烟花升空到目标位置开始渐隐
32. if(this.y - this.yEnd <= 50){
33. this.opacity = (this.y - this.yEnd) / 50;
34. }
35. //如果到了目标位置 就开始第二个状态
36. if(this.y <= this.yEnd){
37. this.status = 2;
38. }
39. }
40.
41. //渲染烟花 烟花所有动作完成之后返回false
42. render(ctx){
43. switch(this.status){
44. case 1: //升空
45. ctx.save();
46. ctx.beginPath();
47. ctx.globalCompositeOperation = 'lighter';
48. ctx.globalAlpha = this.opacity;
49. ctx.translate(this.x, this.y);
50. ctx.scale(0.8, 2.3);
51. ctx.translate(-this.x, -this.y);
52. ctx.fillStyle = this.color;
53. ctx.arc(this.x + Math.sin(Math.PI * 2 * Math.random()) / 1.2, this.y, this.size, 0, Math.PI * 2, false);
54. ctx.fill();
55. ctx.restore();
56.
57. this.rise();
58. return true;
59. break;
60. case 2: //烟花消失阶段,等待炸裂
61. if(--this.wait <= 0){
62. this.opacity = 1;
63. this.status = 3;
64. }
65. return true;
66. break;
67. case 3: //炸裂之后 渲染烟花微粒
68. ctx.save();
69. ctx.globalCompositeOperation = 'lighter';
70. ctx.globalAlpha = this.opacity;
71. ctx.fillStyle = this.color;
72. for(let i = 0;i < this.particles.length;++i){
73. this.particles[i].render(ctx);
74. }
75. ctx.restore();
76. this.opacity -= 0.01;
77. return this.opacity > 0;
78. break;
79. default:
80. return false;
81. }
82. }
83. }
4.放烟花
1. const canvas = {
2. init: function(){
3. //一些属性的设定 可以不用管
4. this.setProperty();
5. this.renderBg();
6.
7. //循环体 **主要
8. this.loop();
9. },
10. setProperty: function(){
11. this.fireworks = [];
12. this.width = config.width;
13. this.height = config.height;
14. this.fireworkTime = (config.fireworkTime.min + (config.fireworkTime.max - config.fireworkTime.min) * Math.random()) | 0;
15.
16. this.bgCtx = document.querySelector('#bg').getContext('2d');
17. this.fireworkCtx = document.querySelector('#firework').getContext('2d');
18. },
19. renderBg(){
20. this.bgCtx.fillStyle = 'hsla(210, 60%, 5%, 0.9)'
21. this.bgCtx.fillRect(0, 0, this.width, this.height);
22. },
23.
24. loop(){
25. requestAnimationFrame(this.loop.bind(this));
26. this.fireworkCtx.clearRect(0, 0, this.width, this.height);
27.
28. //随机创建烟花
29. if(--this.fireworkTime <= 0){
30. this.fireworks.push(new Firework(config.fireworkOpt));
31. //每次到点之后重新设置烟花产生时间 (|0转化为整数)
32. this.fireworkTime = (config.fireworkTime.min + (config.fireworkTime.max - config.fireworkTime.min) * Math.random()) | 0;
33. }
34.
35. for(let i = this.fireworks.length - 1; i >= 0; --i){
36. //渲染烟花 (若返回值为false则移除烟花)
37. !this.fireworks[i].render(this.fireworkCtx) && this.fireworks.splice(i,1);
38. }
39.
40. }
41. }
42. canvas.init();
5.完善
此时烟花是这样的,感觉少了点小尾巴。现在我们每一帧都是清除了画布,如果要加上小尾巴其实也很简单,每一帧都不要清除画布,而是覆盖一层新的有透明度的天空上去。
1. //canvas.loop方法
2.
3. // this.fireworkCtx.clearRect(0, 0, this.width, this.height);
4. this.fireworkCtx.fillStyle = config.skyColor;
5. this.fireworkCtx.fillRect(0,0,this.width,this.height);
这时就变成这样了。但是,还是缺少了在爆炸瞬间天空变亮的场景。那么在画烟花的时候,先会获取一下烟花的颜色以及透明度。
1. // *****Firework constructor
2. // this.color = `hsla(${360 * Math.random() | 0},80%,60%,1)`;
3. this.hue = 360 * Math.random() | 0;
4. this.color = `hsla(${this.hue},80%,60%,1)`;
1. // *****Firework 新增实例方法
2. getSkyColor(){
3. const skyColor = {
4. //只有炸裂阶段才返回亮度
5. lightness: this.status == 3 ? this.opacity : 0 ,
6. hue: this.hue
7. };
8. return skyColor;
9. }
1. // *****config 修改config的skyColor
2. // skyColor: 'hsla(210, 60%, 5%, 0.2)',
3. skyColor: 'hsla({hue}, 60%, {lightness}%, 0.2)',
1. // canvas.loop方法
2. //this.fireworkCtx.fillStyle = config.skyColor;
3. //每次替换色调与亮度值。
4. this.fireworkCtx.fillStyle = config.skyColor.replace('{lightness}', 5 + this.skyColor.lightness * 15).replace('{hue}' , this.skyColor.hue);
5.
6. this.skyColor = { //新增
7. lightness: 0,
8. hue: 210
9. };
10. for(let i = this.fireworks.length - 1; i >= 0; --i){
11. //新增 天空颜色为最亮的烟花的颜色
12. this.skyColor = this.skyColor.lightness >= this.fireworks[i].getSkyColor().lightness ? this.skyColor : this.fireworks[i].getSkyColor();
13. !this.fireworks[i].render(this.fireworkCtx) && this.fireworks.splice(i,1);
14. }
大功告成。
作者:sugarain
文中部分内容整理自网络
学习更多
楼+「 Python实战 」、「 Linux运维与Devops实战 」优惠报名中——来自腾讯、Intel、IBM等互联网大厂的一线大牛,带你12周内打通Python、Linux的任督二脉!
点击下面的链接了解详情:
他在一线互联网大厂研发PHP数年,用6周时间带你打通“全宇宙最好的语言”