我创建了一个小点的blob。我希望我的blob根据mouseX和mouseY在其表面显示噪音。我希望它在鼠标所在的象限中显示高噪声。我希望它是波浪状的。以下是我的代码。
var ctx = document.querySelector("canvas").getContext("2d");
var cx = 200;
var cy = 200;
var radius = 50;
var amp = 2;
var mouseX = 0;
var mouseY = 0;
document.querySelector("canvas").addEventListener("mousemove", function (e) {
mouseX = e.clientX;
mouseY = e.clientY;
});
function drawTheBlob() {
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, 400, 400);
ctx.beginPath();
ctx.strokeStyle = "#fff";
for (var a = 0; a < 360; a ++) {
var angle = a * Math.PI/180;
var x = cx + radius * Math.cos(angle) + Math.random() * amp;
var y = cy + radius * Math.sin(angle) + Math.random() * amp;
ctx.lineTo(x, y);
}
ctx.stroke();
ctx.closePath();
requestAnimationFrame(drawTheBlob);
}
drawTheBlob();
<canvas width="400" height="400"></canvas>
答案 0 :(得分:1)
在圆上添加sin波。使用ctx.arc
绘制圆的平坦部分以获得速度,因为绘制许多带线条的圆圈会很慢。请参阅代码以了解已完成的操作。
var ctx = document.querySelector("canvas").getContext("2d");
ctx.lineWidth = 3;
ctx.lineJoin = "round";
var cx = 100;
var cy = 100;
var radius = 50;
var mouseX = 0;
var mouseY = 0;
const quadWidth = Math.PI / 2; // area of effect PI/2 is 90 degree
const steps = radius / quadWidth; // number steps around the circle matches 1 pixel per step,
const noiseAmpMax = 5; // in pixels
const noiseWaveMoveSpeed = 2; // speed of waves on circle in radians per second
const noiseWaveFreq = 16; // how many waves per 360 deg
document.querySelector("canvas").addEventListener("mousemove", function(e) {
mouseX = e.clientX;
mouseY = e.clientY;
});
function drawTheBlob(time) { // time is passed from the requestAnimationFrame call
var amp = 0; // amplitude of noise
var wavePos = ((time / 1000) * Math.PI) * noiseWaveMoveSpeed;
var mouseDir = Math.atan2(mouseY - cy, mouseX - cx);
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, 400, 400);
ctx.beginPath();
ctx.strokeStyle = "#fff";
ctx.fillStyle = "red";
// draw arc for parts that have no noise as it is a log quicker
ctx.arc(cx, cy, radius, mouseDir + quadWidth / 2, mouseDir + Math.PI * 2 - quadWidth / 2);
for (var a = 0; a < 1; a += 1 / steps) {
var angle = (mouseDir - quadWidth / 2) + a * quadWidth;
var angDist = Math.abs(angle - mouseDir); // find angular distance from mouse
// as a positive value, it does not mater
// what the sign is
if (angDist < quadWidth / 2) { // is angle distance within the range of effect
// normalise the distance (make it 0 to 1)
amp = 1 - angDist / (quadWidth / 2);
} else {
amp = 0; // no noise
}
// amp will be zero if away from mouse direction and 0 to 1 the closer to
// mouse angle it gets.
// add a sin wave to the radius and scale it by amp
var dist = radius + Math.sin(wavePos + noiseWaveFreq * angle) * noiseAmpMax * amp;
var x = cx + dist * Math.cos(angle);
var y = cy + dist * Math.sin(angle);
ctx.lineTo(x, y);
}
ctx.closePath(); // use close path to close the gap (only needed if you need to draw a line from the end to the start. It is not needed to match beginPath
ctx.fill();
ctx.stroke();
requestAnimationFrame(drawTheBlob);
}
requestAnimationFrame(drawTheBlob); // start this way so that you get the time argument
<canvas width="200" height="200"></canvas>
首先我们需要从圆圈到鼠标的方向。要做到这一点,我们使用函数Math.atan2
它从圆到鼠标的向量,并以弧度返回方向。该函数有点奇怪,因为它首先需要y,然后是x。
var mouseDir = Math.atan2(mouseY - cy, mouseX - cx);
现在我们有了鼠标的方向,我们可以使用arc
绘制没有噪音的圆圈部分。
ctx.arc(cx, cy, radius, mouseDir + quadWidth / 2, mouseDir + Math.PI * 2 - quadWidth / 2);
变量quadWidth
是噪声位的角度大小,因此从mouseDir
我们加上角度宽度的一半,并将弧线绘制到mouseDir
加上360度,占{{1}的一半}}
几乎所有编程语言都使用弧度来定义角度,360度等于2 * PI或2 * 3.1415,这可能很难让你理解,但是有充分的理由使用弧度。现在请记住,弧度的整圆是quadWidth
,2 * Math.PI = 360deg
,Math.PI = 180deg
,Math.PI / 2 = 90deg
和Math.PI / 4 = 45Deg
。你不必记住Math.PI / 180 = 1deg
只是半圈的数字。
Math.PI
是一个定义为quadWidth
的常量,为90deg。
for循环仅在const quadWidth = Math.PI / 2;
周围绘制(Math.PI / 2)90deg部分,从45度左侧到45度右侧。或者你设置的任何内容mouseDir
。
quadWidth
我从0到1循环给出合理平滑曲线的步数。我们可以通过乘以值for (var a = 0; a < 1; a += 1 / steps) {
并将其添加到a *
quadWidth
来找到我们绘制的嘈杂弧的哪个部分。这意味着我们从mouseDir - quadWidth / 2
开始,然后将时钟移至mouseDir - 45deg
mouseDir + 45deg
接下来我发现var angle = (mouseDir - quadWidth / 2) + a * quadWidth;
离angle
有多远(可以在这里稍微优化一下,但如果你想在另一部分吸取更多噪音,这种方式会更灵活一点())
mouseDir
如果该数字小于var angDist = Math.abs(angle - mouseDir);
,则将该值转换为0到1的范围,其中0表示距离鼠标方向最远的角度和最近的1。
quadWidth / 2
现在我们计算当前角度的圆的半径并为其添加正弦波。首先是if (angDist < quadWidth / 2) {
amp = 1 - angDist / (quadWidth / 2);
} else {
amp = 0;
}
然后是sin波乘以最后一步计算的radius
。在amp
为零的情况下,不添加任何正弦波,其中amp
为1(在鼠标方向上),将添加完整的正弦波。
amp
值var dist = radius + Math.sin(wavePos + noiseWaveFreq * angle) * noiseAmpMax * amp
,wavePos
和noiseWaveFreq
控制着正弦波的动画。使用这些值来了解它们的作用,noiseAmpMax
是根据函数开始时的时间计算的。
使用wavePos
,我们可以计算圆的下一行的x,y位置
dist
我添加了一些常量
var x = cx + dist * Math.cos(angle);
var y = cy + dist * Math.sin(angle);
ctx.lineTo(x, y);
要了解他们的实验,并更改数字,看看会发生什么。