I made a script about moving rectangles. I'd like to stop the animation when the two object hits each other and make a javasript output of bot of the rectangles to te top left. How can I do that?
Here is my actual code:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>
window.onload=function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
// define a rect using a javascript object
var rect1={
x:25,
y:150,
width:180,
height:50,
directionX:1
}
// define another rect using a javascript object
var rect2={
x:800,
y:150,
width:200,
height:80,
directionX:-1
}
// put each rect in a rects[] array
var rects=[rect1,rect2];
// start the animation loop
requestAnimationFrame(animate);
function animate(time){
// move each rect in the rects[] array by its
// own directionx
for(var i=0;i<rects.length;i++){
rects[i].x+=rects[i].directionX;
}
// draw all the rects in their new positions
draw();
// request another frame in the animation loop
requestAnimationFrame(animate);
}
function draw(){
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<rects.length;i++){
var r=rects[i]
ctx.strokeRect(r.x,r.y,r.width,r.height);
}
}
}
</script>
</head>
<body>
<canvas id="canvas" width="1000px" height="600"
style="border: 1px solid #000000;"></canvas>
</body>
</html>
You run the animation by calling requestAnimationFrame(animate)
So if you wanna stop the animation, it can be simple, just stop calling it ! :)
You might use an if statement :
if(collision){
// Not requesting a new frame
// Do the actions on collision
} else {
// Requesting a new frame
requestAnimationFrame(animate);
}
The collision function will look like this:
function collision(){
let collision = false;
if(rect1.x > rect2.x + rect2.width ||
rect1.x + rect1.width < rect2.x ||
rect1.y > rect2.y + rect2.height ||
rect1.y + rect1.height < rect2.y){
// console.log(`No collision between rect1 and rect2`);
} else {
// console.log(`Collision !! between rect1 and rect2`);
collision = true;
}
return collision;
}
For what is about the output, you can use fillText() to log the positions of your rectangles where you want on the canvas.
for(let i = 0; i < rects.length; i++){
ctx.font = `20px Arial`;
ctx.fillStyle = "black";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText(`Rect ${i + 1}: x = ${rects[i].x}, y = ${rects[i].y}`, 10, 10 + 20 * i);
}
window.onload = function(){
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const cw = canvas.width;
const ch = canvas.height;
const rect1 = {
x: 25,
y: 30,
width: 180,
height: 50,
directionX: 1
}
const rect2 = {
x: 800,
y: 30,
width: 200,
height: 80,
directionX: -1
}
const rect3 = {
x: -215,
y: 90,
width: 500,
height: 90,
directionX: 1
}
const rects = [rect1, rect2, rect3];
function collision(){
let collision = false;
for(let i = 0; i < rects.length - 1; i++){
for(let j = i + 1; j < rects.length; j++){
if( rects[i].x > rects[j].x + rects[j].width ||
rects[i].x + rects[i].width < rects[j].x ||
rects[i].y > rects[j].y + rects[j].height ||
rects[i].y + rects[i].height < rects[j].y){
// console.log(`No collision between rect${i+1} and rect${j+1}`);
} else {
// console.log(`Collision !! between rect${i+1} and rect${j+1}`);
collision = true;
}
}
}
return collision;
}
function logPosition(){
for(let i = 0; i < rects.length; i++){
ctx.font = `14px Arial`;
ctx.fillStyle = "black";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText(`Rect ${i + 1}: x = ${rects[i].x}, y = ${rects[i].y}`, 10, 10 + 14 * i);
}
}
function update(){
for(let i = 0; i < rects.length; i++){
rects[i].x += rects[i].directionX;
}
}
function draw(){
ctx.clearRect(0, 0, cw, ch);
for(let i = 0; i < rects.length; i++){
// ------ Draw the rectangle --------------
ctx.strokeRect(rects[i].x, rects[i].y, rects[i].width, rects[i].height);
// ------ Show name on the rectangle ------
ctx.font = `20px Arial`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "black";
ctx.fillText(`Rect ${i + 1}`, rects[i].x + rects[i].width / 2, rects[i].y + rects[i].height / 2);
// ----------------------------------------
}
}
function animate(time){
// Update rectangles position
update();
// Draw updated rectangles
draw();
// Outpout (top-left) the position of the rectangles if collision otherwise, request a new frame
if(collision()){
logPosition();
console.log("COLLISION");
} else {
requestAnimationFrame(animate);
}
}
// Start the animation
requestAnimationFrame(animate);
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="canvas" width="1000px" height="600"
style="border: 1px solid #000000;"></canvas>
</body>
</html>
Why multiple rectangles ?
Because as you used an stocking array (rects) & for-loops for only 2 rectangles, I supposed it could be more rectangles in the future, so I went for a more general case. But if it was really intented for only 2 rectangles, I would drop the stocking array & the for-loops.
window.onload = function(){
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const cw = canvas.width;
const ch = canvas.height;
const rect1 = {
x: 25,
y: 50,
width: 180,
height: 50,
directionX: 1
}
const rect2 = {
x: 800,
y: 50,
width: 200,
height: 80,
directionX: -1
}
function collision(){
let collision = false;
if( rect1.x > rect2.x + rect2.width ||
rect1.x + rect1.width < rect2.x ||
rect1.y > rect2.y + rect2.height ||
rect1.y + rect1.height < rect2.y){
// console.log(`No collision between rect1 and rect2`);
} else {
// console.log(`Collision !! between rect1 and rect2`);
collision = true;
}
return collision;
}
function logPosition(){
ctx.font = `14px Arial`;
ctx.fillStyle = "black";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText(`Rect 1: x = ${rect1.x}, y = ${rect1.y}`, 10, 10);
ctx.fillText(`Rect 2: x = ${rect2.x}, y = ${rect2.y}`, 10, 24);
}
function update(){
rect1.x += rect1.directionX;
rect2.x += rect2.directionX;
}
function draw(){
ctx.clearRect(0, 0, cw, ch);
// ------ Draw the rectangles ---------------
ctx.strokeRect(rect1.x, rect1.y, rect1.width, rect1.height);
ctx.strokeRect(rect2.x, rect2.y, rect2.width, rect2.height);
// ------ Show name on the rectangles ------
ctx.font = `20px Arial`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "black";
ctx.fillText(`Rect 1`, rect1.x + rect1.width / 2, rect1.y + rect1.height / 2);
ctx.fillText(`Rect 2`, rect2.x + rect2.width / 2, rect2.y + rect2.height / 2);
// -----------------------------------------
}
function animate(time){
// Update rectangles position
update();
// Draw updated rectangles
draw();
// Outpout (top-left) the position of the rectangles if collision otherwise, request a new frame
if(collision()){
logPosition();
console.log("COLLISION");
} else {
requestAnimationFrame(animate);
}
}
// Start the animation
requestAnimationFrame(animate);
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="canvas" width="1000px" height="600"
style="border: 1px solid #000000;"></canvas>
</body>
</html>
That's it !
But if you have others actions and that you need the animation loop to keep running, then, the other option is to stop updating the logic (the position of the rectangle). It can be achieved by using an if statement :
function animate(time){
// Update rectangles position
if(!collision()){
update();
} else {
logPosition();
console.log("COLLISION");
}
// Draw updated rectangles
draw();
// Outpout (top-left) the position of the rectangles if collision otherwise, request a new frame
requestAnimationFrame(animate);
}