资讯专栏INFORMATION COLUMN

一步步打造Canvas小球动画

mrcode / 467人阅读

摘要:我们需要使用到的方法有第一步绘制一个小球画布的宽画布的高定义圆心坐标定义圆心坐标定义半径清除画布开始绘制画圆圆的填充颜色闭合路径填充在线预览第二步让小球动起来让小球动起来的原理就是,不断地改变小球的坐标位置并进行重绘。

我们需要使用到Canvas的方法有:

context.arc(x, y, r, sAngle, eAngle, counterclockwise);
第一步:绘制一个小球
var  canvas = document.getElementById("canvas"),
     ctx = canvas.getContext("2d"),
     w = canvas.width, //canvas画布的宽
     h = canvas.height,// canvas画布的高
     posX = 20,//定义圆心X坐标
     posY = 20,//定义圆心Y坐标 
     radius = 20;//定义半径
ctx.clearRect(0, 0, w, h);//清除画布
ctx.beginPath();//开始绘制
ctx.arc(posX,posY,radius,0,2*Math.PI);//画圆
ctx.fillStyle = "red";//圆的填充颜色
ctx.closePath();//闭合路径
ctx.fill();//填充

在线预览:https://codepen.io/jianxiujiu...

第二步:让小球动起来

让小球动起来的原理就是,不断地改变小球的坐标位置并进行重绘。
重绘可以用setInterval、setTimeout或requestanimationframe。关于它们的区别此处不做详解,具体可以参考我好基友的一篇文章:setTimeout 和 requestAnimationFrame

window.requestAnimFrame = (function(){
    return window.requestAnimationFrame       || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
})();
var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    w = canvas.width,
    h = canvas.height,
    posX = 20, //小球出现的X轴位置
    posY = 20, //小球出现的Y轴位置
    speedX = 3,//小球X轴速度
    speedY = 3,//小球Y轴速度
    radius = 20;//小球半径

    function ani(){
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        posX += speedX;
        posY += speedY;     
        ctx.beginPath();
        ctx.arc(posX,posY,radius,0,2*Math.PI);
        ctx.fillStyle = "red";
        ctx.closePath();
        ctx.fill();   
        if(posY < h - radius){ 
            requestAnimFrame(ani) //如果Y轴位置不超过容器高度则一直移动
        }
    }
    ani();

在线预览:https://codepen.io/jianxiujiu...

第三步:一个小球的碰撞动画

接下来我们让小球动起来,并在画布四周进行碰撞运动。

window.requestAnimFrame = (function(){
    return window.requestAnimationFrame       || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
})();
var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    w = canvas.width,
    h = canvas.height,
    posX = 20,
    posY = 20,
    speedX = 2,//小球X轴速度
    speedY = 2,//小球Y轴速度
    startSpeedX = 2,//小球X轴初始速度
    startSpeedY = 2,//小球Y轴初始速度
    radius = 20;//小球半径

    function ani(){       
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        posX += speedX;
        posY += speedY;
        
        //小球碰壁反弹
        if(posY > h - radius){ 
            speedY*=-1;
        }
        if(posX > w - radius){
            speedX*=-1;  
        }
        if(posY < radius){
            speedY = startSpeedY;
            posY = radius;
        }
        if(posX < radius){
            speedX = startSpeedX;
            posX = radius;
        }
        
        ctx.beginPath();
        ctx.arc(posX,posY,radius,0,2*Math.PI);
        ctx.fillStyle = "red";
        ctx.closePath();
        ctx.fill();
        requestAnimFrame(ani);
    }

    ani();

在线预览:https://codepen.io/jianxiujiu...

第四步:多个小球的碰撞动画
window.requestAnimFrame = (function(){
    return window.requestAnimationFrame       || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
})();
var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    w = canvas.width,
    h = canvas.height,
    posX,
    posY,
    speedX,
    speedY,
    radius;

    function randomNum(m,n) { //随机函数
        return Math.floor(Math.random() * (n - m + 1) + m);
    }

    var balls = [] //建立小球数组
    function getBall(){
        for( n = 0; n < 20;n++){ //小球的数量
            radius = randomNum (10,20), //半径随机10-20px
            posX = randomNum(radius,w-radius), //X轴位置随机
            posY = randomNum(radius,h-radius), //Y轴位置随机
            speedX = randomNum(3,6), //X轴速度随机
            speedY = randomNum(1,2), //Y轴速度随机
            startSpeedX = startSpeedX,//记录X轴起始速度
            startSpeedY = startSpeedY;//记录X轴起始速度
            fillColor = "rgb(" + randomNum(0,255) + "," + randomNum(0,255) + "," + randomNum(0,255) + ")";//小球颜色随机
            var ball = {
                radius : radius,
                posX : posX,
                posY : posY,
                speedX : speedX,
                speedY : speedY,
                startSpeedX : startSpeedX, 
                startSpeedY : startSpeedX,
                fillColor : fillColor
            }
            balls.push(ball) //将生成的小球存到数组里
        }    
    }
    getBall();   
            
    function draw(){     
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        var l = balls.length; 
        for(var i = 0;i h - ballCur.radius){
                ballCur.speedY*=-1;
            }
            if(ballCur.posX > w - ballCur.radius){
                ballCur.speedX*=-1;  
            }
            if(ballCur.posY < ballCur.radius){
                ballCur.speedY = startSpeedY;
                ballCur.posY = ballCur.radius;
            }
            if(ballCur.posX < ballCur.radius){
                ballCur.speedX = startSpeedX;
                ballCur.posX = ballCur.radius;
            }            
                               
            ctx.arc(ballCur.posX,ballCur.posY,ballCur.radius,0,2*Math.PI);        
            ctx.fillStyle = ballCur.fillColor;
            ctx.closePath();
            ctx.fill();
           
        }  
        requestAnimFrame(draw);    
    }        
    draw();

在线预览:https://codepen.io/jianxiujiu...

第五步:小球为自定义图片的动画

小球动起来之后,如果希望小球为图片,则需要用到Canvas另外一个方法:

context.drawImage(image, x, y); //在画布上定位图像:
context.drawImage(image, x, y, width, height);//在画布上定位图像,并规定图像的宽度和高度
context.drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight,destX, destY, destWidth, destHeight);//剪切图像,并在画布上定位被剪切的部分

和绘制普通小球不一样,绘制图片球的时候,我们需要把之前动画的代码在加载完图片之后再执行。并且碰撞的位置也需要进行调整。

window.requestAnimFrame = (function(){
    return window.requestAnimationFrame       || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
})();
var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    w = canvas.width,
    h = canvas.height,
    ballWidth = 60, //图片球宽度
    posX,
    posY,
    speedX,
    speedY;
    var img = new Image();
    img.src = "img/ball.png";
    img.onload = function(){     
        getBall();  
        draw();
    }

    function randomNum(m,n) {
        return Math.floor(Math.random() * (n - m + 1) + m);
    }

    var balls = []
    function getBall(){
        for( n = 0; n < 20;n++){   
            posX = randomNum(ballWidth,w - ballWidth),
            posY = randomNum(ballWidth,h - ballWidth),
            speedX = randomNum(3,7),
            speedY = randomNum(4,8),
            startSpeedX = speedX,
            startSpeedY = speedY;
            ballPicPos = randomNum(0,4)*60; //小球图片位置随机
            var ball = {
                posX : posX,
                posY : posY,
                speedX : speedX,
                speedY : speedY,
                startSpeedX : startSpeedX, 
                startSpeedY : startSpeedX,
                ballPicPos : ballPicPos
            }
            balls.push(ball);                  
        }   
    }
     
            
    function draw(){     
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        var l = balls.length;
        for(var i = 0;i h - ballWidth){
                ballCur.speedY*=-1;
            }
            if(ballCur.posX > w - ballWidth){
                ballCur.speedX*=-1;  
            }
            if(ballCur.posY < 0){
                ballCur.speedY = startSpeedY;
                ballCur.posY = 0;
            }
            if(ballCur.posX < 0){
                ballCur.speedX = startSpeedX;
                ballCur.posX = 0;
            }                            
           
           ctx.beginPath(); 
           ctx.fillStyle = ctx.drawImage(img,0,ballCur.ballPicPos,ballWidth,ballWidth,ballCur.posX,ballCur.posY,ballWidth,ballWidth);
           ctx.fill();
           ctx.closePath();
           ctx.restore();
           
        }  
        requestAnimFrame(draw);  
    }                

线上预览:https://codepen.io/jianxiujiu...

PS:小球的图片位置如果取值大于图片本身的位置,则IE11下显示图片会有BUG。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87324.html

相关文章

  • 步步实现nest粒子特效

    摘要:尝试实现画出一个弹射的小球很简单,那怎么用多个小球实现这样的效果呢。 本文首发于我的博客,这是我的github,欢迎star。   这篇博客是模仿nest.js实现一个demo,由简单到复杂,来一步步的实现它。这里是效果预览。我的github里边还有很多别的前端的demo,喜欢的话可以点个star,你的支持就是我的动力。 从一道面试题开始 实现一个半径10px的小球在500px*5...

    ky0ncheng 评论0 收藏0
  • 《每周canvas动画》——角度反弹

    摘要:每周一点动画代码文件在上一节我们介绍了高级的坐标旋转方法,我们只需要知道物体的位置,通过设定每一帧需要旋转的角速度通过公式就可以计算出做圆周运动时物体的下一个坐标位置。思路有了,我们需要把它转化成平面来做角度反弹。 每周一点canvas动画代码文件 在上一节我们介绍了高级的坐标旋转方法,我们只需要知道物体的位置,通过设定每一帧需要旋转的角速度,通过公式 newX = x*cos - y...

    sf_wangchong 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<