canvas Realizes Dynamic Small Ball Overlap Effect

  • 2021-07-16 01:42:58
  • OfStack

Previous words

In the javascript motion series, various motions are introduced in detail, including the wall-hitting motion. However, if canvas is used to realize it, it is another way of thinking. This article will introduce the overlapping effect of canvas dynamic balls in detail

Static ball

Firstly, 50 static spheres with random radius and random position are generated


<button id="btn"> Button </button>
<canvas id="canvas" width="500" height="300" style="border:1px solid black"> The current browser does not support canvas Please change your browser and try again </canvas>
<script>
var canvas = document.getElementById('canvas');
var H=300,W=500;
btn.onclick = function(){
 getBalls();
}
getBalls();
function getBalls(){
 canvas.height = H;
 if(canvas.getContext){
 var cxt = canvas.getContext('2d');
 for(var i = 0; i < 50; i++){
 var tempR = Math.floor(Math.random()*255);
 var tempG = Math.floor(Math.random()*255);
 var tempB = Math.floor(Math.random()*255);
 cxt.fillStyle = 'rgb(' + tempR + ',' + tempG + ',' + tempB + ')';
 var tempW = Math.floor(Math.random()*W);
 var tempH = Math.floor(Math.random()*H);
 var tempR = Math.floor(Math.random()*50);
 cxt.beginPath();
 cxt.arc(tempW,tempH,tempR,0,Math.PI*2);
 cxt.fill();
 }
 } 
}
</script>

Random motion

Then, these 50 balls move randomly, and the motion status of the balls needs to be updated with the timer. At this time, you need to rewrite the above code


<button id="btn"> Update </button>
<canvas id="canvas" width="500" height="300" style="border:1px solid black"> The current browser does not support canvas Please change your browser and try again </canvas>
<script>
btn.onclick = function(){history.go();}
var canvas = document.getElementById('canvas');
// Storage canvas width and height 
var H=300,W=500;
// Number of storage balls 
var NUM = 50;
// Storage pellet 
var balls = [];
function getBalls(){
 if(canvas.getContext){
 var cxt = canvas.getContext('2d');
 for(var i = 0; i < NUM; i++){
 var tempR = Math.floor(Math.random()*255);
 var tempG = Math.floor(Math.random()*255);
 var tempB = Math.floor(Math.random()*255);
 var tempColor = 'rgb(' + tempR + ',' + tempG + ',' + tempB + ')';
 var tempX = Math.floor(Math.random()*W);
 var tempY = Math.floor(Math.random()*H);
 var tempR = Math.floor(Math.random()*30+20);
 var tempBall = {
 x:tempX,
 y:tempY,
 r:tempR,
 stepX:Math.floor(Math.random() * 4 -2),
 stepY:Math.floor(Math.random() * 4 -2),
 color:tempColor,
 disX:Math.floor(Math.random() * 3 -1),
 disY:Math.floor(Math.random() * 3 -1)
 };
 balls.push(tempBall);
 }
 } 
}
function updateBalls(){
 for(var i = 0; i < balls.length; i++){
 balls[i].stepY += balls[i].disY;
 balls[i].stepX += balls[i].disX;
 balls[i].x += balls[i].stepX;
 balls[i].y += balls[i].stepY; 
 }
}
function renderBalls(){
 // Reset the canvas height to empty the canvas 
 canvas.height = H; 
 if(canvas.getContext){
 var cxt = canvas.getContext('2d');
 for(var i = 0; i < balls.length; i++){
 cxt.beginPath();
 cxt.arc(balls[i].x,balls[i].y,balls[i].r,0,2*Math.PI);
 cxt.fillStyle = balls[i].color;
 cxt.closePath();
 cxt.fill(); 
 } 
 }
}
getBalls();
clearInterval(oTimer);
var oTimer = setInterval(function(){
 // Update the motion status of the ball 
 updateBalls();
 // Render a small ball 
 renderBalls();
},50);
</script>

Wall-impingement detection

Next, add the detection function of the ball hitting the wall. When the ball hits the wall, it will change to the opposite direction


function bumpTest(ele){
 // Left side 
 if(ele.x <= ele.r){
 ele.x = ele.r;
 ele.stepX = -ele.stepX;
 }
 // Right side 
 if(ele.x >= W - ele.r){
 ele.x = W - ele.r;
 ele.stepX = -ele.stepX;
 }
 // Upper side 
 if(ele.y <= ele.r){
 ele.y = ele.r;
 ele.stepY = -ele.stepY;
 }
 // Underside 
 if(ele.y >= H - ele.r){
 ele.y = H - ele.r;
 ele.stepY = -ele.stepY;
 }
}

<button id="btn"> Update </button>
<canvas id="canvas" width="500" height="300" style="border:1px solid black"> The current browser does not support canvas Please change your browser and try again </canvas>
<script>
btn.onclick = function(){history.go();}
var canvas = document.getElementById('canvas');
// Storage canvas width and height 
var H=300,W=500;
// Number of storage balls 
var NUM = 30;
// Storage pellet 
var balls = [];
function getBalls(){
 if(canvas.getContext){
 var cxt = canvas.getContext('2d');
 for(var i = 0; i < NUM; i++){
 var tempR = Math.floor(Math.random()*255);
 var tempG = Math.floor(Math.random()*255);
 var tempB = Math.floor(Math.random()*255);
 var tempColor = 'rgb(' + tempR + ',' + tempG + ',' + tempB + ')';
 var tempR = Math.floor(Math.random()*30+20);
 var tempX = Math.floor(Math.random()*(W-tempR) + tempR);
 var tempY = Math.floor(Math.random()*(H-tempR) + tempR);
 
 var tempBall = {
 x:tempX,
 y:tempY,
 r:tempR,
 stepX:Math.floor(Math.random() * 13 -6),
 stepY:Math.floor(Math.random() * 13 -6),
 color:tempColor
 };
 balls.push(tempBall);
 }
 } 
}
function updateBalls(){
 for(var i = 0; i < balls.length; i++){
 balls[i].x += balls[i].stepX;
 balls[i].y += balls[i].stepY; 
 bumpTest(balls[i]);
 }
}
function bumpTest(ele){
 // Left side 
 if(ele.x <= ele.r){
 ele.x = ele.r;
 ele.stepX = -ele.stepX;
 }
 // Right side 
 if(ele.x >= W - ele.r){
 ele.x = W - ele.r;
 ele.stepX = -ele.stepX;
 }
 // Upper side 
 if(ele.y <= ele.r){
 ele.y = ele.r;
 ele.stepY = -ele.stepY;
 }
 // Underside 
 if(ele.y >= H - ele.r){
 ele.y = H - ele.r;
 ele.stepY = -ele.stepY;
 }
}
function renderBalls(){
 // Reset the canvas height to empty the canvas 
 canvas.height = H; 
 if(canvas.getContext){
 var cxt = canvas.getContext('2d');
 for(var i = 0; i < balls.length; i++){
 cxt.beginPath();
 cxt.arc(balls[i].x,balls[i].y,balls[i].r,0,2*Math.PI);
 cxt.fillStyle = balls[i].color;
 cxt.closePath();
 cxt.fill(); 
 } 
 }
}
getBalls();
clearInterval(oTimer);
var oTimer = setInterval(function(){
 // Update the motion status of the ball 
 updateBalls();
 // Render a small ball 
 renderBalls();
},50);
</script>

Overlapping effect


canvas Composite properties of globalCompositeOperation Indicates how a later drawn graph is combined with a first drawn graph. The property value is a string, and the possible values are as follows: 
source-over( Default ) The later drawn figure is above the first drawn figure 
source-in: The overlapping part of the later drawn figure and the first drawn figure is visible, and the other parts of both are completely transparent 
source-out: The part of the later drawn figure that does not overlap with the first drawn figure is visible, and the first drawn figure is completely transparent 
source-atop: The overlapping part of the later drawn figure and the first drawn figure is visible, and the first drawn figure is not affected 
destination-over: The later drawn figure is below the first drawn figure, and only the part under the previous transparent pixel is visible 
destination-in: The later drawing is located below the first drawing, and the non-overlapping part of the two is completely transparent 
destination-out: The later drawn figure erases the part overlapping the first drawn figure 
destination-atop: The later drawing is located below the first drawing, and the first drawing will become transparent where the two do not overlap 
lighter: The value of the overlapping part of the later drawn figure and the first drawn figure is added to brighten the part 
copy: The post-drawn graphic completely replaces the overlapping pre-drawn graphic 
xor: The portion where the later drawn figure overlaps the first drawn figure is executed " XOR " Operation 

Add the overlapping effect of the ball to 'xor', which is the final effect display


<button id="btn"> Transformation </button>
<canvas id="canvas" width="500" height="300" style="border:1px solid black"> The current browser does not support canvas Please change your browser and try again </canvas>
<script>
btn.onclick = function(){history.go();}
var canvas = document.getElementById('canvas');
// Storage canvas width and height 
var H=300,W=500;
// Number of storage balls 
var NUM = 30;
// Storage pellet 
var balls = [];
function getBalls(){
 if(canvas.getContext){
 var cxt = canvas.getContext('2d');
 for(var i = 0; i < NUM; i++){
 var tempR = Math.floor(Math.random()*255);
 var tempG = Math.floor(Math.random()*255);
 var tempB = Math.floor(Math.random()*255);
 var tempColor = 'rgb(' + tempR + ',' + tempG + ',' + tempB + ')';
 var tempR = Math.floor(Math.random()*30+20);
 var tempX = Math.floor(Math.random()*(W-tempR) + tempR);
 var tempY = Math.floor(Math.random()*(H-tempR) + tempR);
 
 var tempBall = {
 x:tempX,
 y:tempY,
 r:tempR,
 stepX:Math.floor(Math.random() * 21 -10),
 stepY:Math.floor(Math.random() * 21 -10),
 color:tempColor
 };
 balls.push(tempBall);
 }
 } 
}
function updateBalls(){
 for(var i = 0; i < balls.length; i++){
 balls[i].x += balls[i].stepX;
 balls[i].y += balls[i].stepY; 
 bumpTest(balls[i]);
 }
}
function bumpTest(ele){
 // Left side 
 if(ele.x <= ele.r){
 ele.x = ele.r;
 ele.stepX = -ele.stepX;
 }
 // Right side 
 if(ele.x >= W - ele.r){
 ele.x = W - ele.r;
 ele.stepX = -ele.stepX;
 }
 // Upper side 
 if(ele.y <= ele.r){
 ele.y = ele.r;
 ele.stepY = -ele.stepY;
 }
 // Underside 
 if(ele.y >= H - ele.r){
 ele.y = H - ele.r;
 ele.stepY = -ele.stepY;
 }
}
function renderBalls(){
 // Reset the canvas height to empty the canvas 
 canvas.height = H; 
 if(canvas.getContext){
 var cxt = canvas.getContext('2d');
 for(var i = 0; i < balls.length; i++){
 cxt.beginPath();
 cxt.arc(balls[i].x,balls[i].y,balls[i].r,0,2*Math.PI);
 cxt.fillStyle = balls[i].color;
 cxt.globalCompositeOperation = 'xor';
 cxt.closePath();
 cxt.fill(); 
 } 
 }
}
getBalls();
clearInterval(oTimer);
var oTimer = setInterval(function(){
 // Update the motion status of the ball 
 updateBalls();
 // Render a small ball 
 renderBalls();
},50);
</script>

Source code view


Related articles: