炫酷粒子表白 | 听说女神都想谈恋爱了!

2023-12-23 04:30

本文主要是介绍炫酷粒子表白 | 听说女神都想谈恋爱了!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

最近听女神说想谈恋爱了,✧(≖ ◡ ≖) 嘿嘿,一定不能放过这个机会,给她来个不一样的表白。

那么咱们就一起来把这个粒子系统玩出花来吧

演示地址:

https://es2049.studio/work-show/textPraticle/

如何将一系列的粒子组成一句表白呢?

实现原理其实很简单,Canvas 中有个 getImageData 的方法,可以得到一个矩形范围所有像素点数据。那么我们就试试来获取一个文字的形状吧。

第一步,用 measureText 的方法来计算出文字适当的尺寸和位置。

	// 创建一个跟画布等比例的 canvasconst width = 100;const height = ~~(width * this.height / this.width); // this.width , this.height 说整个画布的尺寸const offscreenCanvas    =document.createElement('canvas');const offscreenCanvasCtx    =offscreenCanvas.getContext('2d');offscreenCanvas.setAttribute('width', width);offscreenCanvas.setAttribute('height', height);// 在这离屏 canvas 中将我们想要的文字 textAll 绘制出来后,再计算它合适的尺寸offscreenCanvasCtx.fillStyle = '#000';offscreenCanvasCtx.font = 'bold 10px Arial';constmeasure=offscreenCanvasCtx.measureText(textAll); // 测量文字,用来获取宽度const size = 0.8;// 宽高分别达到屏幕0.8时的sizeconst fSize=Math.min(height * size * 10 / lineHeight, width * size * 10 / measure.width);  // 10像素字体行高 lineHeight=7 magicoffscreenCanvasCtx.font = `bold ${fSize}px Arial`;// 根据计算后的字体大小,在将文字摆放到适合的位置,文字的坐标起始位置在左下方const measureResize    =offscreenCanvasCtx.measureText(textAll);// 文字起始位置在左下方let left = (width - measureResize.width) / 2;const bottom=(height + fSize / 10 * lineHeight) / 2;offscreenCanvasCtx.fillText(textAll, left, bottom);

咱们可以 appendChild 到 body 里看眼

同学们注意,我要开始变形了 [推眼镜] 。 getImageData 获取的像素数据是一个 Uint8ClampedArray (值是 0 - 255 的数组),4 个数一组分别对应一个像素点的 R G B A 值。我们只需要判断 i * 4 + 3 不为 0 就可以得到需要的字体形状数据了。

// texts 所有的单词分别获取 data ,上文的 textAll 是 texts 加一起
Object.values(texts).forEach(item => {offscreenCanvasCtx.clearRect(0, 0, width, height);offscreenCanvasCtx.fillText(item.text, left, bottom);left += offscreenCanvasCtx.measureText(item.text).width;const data = offscreenCanvasCtx.getImageData(0, 0, width, height);const points = [];// 判断第 i * 4 + 3 位是否为0,获得相对的 x,y 坐标(使用时需乘画布的实际长宽, y 坐标也需要取反向)for (let i = 0, max = data.width * data.height; i < max; i++) {if (data.data[i * 4 + 3]) {points.push({x: (i % data.width) / data.width,                y: (i / data.width) / data.height});}}// 保存到一个对象,用于后面的绘制geometry.push({color: item.hsla,        points});
})

制定场景,绘制图形

文字图形的获取方式以及搞定了,那么咱们就可以把内容整体输出了。咱们定义一个简单的脚本格式。

	// hsla 格式方便以后做色彩变化的扩展const color1 = {h:197,s:'100%',l:'50%',a:'80%'};const color2 = {h:197,s:'100%',l:'50%',a:'80%'};// lifeTime 祯数const Actions = [{lifeTime:60,text:[{text:3,hsla:color1}]},   {lifeTime:60,text:[{text:2,hsla:color1}]},  {lifeTime:60,text:[{text:1,hsla:color1}], {lifeTime:120,text:[     {text:'I',hsla:color1},{text:'❤️',hsla:color2},{text:'Y',hsla:color1},{text:'O',hsla:color1},  {text:'U',hsla:color1}]},];

根据预设的脚本解析出每个场景的图形,加一个 tick 判断是否到了 lifeTime 切换到下一个图形重新绘制图形。

function draw() {this.tick++;if (this.tick >= this.actions[this.actionIndex].lifeTime) {this.nextAction();}this.clear();    this.renderParticles(); // 绘制点    this.raf = requestAnimationFrame(this.draw);
}function nextAction() {....//切换场景 balabala..this.setParticle(); // 随机将点设置到之前得到的 action.geometry.points 上}

这样咱们基本的功能已经完成了。

能不能再给力一点

说好的粒子系统,现在只是 context.arc 简单的画了一点。那咱们就来加个粒子系统吧。

class PARTICLE {// x,y,z 为当前的坐标,vx,vy,vz 则是3个方向的速度constructor(center) {this.center = center; this.x = 0;this.y = 0;        this.z = 0;        this.vx = 0;        this.vy = 0;        this.vz = 0;}// 设置这些粒子需要运动到的终点(下一个位置)setAxis(axis) {this.nextX = axis.x;        this.nextY = axis.y;        this.nextZ = axis.z;        this.color = axis.color;}step() {// 弹力模型 距离目标越远速度越快this.vx += (this.nextX - this.x) * SPRING;this.vy += (this.nextY - this.y) * SPRING;this.vz += (this.nextZ - this.z) * SPRING;// 摩擦系数 让粒子可以趋向稳定this.vx *= FRICTION;this.vy *= FRICTION;this.vz *= FRICTION;this.x += this.vx;        this.y += this.vy;        this.z += this.vz;}getAxis2D() {this.step();// 3D 坐标下的 2D 偏移,暂且只考虑位置,不考虑大小变化const scale = FOCUS_POSITION / (FOCUS_POSITION + this.z);return {x: this.center.x + (this.x * scale),y: this.center.y - (this.y * scale),};}
}

大功告成!

既然是 3D 的粒子,其实这上面还有不是文章可做,同学们可以发挥想象力来点更酷炫的。

还有什么好玩的

上面是将粒子摆成文字。那咱们当然也可以直接写公式摆出个造型。

// Actions 中用 func 代替 texts
{lifeTime: 100,func: (radius) => {const i = Math.random() * 1200;let x = (i - 1200 / 2) / 300;let y = Math.sqrt(Math.abs(x)) - Math.sqrt(Math.cos(x)) * Math.cos(30 * x);return {x: x * radius / 2,y: y * radius / 2,z: ~~(Math.random() * 30),color: color3};}
}

再把刚才文字转换形状的方法用一下

{lifeTime: Infinity,func: (width, height) => {if(!points.length){const img = document.getElementById("tulip");constoffscreenCanvas = document.createElement('canvas');constoffscreenCanvasCtx = offscreenCanvas.getContext('2d');const imgWidth = 200;const imgHeight = 200;offscreenCanvas.setAttribute('width', imgWidth);offscreenCanvas.setAttribute('height', imgHeight);offscreenCanvasCtx.drawImage( img, 0, 0, imgWidth, imgHeight);let imgData=offscreenCanvasCtx.getImageData( 0, 0, imgWidth, imgHeight);for ( let i = 0, max = imgData.width * imgData.height; i < max; i++) {if (imgData.data[i * 4 + 3]) {points.push({x: (i % imgData.width) / imgData.width,y: (i / imgData.width) / imgData.height});}}}const p= points[~~(Math.random() * points.length)]const radius = Math.min(width * 0.8, height * 0.8);return {x: p.x * radius - radius / 2,y: (1 - p.y) * radius - radius / 2,z: ~~(Math.random() * 30),color: color3};}
}

完美 ?

然后咱也可以用 drawImage 绘制图片来代替 arc 画点。

等等!!前面的效果总觉得哪里不对劲,好像有些卡 。

优化小提示

1、分层。如果还需要增加一些其他的内容到 Canvas 中的话,可以考虑拆出多个 Canvas 来做。

2、减少属性设置。包括 lineWidth、fillStyle 等等。Canvas 上下文是很复杂的一个对象,当你调它的一些属性设置时消耗的性能还是不少的。arc 之类的画图方法也要减少。

3、离屏绘制。不用 arc 画点,要怎么办。上面的延迟其实就是每次画点时都调用了一遍 fillStyle、arc。但是当我们绘制图片 drawImage 时,性能明显会好上很多。drawImage 除了直接绘图片外,还能绘制另一个 Canvas,所以我们提前将这些点画到一个不在屏幕上的 Canvas 里就可以了。

4、减少 js 计算,避免堵塞进程,可以使用 web worker。当然咱们目前的计算完全用不上这个 我这使用了 3000 个粒子,对比下使用离屏绘制前后的帧率。

总结

现在唯一限制你的就是想象力了。大家一起去征服老板,征服女神!

参考:

deformable particles

https://codepen.io/airen/pen/owRMoY

Canvas 参考手册

http://www.w3school.com.cn/tags/html_ref_canvas.asp

y=sqrt(abs(x))-sqrt(cos(x))*cos(40x)

作者:ES2049

来源:https://juejin.im/post/5bdfe1dbe51d45054771f9d4

转载于:https://my.oschina.net/u/3989863/blog/2986767

这篇关于炫酷粒子表白 | 听说女神都想谈恋爱了!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Unity 资源 之 Super Confetti FX:点亮项目的璀璨粒子之光

Unity 资源 之 Super Confetti FX:点亮项目的璀璨粒子之光 一,前言二,资源包内容三,免费获取资源包 一,前言 在创意的世界里,每一个细节都能决定一个项目的独特魅力。今天,要向大家介绍一款令人惊艳的粒子效果包 ——Super Confetti FX。 二,资源包内容 💥充满活力与动态,是 Super Confetti FX 最显著的标签。它宛如一位

回归预测 | MATLAB实现PSO-LSTM(粒子群优化长短期记忆神经网络)多输入单输出

回归预测 | MATLAB实现PSO-LSTM(粒子群优化长短期记忆神经网络)多输入单输出 目录 回归预测 | MATLAB实现PSO-LSTM(粒子群优化长短期记忆神经网络)多输入单输出预测效果基本介绍模型介绍PSO模型LSTM模型PSO-LSTM模型 程序设计参考资料致谢 预测效果 Matlab实现PSO-LSTM多变量回归预测 1.input和outpu

旅行商问题 | Matlab基于混合粒子群算法GA-PSO的旅行商问题TSP

目录 效果一览基本介绍建模步骤程序设计参考资料 效果一览 基本介绍 混合粒子群算法GA-PSO是一种结合了遗传算法(Genetic Algorithm, GA)和粒子群优化算法(Particle Swarm Optimization, PSO)的优化算法。在解决旅行商问题(Traveling Salesman Problem, TSP)时,这种混合算法可以结合两种算法的优点

GAMES104:12 游戏引擎中的粒子和声效系统-学习笔记

文章目录 一,粒子基础Particle System二,粒子渲染三,GPU粒子及生命周期控制四,粒子应用五,声音基础5.1 Sound System5.2 Digital Sound5.3 Audio Rendering QA 一,粒子基础Particle System 网游里你的付费大部分是为了粒子效果付费hhhh 粒子是拥有位置、速度、大小、颜色和生命周期的3d模型。

激光尘埃粒子计数器内光源选择:半导体激光管OR氦氖激光管?

在选择激光尘埃粒子计数器时,关键考虑因素包括光源类型、测量范围、灵敏度、稳定性、使用寿命以及应用场景等。针对这些因素,我们可以对半导体激光器和氦氖激光器(He-Ne激光器)进行比较,以判断选择哪种激光尘埃粒子计数器更合适。 激光管定义 半导体激光管(激光二极管) 半导体激光管,也被称为激光二极管(Laser Diode),是一种利用半导体PN结将电流转换成光能并产生激

【ACDream】 1093 女神的正多面体 矩阵快速幂

题目大意:给你三种正多边形,给你起点s,终点e以及最多行走的步数k,问有多少种路径方案(路径中只要有一个顶点不同即视为不同)。 题目分析: 可以通过矩阵快速幂求解。 为每个正多边形(最多三个)构建一个邻接矩阵A,然后第K步的方案数即为A^k。 结果即为A^1 + A^2 + A^3 + ...... + A^k. 对于这种形式的矩阵运算,我们可以把它拆分成: k为奇:ans = (

粒子群算法电力系统【原创附代码】

以下为我论文的代码。想要的话可以等我发出来再联系我。 请别小看这几行代码。占据了我代码main函数的半壁江山。 figure(1)tiledlayout(2,2);nexttilehold onplot(lambda_C_s, '-x', 'LineWidth',1.7, 'Color',[254 199 199]/255, 'DisplayName','供电局向区域外销售电价');p

HTML 实现炫酷选项卡效果

在前端开发中,创造出吸引人的交互效果能够极大地提升用户体验。今天,我将分享一段使用 HTML 和 CSS 实现的炫酷选项卡代码,并详细介绍其实现过程。 一、效果展示 我们的选项卡效果具有以下特点: 整体布局美观大方,页面居中显示。选项卡标签颜色鲜艳,分别为紫色(#a55eea)、蓝色(#45aaf2)和绿色(#26de81),且带有圆角边框和白色文字,鼠标悬停时透明度变为 0.7,增加交互反

多目标应用:基于自组织分群的多目标粒子群优化算法(SS-MOPSO)的移动机器人路径规划研究(提供MATLAB代码)

一、机器人路径规划介绍 移动机器人(Mobile robot,MR)的路径规划是 移动机器人研究的重要分支之,是对其进行控制的基础。根据环境信息的已知程度不同,路径规划分为基于环境信息已知的全局路径规划和基于环境信息未知或局部已知的局部路径规划。随着科技的快速发展以及机器人的大量应用,人们对机器人的要求也越来越高,尤其表现在对机器人的智能化方面的要求,而机器人自主路径规划是实现机器人智能化的

你听说过思维导图吗?

引子 如果你没听说过思维导图,那么你可能错过了很美妙的一个工具。不过没关系,现在了解一下也不算迟。 思维导图又叫心智导图是表达发散性思维的有效的图形思维工具 ,它简单却又极其有效,是一种革命性的思维工具。 名词解释大家都不爱看,所谓的思维导图其实就是类似于下面这样一张图。 是不是觉得好复杂,徒手画图?我可没说。我们现在接触到的文档大多数都是电子化的,所以你经常看到的思维