I have been learning canvas for more than a week and I think canvas is really fun. People who learn Canvas probably have similar ideas to me. They learn Canvas with the attitude of writing games. So kinematics, collision detection, and some simple algorithms are the basis. Having never made a game before, it was really difficult for me to learn. Today, let’s talk about using canvas to write the simplest bouncy ball game, using the simplest gravity and collision detection.
Let’s go to the DEMO first: Bouncy ball DEMO (Clicking on a blank area in the canvas will give the ball a new speed)
【Create ball object】
The first step is to create a ball object and write the ball’s constructor:
The attributes of the ball are very simple, xy is the coordinates of the ball, vx and vy are the initial horizontal velocity and initial vertical velocity of the ball. radius is the radius of the ball, color is the color of the ball (in order to distinguish different balls), oldx and oldy record the position of the ball in the previous frame, and are used for position correction after the collision between the balls in the later stage (actually useless later) On the above, the position correction is calculated directly. If you use oldx to set it, it will be very loose, but if you record it, it will inevitably be used).
After writing the attributes of the ball, write the action of the ball in the ball prototype:
if(Math.abs(this.vx) < 0.01){
this.vx = 0;
}
else this.vx = this.vx>0? - mocali*t : mocali*t;
this.vy = this.vy g * t;
this.x = t * this.vx * pxpm;
this.y = t * this.vy * pxpm;< /p>
if(this.y > canvas.height - ballRadius || this.y < ballRadius){
this.y = this.y < ballRadius ? ballRadius : (canvas.height - ballRadius);
this.vy = -this.vy*collarg
}
if(this.x > canvas.width - ballRadius || this.x < ballRadius){
this.x = this .x < ballRadius ? ballRadius : (canvas.width - ballRadius);
this.derectionX = !this.derectionX;
this.vx = -this.vx*collarg;
}
this .paint();
},
}
There are only two ways to move the ball. The first method is to draw yourself, and the second method is to control the movement of the ball. t is the time difference between the current frame and the previous frame. Used to calculate the increment of the ball's speed to obtain the increment of the ball's displacement, thereby calculating the new position of the ball and redrawing the ball. When the new position is obtained, it is also determined whether the new position of the ball exceeds the wall. If it exceeds, the speed is corrected to allow the ball to rebound.
Some constants in the second method ballRadius =30, g = 9.8, mocali = 0.5, balls = [], collarg = 0.8, pxpm = canvas.width/20; The meaning is obvious: ballradius is the radius of the ball, g is the acceleration of gravity, mocali is the horizontal deceleration caused by air resistance, balls is an array used to store small ball objects, and collagen is the elastic coefficient. pxpm is a mapping between pixels and meters, treating the canvas as a 20-meter-wide area.
【Collision Detection】
After creating the ball object, start writing the collision. The collision between the balls:
//Get the increment of velocity after collision
var ax = ((b1.vx - b2.vx)*Math.pow((b1.x - b2.x) , 2) (b1.vy - b2.vy)*(b1.x - b2.x)*(b1.y - b2.y))/Math.pow(rc , 2)
var ay = ((b1.vy - b2.vy )*Math.pow((b1.y - b2.y) , 2) (b1.vx - b2.vx)*(b1.x - b2.x) (b1.y - b2.y))/Math. pow(rc, 2)
//Give the ball a new speed
b1.vx = (b1.vx-ax)*collarg;
b1.vy = (b1.vy-ay)*collarg;
b2.vx = (b2.vx ax)*collarg;
b2.vy = (b2.vy ay)*collarg;
//Get the oblique cutting position of the two balls and force the twist
var clength = ((b1.radius b2.radius)-rc)/2;
var cx = clength * (b1.x-b2 .x)/rc;
var cy = clength * (b1.y-b2.y)/rc;
b1.x = b1.x cx;
b1.y = b1.y cy;
b2.x = b2.x-cx;
b2.y = b2.y-cy;
}
}
}
}
}
I won’t go into the specific principles. If you want to know the principles, just click on Algorithm design of small ball collision . The following paragraph is to prevent the ball from being able to rebound normally due to repeated collision detection, so the distance between the centers of the two balls is calculated, and then the oblique position of the two balls is calculated, and the positions of the two balls are corrected.
【Motion Animation】
Final step:
canvas.onclick = function(event){
event = event || window.event;
var x = event.clientX document.body.scrollLeft document.documentElement.scrollLeft - canvas.offsetLeft;
var y= event.clientY document.body.scrollTop document.documentElement.scrollTop - canvas.offsetTop;
balls.forEach(function(){
this.vx = (x - this.x)/20; //Initial velocity m/s
this.vy = (y - this.y) /20;
});
}
function animate(){
ctx.save();
ctx.fillStyle = "rgba(255,255,255,0.2)";
ctx.fillRect(0,0,canvas.width,canvas .height)
ctx.restore();
// ctx.clearRect(0,0,canvas.width,canvas.height)
var t1 = new Date();
var t = (t1 - t0)/1000;
collision();
balls.forEach(function(){
this.run (t);
});
t0 = t1;
if("requestAnimationFrame" in window){
requestAnimationFrame(animate);
}
else if("webkitRequestAnimationFrame" in window){
webkitRequestAnimationFrame(animate);
}
else if("msRequestAnimationFrame" in window){
msRequestAnimationFrame(animate);
}
else if("mozRequestAnimationFrame" in window){
mozRequestAnimationFrame(animate);
}
}
}
Give the ball an initial velocity by clicking on the canvas, and then animate is the method used to run each frame of the animation. The above ctx.fillStyle = "rgba(255,255,255,0.2)"; ctx.fillRect(0,0,canvas.width,canvas.height) is to add a ghost shadow to the ball. I think this will look better. If you don't like it, , just use clearRect to clear it directly. Then calculate the time difference of each frame, and then traverse and redraw the small ball array in the small ball array. Then add the collision method for collision detection. The animation is finished.
At this point, it has been written. Source code address:
https://github.com/whxaxes/canvas-test/blob/gh-pages/src/Other-demo/shotBall.html