One canvas animation code file per week

In previous chapters I have introduced some animation effects, which are relatively basic. But with these basic animation forms and concepts, you can design more complex animations. This chapter will introduce collision detection, a relatively difficult physics concept in animation. I’m not saying it’s difficult to understand, but the process of implementing it, and the way it’s implemented, will test your imagination. Without further ado, the main contents of this chapter are:

  1. Collision detection methods

  2. Geometry collision detection method

  3. Collision detection based on distance

1. Collision detection method

I remember that we introduced the method of boundary detection in the previous chapter “One Point a Week Canvas Animation” – Boundary detection and Friction. If you forget it, you can take a look. The collision detection that we are going to introduce today is between objects, that is to say, in addition to the collision between objects and boundaries, we also need to realize the collision between objects in our animation.

Going back to the animation form we talked about, boundary detection is a collision between objects and boundaries, and user interaction can also be said to be a collision between mouse and object. The collision detection techniques used in these two animations are similar to the collision between objects.

Method 1: determine whether there is overlap between objects. Here, the outer rectangular boundary of objects is used to determine method 2: determine the distance between objects. When the distance is less than a certain value, the collision condition is met and the object produces collision effect

These are the two methods we use commonly, and I’ll supplement them later on with more advanced ones.

2. Geometry collision detection method

Looking at the code source, we added a method getBounds on the Ball. Js class in the previous section. If you forget, open it up and see what its return value is.

Ball.prototype.getBounds = function(){
    return {
        x: this.x - this.radius,
        y: this.y - this.radius,
        width: this.radius*2,
        height: this.radius*2
    };
}Copy the code

Now if you’re given two objects, there’s a getBounds method on each object. But you still can’t tell if two objects are touching. Here we need to define a new method in the utils.js utility function file:

utils.intersects = function(rectA, rectB){ return ! (rectA.x + rectA.width < rectB.x || rectB.x + rectB.width < rectA.x || rectA.y + rectA.height < rectB.y || rectB.y + rectB.height < rectA.y); }Copy the code

Remember we added a method earlier called utils.containspoint, which we use to determine if the mouse is clicked on an object. Similarly, the above method returns a Boolean to determine whether two objects overlap.

In our method we pass in two objects rectA and rectB, comparing the diagram carefully to understand the implementation of the code. Return true when encountered, i.e. our two objects overlap, and we can handle this in our code:

If (utils. Intersects (rectA, rectB)){//dosomething}Copy the code

However, things in the world are always like this, simple and easy often do not get the best result, to get the best result, then things will naturally increase a lot of complexity. Take a look at the pictures below:

As a result, the above method is simple but far from accurate. But it depends on your choice, if the requirements are not high, within the acceptable range, you can also choose to use this method to do collision detection.

With all this theoretical stuff, let’s see if it works. Look at the renderings first

Here we create a new class called Box.js, which is essentially a rectangular file, not much different from the ball-.js file, except that one is a sphere and the other is a square. If you’re using squares, you can skip the getBound method. Instead of listing the box code, I’ll look at the effect code:

your browser not support canvas! // Import the box fileCopy the code

The principle of the code is very simple, the box here has two states, the activeBox is falling and the box has fallen to the bottom. When the first box appears in our canvas, both activeBox and Box are there, and no collision detection is performed in the drawBox. When the first one falls to the bottom, a second box is created, and the activeBox becomes the second box. As it falls, it checks for collisions with the existing rectangles in the array boxes, and so on.

3. Collision detection based on distance

In this part, we abandon the collision detection method of enclosing rectangular geometry mentioned in the previous section. A new method — range-based collision detection is adopted. The best example of distance-based collision detection is the sphere. How do you calculate the distance between two spheres

var dx = ballB.x - ballA.x,
    dy = ballB.y - ballA.y,
    dist = Math.aqrt(dx * dx + dy * dy);Copy the code

Now that we have the distance, we can use it to tell if two spheres have collided.

So if the distance between the two spheres is less than the radius, then you have a collision. Hurry up to the code!

Here we have the effect of colliding two spheres in a horizontal direction. The code is so simple that I won’t list it here.

3.1 Collision detection with elastic effect

Finally, here is a collision detection of multiple objects with elastic effect. We introduced elastic animation in the last section, and here we will make a small use of it to pave the way for the collision of multiple objects in the next section. The idea of the whole animation is: a static sphere centerBall is placed in the middle of the canvas, and then 10 balls are drawn. The balls move freely in the canvas and collide with centerBall. However, after the collision, the motion state of the balls is an elastic animation effect.

The specific code is as follows

window.onload = function(){ var canvas = document.getElementById('canvas'), context = canvas.getContext('2d'), CenterBall = new Ball(60, "#00d49e"), balls = [], numBalls = 10, spring = 0.03, bounce = -1; centerBall.x = canvas.width/2; centerBall.y = canvas.height/2; for(var i=0; i canvas.width){ ball.x = canvas.width - ball.radius; ball.vx *= bounce; } if(ball.x - ball.radius < 0){ ball.x = ball.radius; ball.vx *= bounce; } if(ball.y + ball.radius > canvas.height){ ball.y = canvas.height - ball.radius; ball.vy *= bounce; } if(ball.y - ball.radius < 0){ ball.y = ball.radius; ball.vy *= bounce; }} function draw(ball){var dx = ball. var dy = ball.y - centerBall.y; var dist = Math.sqrt(dx*dx+dy*dy); var min_dist = centerBall.radius + ball.radius; if(dist < min_dist){ var angle = Math.atan2(dy, dx); var targetX = centerBall.x + Math.cos(angle)*min_dist, targetY = centerBall.y + Math.sin(angle)*min_dist; ball.vx += (targetX - ball.x)*spring; ball.vy += (targetY - ball.y)*spring; } ball.draw(context); } (function drawFrame(){ window.requestAnimationFrame(drawFrame, canvas); context.clearRect(0, 0, canvas.width, canvas.height); balls.forEach(move); balls.forEach(draw); centerBall.draw(context); } ()); }Copy the code

Although the code looks a bit long, it’s basically what we’ve covered before. The only new thing is that in the collision detection section, we used the effect of elastic animation to deal with the velocity of the sphere after the collision, but this was also covered in the elastic animation section. I won’t explain too much here, but notice in the dynamic diagram that when the ball hits the centerBall, it doesn’t come back immediately, but some of it goes into the centerBall, because the elastic animation changes the acceleration, so don’t think that’s wrong.

In the next section, we introduce multi-object collision detection strategies and more advanced collision detection methods! Stay tuned!