前端开发canvas动画之碰撞测试

前端开发的命名规范
web前端开发规范 实现符合w3c的web标准
公司前端开发规范

本章的主要内容有:

环境边界检测
摩擦力的应用

同样我们在本章的第一部分介绍前一节环境边界检测的主要内容:

边界设置
超出边界移除
超出边界重新形成
边界环绕
边界反弹

1.设置边界

在上一章 速度与加速度(2)中我们在重力加速度那一部分时其实就用到了边界检测的内容,在本章中我们将系统的讲述关于边界检测方面的内容!在大多数的情况下,一个简单的矩形就是一个物体运动的环境边界。比如我们的canvas画布,我们做的所有动画都是在canvas中运行的,那么canvas画布就是我们动画的运行环境。那么,如何设置canvas的边界呢?答案很简单:

javascript 代码

var left = 0,
    top = 0,
    right = canvas.width,
    bottom = canvas.height

这里我们假设你使用整个canvas画布。当然,如果你只是用一部分也可以设定:top = 120, bottom = 300, left = 50, right = 300 这些数值的大小都随你设置,只要最终的效果是一个矩形的环境就是ok的(这里我们先讲最简单的矩形环境).

设置完边界我们就可以开始做些事情了,假设我们的canvas里有个小球:

javascript 代码

if (ball.x > right) {
    // do something
} else if (ball.x < left) {
    //do something
}
if (ball.y > bottom) {
    //do something
} else if (ball.y < top) {
    //do something
}

我们通过判断小球的位置是否超出canvas的边界来做一些事情,那能做哪些事情呢?

2.超出边界移除

我们第一个要做的效果是超出边界移除,用到的是ball.js文件;

javascript 代码

<canvas id=”canvas” width=”400″ height=”400″ style=”background:#000;”>
    your browser not support canvas
</canvas>
<p id=”log”></p>
<script src=”../js/utils.js”></script>
<script src=”../js/ball.js”></script>
<script>
    window.onload = function() {
        var canvas = document.getElementById(‘canvas’),
            context = canvas.getContext(‘2d’),
            log = document.getElementById(‘log’)
        var balls = [],
            numBall = 10,
            canWid = canvas.width,
            canHei = canvas.height
        //定义10个小球
        for (var i = 0; i < numBall; i++) {
            var size = Math.random() * 20 + 5, //颜色
                color = Math.random() * 0xffffff, //大小
                ball = new Ball(size, color)
            ball.id = ‘ball_’ + i //给每个小球一个id
            ball.radius = Math.random() * 30 + 10
            ball.x = Math.random() * canWid
            ball.y = Math.random() * canHei
            ball.vx = Math.random() * 2 – 1
            ball.vy = Math.random() * 2 – 1
            balls.push(ball) //push进数组
        }
        //定义draw函数
        function draw(ball, pos) {
            //让小球加上它的速度值
            ball.x += ball.vx
            ball.y += ball.vy
            //判断是否超出边界,不论超出哪一边
            if (
                ball.x – ball.radius > canvas.width ||
                ball.radius + ball.x < 0 ||
                ball.y – ball.radius > canvas.height ||
                ball.y + ball.radius < 0
            ) {
                //将超出边界的小球从数组中删除
                balls.splice(pos, 1)
                if (balls.length > 0) {
                    //将超出的小球的id值输出
                    log.innerHTML += ‘移除’ + ball.id + ‘<br/>’
                } else {
                    log.innerHTML = ‘全部移除’
                }
            }
            ball.draw(context)
        }
        //动画循环
        ;(function drawFrame() {
            window.requestAnimationFrame(drawFrame, canvas)
            context.clearRect(0, 0, canvas.width, canvas.height)
            //定义初始变量 i 为小球的数量, 并且会随着小球的移除减小
            var i = balls.length
            while (i–) {
                draw(balls[i], i)
            }
        })()
    }
</script>

我们定义了十个小球,并把它们push进一个数组balls中,每当有小球超出边界(即完全消失在canvas中),就从balls中删除小球,并且打印出小球的id值。以横坐标为例,这里我们并没有使用ball.x > canvas.width,而是使用ball.x – ball.radius > canvas.width,这里做一点小的解释。因为 ball.x 是小球的球心,所以要让小球完全移除必须是小球的最左边(或最右边)完全超出canvas的边界,这才叫完全移除。

图示以canvas左侧边界为例,小球最右边的坐标为 ball.x + ball.raidus。所以,只要它超过了canvas的左侧边界,小球就被判定为完全移除。

3.超出边界重新形成

这个效果的思想比较简单:当小球超出了边界,重置他的位置就ok了。

这部分代码与上一部分代码区别不是很大,这里我只列出改变的部分:

javascript 代码

function draw(ball, pos) {
    // …
    if (边界超出判定) {
        //超出了重置速度与坐标
        ball.x = canvas.width / 2
        ball.y = canvas.height
        ball.vx = Math.random() * 2 – 1
        ball.vy = Math.random() * -2 – 1
    }
    // …
}
;(function drawFrame() {
    window.requestAnimationFrame(drawFrame, canvas)
    context.clearRect(0, 0, canvas.width, canvas.height)
    balls.forEach(draw)
})()

当小球超出了边界,我们就重置它的坐标与速度。注意,这里在重置速度代码中,我们将小球的竖直方向的速度(ball.vy)设置为负值,就达到了小球从下到上喷涌的效果。

3.边界环绕

边界环绕其实是上一部分的一个子类型。它想要实现的效果是:当物体从一个边界消失,会从对立的边界出现。简单来说,就是如果物体从左边界消失,就会从右边界出现。

如图所示,我们将canvas画布左右边界对接。当物体从左边界消失,立即又从右边界出现,形成一种环绕效果。其实,没有想象中的那么神秘,我们也不会真的把canvas画布的左右边界对接。

javascript 代码

<canvas id=”canvas” width=”500″ height=”500″ style=”background:#000;”>
    your browser not support canvas!
</canvas>
<script src=”../js/utils.js”></script>
<script src=”../js/spaceship.js”></script>
<script>
    window.onload = function() {
        var canvas = document.getElementById(‘canvas’),
            context = canvas.getContext(‘2d’)
        var ship = new SpaceShip()
        ship.x = canvas.width / 2
        ship.y = canvas.height / 2
        var vr = 0,
            vx = 0,
            vy = 0,
            ax = 0,
            ay = 0,
            angle = 0,
            thrust = 0
        window.addEventListener(
            ‘keydown’,
            function(event) {
                switch (event.keyCode) {
                    case 37:
                        vr = -3
                        break
                    case 39:
                        vr = 3
                        break
                    case 38:
                        ship.showFlame = true
                        thrust = 0.05
                        break
                    case 40:
                        thrust -= 0.02
                        break
                }
            },
            false,
        )
        window.addEventListener(
            ‘keyup’,
            function(event) {
                vr = 0
                thrust = 0
                ship.showFlame = false
            },
            false,
        )
        ;(function drawFrame() {
            window.requestAnimationFrame(drawFrame, canvas)
            context.clearRect(0, 0, canvas.width, canvas.height)
            angle += (vr * Math.PI) / 180
            ship.rotation = angle
            ax = Math.cos(angle) * thrust
            ay = Math.sin(angle) * thrust
            vx += ax
            vy += ay
            ship.x += vx
            ship.y += vy
            //核心部分
            if (ship.x – ship.width / 2 > canvas.width) {
                ship.x = 0
            }
            if (ship.x < 0) {
                ship.x = canvas.width
            }
            if (ship.y – ship.height / 2 > canvas.height) {
                ship.y = 0
            }
            if (ship.y < 0) {
                ship.y = canvas.height
            }
            ship.draw(context)
        })()
    }
</script>

4.边界反弹

ok!本章的重头戏来了,标题的意思已经很明白了,我们要让物体触碰到边界的时候反弹回来。就像真实的世界中一样,球体撞到墙上反弹回来。有了前面的铺垫,要实现这个效果那还不是分分钟的事情!一样的套路,

javascript 代码

<canvasid=”canvas”width=”400″height=”300″style=”background:#000;”>
your browser not support canvas!
</canvas>
<script src=”../js/utils.js”></script>
<script src=”../js/ball.js”></script>
<script>
window.onload=function(){
var canvas =document.getElementById(“canvas”),
context = canvas.getContext(“2d”);
var vx =Math.random()*10-5;
var vy =Math.random()*10-5;
var ball =newBall(20,”#ff0000″);
ball.x = canvas.width/2;
ball.y = canvas.height/2;
//动画循环
(functiondrawFrame(){
window.requestAnimationFrame(drawFrame, canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
ball.x += vx;
ball.y += vy;
//核心部分
if(ball.x+ ball.radius > canvas.width){
ball.x = canvas.width – ball.radius;
vx *= -1;
}elseif(ball.x- ball.radius <0){
ball.x = ball.radius;
vx *= -1;
}
if(ball.y+ ball.radius > canvas.height){
ball.y = canvas.height – ball.radius;
vy *= -1;
}elseif(ball.y- ball.radius <0){
ball.y = ball.radius;
vy *= -1;
}
ball.draw(context);
}())
}

代码很简洁,你只需要关注核心部分。这里同样我们判断小球是否超出边界,但不同的是,我们这次判断的是小球的最右边的位置,即坐标为ball.x + ball.radius的位置,当这个位置大于canvas的宽度的时候,在if执行语句中我们让小球的位置等于 canvas.width – ball.radius 即刚好球体的最右边的位置靠在canvas画布的右边界上,并且最重要的是:我们让速度乘以 -1 ,相当于将速度方向旋转180度。

更好的写法,我们定义一个变量bounce,它的值除了-1你还可以取-0.5, -1.5….,不同之处在于,小球的速度会衰减或增强。如果你想要模仿现实中小球在经过几次反弹后速度逐渐减小最后停止,那么你可以将bounce的值设为[-1, 0)之间的值试一试。

javascript 代码

var bounce = -1
if (ball.x + ball.radius > canvas.width) {
    ball.x = canvas.width – ball.radius
    vx *= bounce
} else if (ball.x – ball.radius < 0) {
    ball.x = ball.radius
    vx *= bounce
}
if (ball.y + ball.radius > canvas.height) {
    ball.y = canvas.height – ball.radius
    vy *= bounce
} else if (ball.y – ball.radius < 0) {
    ball.y = ball.radius
    vy *= bounce
}
web前端开发命名规范
前端开发规范 意义
前端开发文件名称规范
赞(0)
前端开发者 » 前端开发canvas动画之碰撞测试
64K

评论 抢沙发

评论前必须登录!