关于您的问题的评论:
您在每帧中将fillStyle的颜色更改为随机颜色。这就是它一直“改变”颜色的原因。将其设置为圆的颜色:
context.fillStyle = circle.color
- 使用数组制作具有x、y、直径、弹性、速度和颜色的圆
- 使用requestAnimationFrame绘制并更新它们(我的是自定义函数)
我的回答:
昨晚我刚刚做了这个,其中一些圆会跟随光标,并“弹”出屏幕边缘。我测试了代码,它可以工作。
我可能稍后会发布链接,但现在这是全部代码...
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas"></canvas>
<script>
var lastTime = 0;
function requestMyAnimationFrame(callback, time)
{
var t = time || 16;
var currTime = new Date().getTime();
var timeToCall = Math.max(0, t - (currTime - lastTime));
var id = window.setTimeout(function(){ callback(currTime + timeToCall); }, timeToCall);
lastTime = currTime + timeToCall;
return id;
}
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = window.innerWidth - 20;
canvas.height = window.innerHeight - 20;
canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
var circles = [];
var mouse =
{
x: 0,
y: 0
}
function getCoordinates(x, y)
{
return "(" + x + ", " + y + ")";
}
function getRatio(n, d)
{
if (d === 0 || n === 0)
{
return 0;
}
else
{
return n/d;
}
}
function Circle(x,y,d,b,s,c)
{
this.x = x;
this.y = y;
this.diameter = Math.round(d);
this.radius = Math.round(d/2);
this.bounciness = b;
this.speed = s;
this.color = c;
this.deltaX = 0;
this.deltaY = 0;
this.drawnPosition = "";
this.fill = function()
{
context.beginPath();
context.arc(this.x+this.radius,this.y+this.radius,this.radius,0,Math.PI*2,false);
context.closePath();
context.fill();
}
this.clear = function()
{
context.fillStyle = "#ffffff";
this.fill();
}
this.draw = function()
{
if (this.drawnPosition !== getCoordinates(this.x, this.y))
{
context.fillStyle = this.color;
this.fill();
}
}
this.keepInBounds = function()
{
if (this.x < 0)
{
this.x = 0;
this.deltaX *= -1 * this.bounciness;
}
else if (this.x + this.diameter > canvas.width)
{
this.x = canvas.width - this.diameter;
this.deltaX *= -1 * this.bounciness;
}
if (this.y < 0)
{
this.y = 0;
this.deltaY *= -1 * this.bounciness;
}
else if (this.y+this.diameter > canvas.height)
{
this.y = canvas.height - this.diameter;
this.deltaY *= -1 * this.bounciness;
}
}
this.followMouse = function()
{
var centerX = Math.round(this.x + this.radius);
var centerY = Math.round(this.y + this.radius);
if (centerX < mouse.x)
{
this.deltaX += this.speed;
}
else if (centerX > mouse.x)
{
this.deltaX -= this.speed;
}
else
{
}
if (centerY < mouse.y)
{
this.deltaY += this.speed;
}
else if (centerY > mouse.y)
{
this.deltaY -= this.speed;
}
else
{
}
this.x += this.deltaX;
this.y += this.deltaY;
this.x = Math.round(this.x);
this.y = Math.round(this.y);
}
}
function getRandomDecimal(min, max)
{
return Math.random() * (max-min) + min;
}
function getRoundedNum(min, max)
{
return Math.round(getRandomDecimal(min, max));
}
function getRandomColor()
{
var colors = [];
for (var i = 0; i < 3; i++)
{
colors[i] = getRoundedNum(0, 255);
}
return "rgb(" + colors[0] + "," + colors[1] + ", " + colors[2] + ")";
}
function createCircle(i)
{
var minDiameter = 25;
var maxDiameter = 50;
var minBounciness = 0.2;
var maxBounciness = 0.65;
var minSpeed = 0.3;
var maxSpeed = 0.45;
var x = getRoundedNum(0, canvas.width);
var y = getRoundedNum(0, canvas.height);
var d = getRoundedNum(minDiameter, maxDiameter);
var c = getRandomColor();
var b = getRandomDecimal(minBounciness, maxBounciness);
var s = getRandomDecimal(minSpeed, maxSpeed);
circles[i] = new Circle(x,y,d,b,s,c);
}
function makeCircles()
{
var maxCircles = getRoundedNum(2, 5);
for (var i = 0; i < maxCircles; i++)
{
createCircle(i);
}
}
function drawCircles()
{
var ii = 0;
for (var i = 0; ii < circles.length; i++)
{
if (circles[i])
{
circles[i].draw();
ii++;
}
}
}
function clearCircles()
{
var ii = 0;
for (var i = 0; ii < circles.length; i++)
{
if (circles[i])
{
circles[i].clear();
ii++;
}
}
}
function updateCircles()
{
var ii = 0;
for (var i = 0; ii < circles.length; i++)
{
if (circles[i])
{
circles[i].keepInBounds();
circles[i].followMouse();
ii++;
}
}
}
function update()
{
requestMyAnimationFrame(update,10);
updateCircles();
}
function draw()
{
requestMyAnimationFrame(draw,1000/60);
context.clearRect(0,0,canvas.width,canvas.height);
drawCircles();
}
function handleError(e)
{
}
window.addEventListener("load", function()
{
window.addEventListener("error", function(e)
{
handleError(e);
});
window.addEventListener("resize", function()
{
canvas.width = window.innerWidth - 20;
canvas.height = window.innerHeight - 20;
});
window.addEventListener("mousemove", function(e)
{
mouse.x = e.layerX || e.offsetX;
mouse.y = e.layerY || e.offsetY;
});
makeCircles();
update();
draw();
});
</script>
</body>
</html>
radius、x、y、color
等属性,代表着你的圆圈。然后你通过循环遍历该数组,获取这些值来绘制圆圈,并更新它们以使圆圈移动。最后,如果想向画布添加一个新的圆圈,你只需将一个新对象推入你的circleArray中即可。 - Laurominewindow.setTimeout
进行递归调用可以避免绘制时间超过间隔的级联失败。此外,您似乎没有调用closePath
。 - Paul S.requestAnimationFrame
让你在重新绘制之间执行操作,setTimeout
则让你等待一定的时间。如果你想等待然后再进行动画,则可以同时使用两者。如果你只是想等待,那就用setTimeout
。如果你只是想进行动画,那就用requestAnimationFrame
。 - Paul S.