91

canvas动画3:交互 - dkplus

 6 years ago
source link: http://www.cnblogs.com/dkplus/p/7887482.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

canvas动画3

时隔很久,本人终于又写博客了(重度拖延症),把之前留下的canvas交互动画讲一讲。

电脑上的交互,指的是鼠标和键盘,我们今天主要用的是鼠标。

既然是鼠标的话,就要获取鼠标的各种事件,这次以mousemove做示例。

我们先定义一个鼠标对象,然后添加mousemove事件:

var mouse = {
    x: undefined,
    y: undefined
}
//这样的话控制台就会跟随我们的鼠标移动输出相应的坐标
window.addEventListener("mousemove",function (event) {
    mouse.x = event.x;
    mouse.y = event.y;
    console.log(mouse);
});

我们声明一个初始化函数init(),用于把制造圆的过程封装:

function init() {
    circleArray = []
    for (var i = 0; i < 800; i++) {
        var x = Math.random()*window.innerWidth;
        var y = Math.random()*window.innerHeight;
        var dx = (Math.random()-0.5)*2;
        var dy = (Math.random()-0.5)*2;
        var radius = Math.random()*3 +1;
        circleArray.push(new Circle(x, y, dx, dy, radius));
    }
}
init();

这样的话,按照上一篇文章的做法,我们的canvas会出现一些问题。所以,需要给Circle对象update()里的属性都加上this

function Circle(x, y, dx, dy, radius) {
    this.x = x;
    this.y = y;
    this.dx = dx;
    this.dy = dy;
    this.radius = radius;

    this.draw = function() {
        ctx.beginPath();
        ctx.strokeStyle = "#000";
        ctx.arc(this.x,this.y,this.radius,Math.PI/180*0,Math.PI/180*360,false);
        ctx.stroke();
        ctx.fill();
    }
    this.update = function() {
        //圆触碰边界时反弹,偏移值为负
        if (this.x + this.radius > innerWidth || this.x - this.radius < 0 ) {
            this.dx = -this.dx;
        }
        if (this.y + this.radius > innerHeight || this.y - this.radius < 0 ) {
            this.dy = -this.dy;
        }
        //刷新绘制时圆的偏移运动
        this.x += this.dx;
        this.y += this.dy;
        //根据更新的值进行绘制
        this.draw();

    }
}

接下来我们就要用mousemove于动画进行交互了,我们假定圆心在鼠标坐标周围50px以内的时候圆会增大,这段代码应该写在update()里:

if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
    // if (this.radius < maxRadius) {
        this.radius += 1;
    // }
}

我们设置了10个圆,把鼠标移上去的时候会看到在控制范围内的圆会不断变大,不会停下来,所以我在前面就设置了一个圆半径的最大值,以免它一直增大,然后把注释的内容去掉,圆就不会无限增大了:

但是有一个问题,圆放大了以后不会缩小,那么我们就让它在离开圆50px半径范围后缩小:

if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
    if (this.radius < maxRadius) {
        this.radius += 1;
    }
//其他的所有圆半径不断减小
}else{
    this.radius -= 1;
}

这时候又有新问题产生了,画面一片空白,因为圆心不在鼠标固定范围内的圆全都变小了,甚至半径为负!显然简单的else是不成立的,还是得加个条件:

if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
    if (this.radius < maxRadius) {
        this.radius += 1;
    }
//其他的所有圆半径减小到最小值
}else if (this.radius > this.minRadius) {
    this.radius -= 1;
}

这里出现了一个新值:minRadius,我加在了Circle对象里this.minRadius = radius;,以原本的初始值作为它的最小值。好了,现在基本效果已经成型了:

接下来就是颜色的问题了,只要懂得canvas的基本api,修改颜色完全就是小儿科。我们设置一个数组,用于存放颜色值。

var colorArray = [
    '#58D68D',
    '#E67F22',
    '#3598DB',
    '#E84C3D',
    '#9A59B5',
    '#27AE61',
    '#D25400',
    '#BEC3C7',
    '#297FB8'
]

然后在Circle对象里加上一个bg属性:this.bg = colorArray[Math.floor(Math.random()*colorArray.length)];,再往Circle的绘制函数添上一句ctx.fillStyle = this.bg;,然后ctx.fill();,多彩运动的圆圈canvas就做完了。

这是一个运用mousemove事件做的canvas交互动画,有兴趣的可以尝试其他事件(制作游戏用的键盘事件以及其他鼠标事件),或者思考如何给球加重力,如何检测碰撞事件,canvas的世界并不只有这么一点,相关资料的话,给大家推荐本书《canvas开发详解》。

本文的最终js代码如下:

/**
 * 
 * @authors dkplus ([email protected])
 * @date    2017-10-01 20:37:26
 * @version $1.0$
 */
/**
 * 获取canvas对象,设置宽度高度自适应
 * @type {[type]}
 */
var canvas = document.querySelector("#canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

var ctx = canvas.getContext("2d");
/**
 * 屏幕鼠标坐标
 * @type {Object}
 */
var mouse = {
    x: undefined,
    y: undefined
}
/**
 * @param  {鼠标移动事件,回调函数,赋值给鼠标坐标}
 * @return {[type]}
 */
window.addEventListener("mousemove",function (event) {
    mouse.x = event.x;
    mouse.y = event.y;
    // console.log(mouse);
});
/**
 * @param  {重新设置窗口大小,使canvas宽高自适应屏幕}
 * @return {[type]}
 */
window.addEventListener("resize",function () {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    //初始化canvas
    init();
})
//绘制圆的最大半径
var maxRadius = 40;
// var minRadius = 2;

//圆的颜色数组
var colorArray = [
    '#58D68D',
    '#E67F22',
    '#3598DB',
    '#E84C3D',
    '#9A59B5',
    '#27AE61',
    '#D25400',
    '#BEC3C7',
    '#297FB8'
]
/**
 * @param {x圆中心的x坐标}
 * @param {y圆中心的y坐标}
 * @param {dx圆运动的x偏移量}
 * @param {dy圆运动的y偏移量}
 * @param {radius圆的半径}
 * minRadius圆的最小半径
 * bg圆的背景颜色
 * draw绘制函数
 * update圆运动偏移
 */
function Circle(x, y, dx, dy, radius) {
    this.x = x;
    this.y = y;
    this.dx = dx;
    this.dy = dy;
    this.radius = radius;
    this.minRadius = radius;
    this.bg = colorArray[Math.floor(Math.random()*colorArray.length)];

    this.draw = function() {
        ctx.beginPath();
        ctx.strokeStyle = "#777";
        ctx.fillStyle = this.bg;
        ctx.arc(this.x,this.y,this.radius,Math.PI/180*0,Math.PI/180*360,false);
        // ctx.stroke();
        ctx.fill();
    }
    this.update = function() {
        //圆触碰边界时反弹,偏移值为负
        if (this.x + this.radius > innerWidth || this.x - this.radius < 0 ) {
            this.dx = -this.dx;
        }
        if (this.y + this.radius > innerHeight || this.y - this.radius < 0 ) {
            this.dy = -this.dy;
        }
        //刷新绘制时圆的偏移运动
        this.x += this.dx;
        this.y += this.dy;
        //鼠标半径50像素范围内的圆,它们的半径逐步增加到最大值
        if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
            if (this.radius < maxRadius) {
                this.radius += 1;
            }
        //其他的所有圆半径减小到最小值
        }else if (this.radius > this.minRadius) {
            this.radius -= 1;
        }
        //根据更新的值进行绘制
        this.draw();

    }
}
//圆的对象数组
var circleArray = [];
/**
 * 初始化函数,制造800个随机坐标、偏移速度和半径的圆,加入到对象数组
 * @return {[type]}
 */
function init() {
    circleArray = []
    for (var i = 0; i < 800; i++) {
        var x = Math.random()*window.innerWidth;
        var y = Math.random()*window.innerHeight;
        var dx = (Math.random()-0.5)*2;
        var dy = (Math.random()-0.5)*2;
        var radius = Math.random()*3 +1;
        circleArray.push(new Circle(x, y, dx, dy, radius));
    }
}
init();
/**
 * 动画函数
 * @return {[type]}
 */
function animate() {
    //更新前清楚画布
    ctx.clearRect(0,0,window.innerWidth,window.innerHeight);
    requestAnimationFrame(animate);
    //每个圆都调用update()方法
    for (var i = 0; i < circleArray.length; i++) {
        circleArray[i].update();
    }

}
animate();

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK