在画布上随机绘制彩色圆形

3
我正在尝试创建一个动画,在动画中圆圈从右往左运动。圆圈的颜色是由一个函数随机选择的。我已经创建了一个fiddle,其中有一个圆圈从右往左运动。现在我的函数创建了一个随机颜色。该函数每秒执行一次,圆圈每秒钟改变一次颜色,而不是创建一个新圆圈并随机选择颜色。如何更改代码,每秒钟在画布上画一个新的圆圈,并且不仅仅改变圆圈的颜色?
这是我的函数:
function getRandomElement(array) {
  if (array.length == 0) {
    return undefined;
  }
  return array[Math.floor(Math.random() * array.length)];
}

var circles = [
  '#FFFF00',
  '#FF0000',  
  '#0000FF'
];


function drawcircles() {


ctx.beginPath();
      ctx.arc(ballx * 108, canvasHeight / 2, x*5, 0, 2*Math.PI, false);
      ctx.fillStyle = getRandomElement(circles);
      ctx.fill();
ctx.closePath;

}

不要忘记,你需要重新绘制每一帧的内容。你可以使用一个包含对象的数组,这些对象具有radius、x、y、color等属性,代表着你的圆圈。然后你通过循环遍历该数组,获取这些值来绘制圆圈,并更新它们以使圆圈移动。最后,如果想向画布添加一个新的圆圈,你只需将一个新对象推入你的circleArray中即可。 - Lauromine
使用 window.setTimeout 进行递归调用可以避免绘制时间超过间隔的级联失败。此外,您似乎没有调用 closePath - Paul S.
@PaulS。使用它比使用requestAnimationFrame更好吗?我很好奇。 - Lauromine
@Lauromine 它们有不同的用例,requestAnimationFrame 让你在重新绘制之间执行操作,setTimeout 则让你等待一定的时间。如果你想等待然后再进行动画,则可以同时使用两者。如果你只是想等待,那就用 setTimeout。如果你只是想进行动画,那就用 requestAnimationFrame - Paul S.
1
谢谢你的提示。是的,我认为我需要使用requestAnimationFrame。我已经看了一些关于它的教程,但是我找不到一个合适的。你知道有哪些吗? - Bodoppels
1个回答

1

关于您的问题的评论:

您在每帧中将fillStyle的颜色更改为随机颜色。这就是它一直“改变”颜色的原因。将其设置为圆的颜色:

context.fillStyle = circle.color;
  1. 使用数组制作具有x、y、直径、弹性、速度和颜色的圆
  2. 使用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)
        {
            // prevent division by 0
            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;
                    // if commented, the circle will be drawn if it is in the same position
                    //this.drawnPosition = getCoordinates(this.x, this.y);
                    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()
            {
                // deltaX/deltaY will currently cause the circles to "orbit" around the cursor forever unless it hits a wall
                var centerX = Math.round(this.x + this.radius);
                var centerY = Math.round(this.y + this.radius);
                if (centerX < mouse.x)
                {
                    // circle is to the left of the mouse, so move the circle to the right
                    this.deltaX += this.speed;
                }
                else if (centerX > mouse.x)
                {
                    // circle is to the right of the mouse, so move the circle to the left
                    this.deltaX -= this.speed;
                }
                else
                {
                    //this.deltaX = 0;
                }
                if (centerY < mouse.y)
                {
                    // circle is above the mouse, so move the circle downwards
                    this.deltaY += this.speed;
                }
                else if (centerY > mouse.y)
                {
                    // circle is under the mouse, so move the circle upwards
                    this.deltaY -= this.speed;
                }
                else
                {
                    //this.deltaY = 0;
                }
                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()
        {
            // array of three colors
            var colors = [];
            // go through loop and add three integers between 0 and 255 (min and max color values)
            for (var i = 0; i < 3; i++)
            {
                colors[i] = getRoundedNum(0, 255);
            }
            // return rgb value (RED, GREEN, BLUE)
            return "rgb(" + colors[0] + "," + colors[1] + ", " + colors[2] + ")";
        }
        function createCircle(i)
        {
            // diameter of circle
            var minDiameter = 25;
            var maxDiameter = 50;
            // bounciness of circle (changes speed if it hits a wall)
            var minBounciness = 0.2;
            var maxBounciness = 0.65;
            // speed of circle (how fast it moves)
            var minSpeed = 0.3;
            var maxSpeed = 0.45;
            // getRoundedNum returns a random integer and getRandomDecimal returns a random decimal
            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);
            // create the circle with x, y, diameter, bounciness, speed, and color
            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)
        {
            //e.preventDefault();
            //console.error("    ERROR    ------    " + e.message + "    ------    ERROR    ");
        }
        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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接