Home>

### How to make a collision of two blocks on Canvas JavaScript, taking into account the side of a coli

Making a game on JavaScript on Canvas, made the movement of the character and gravity, but I can't do the right collision, such that it worked with too large /small block sizes. Also need a party with which the character collisters with the block

Code for determining collisions:

``````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
) {
RETURN TRUE;
} ELSE {
RETURN FALSE;
}
``````

code to determine the sides:

``````if (mob.x + mob.width >
= Ground.x &
&
self.x + self.width <
= Ground.x) {
if (
(mob.y >
= Ground.y &
&
mob.y <
= ground.y + ground.height) ||
(mob.y + mob.height >
= Ground.y &
&
mob.y + mob.height <
= ground.y + ground.height)
) {
mob.x= ground.x -mob.width;
mob.collisions.left= true;
}
}
//(and so for each)
``````

The problem is that if a character is 50 per 50 pix, then with a color with a block of 200 on 10 pixels, the side coliology does not occur.

Question urgent, any help is welcome.

Requires clarification: what approaches to the decision were tried, and acc. -What exactly in trying to solve does not suit /fail? (There are many ways to determine the collision of figures, and it is not clear which one here is called "correct")

yar852021-08-25 00:58:09

I can give a link to the project so you watched it. It employs the collision and the definition of the parties, but, firstly, the code turns out to be confusing, secondly, with too small /large sides of the block, the character simply fails

bourbaki2021-08-25 00:58:09

Me (as well as other participants, especially those who later will look for a decision) is interesting exactly and answers to him, and not some-there is a project on the link ... Therefore, it is necessary to add specifics right here (in the apartment), and preferably A verbal description -and not to replace the specifics of links to external resources that the abyss may after some time. First of all, there is a very important point here is the method of determining collisions (it can be described in words and formulas, and the minimum code -the form is not so important, if only it was understandable).

yar852021-08-25 00:58:09

And here I ask for help in solving the problem

bourbaki2021-08-25 00:58:09

In order to correctly determine the side of the collision, it is necessary to have the coordinates of these objects in the previous step: whether the intersection of the axes to the collision was to know. If the intersection of y was, the collision could only be right-left, and vice versa. If the intersections were not at all, then the collision occurred by corners -simultaneously on the sides of the top-bottom and right-left. The object of displacement of objects should not be more than half the width or height of one of the objects.

Leonid2021-08-25 00:58:09

Remarkable here only feature ``` DetectCollision. ``` . All explanations added in the comments to this function. Additionally, it should be borne in mind that the inaccurate detection of the collision here is possible if the discrete movement step of objects is greater than half the width or height of one of the objects. But this adjustment can be added to the code, having a position in the previous step.

With collision, both objects change the direction of movement according to the corresponding coordinate. Therefore, if one object catches the other, the effect looks unnatural. Additional improvements are needed here.

In order to determine how sides were collision, you can set the condition ``` if (DX > 0) rect1.sidex= 'left'; ``` ...

``````const canvas= document.getelementByid ('Game');
Const w= canvas.width= 600;
const H= CANVAS.Height= 200;
Const CTX= canvas.getContext ('2D');
const RECT1= {
W: 40,
H: 40,
CX: 200,
CY: 50,
SX: 1,
SY: -2.
}
const RECT2= {
W: 20,
H: 60,
CX: 400,
CY: 120,
SX: 2,
SY: 1.
}
Draw ([RECT1, RECT2]);
FUNCTION DRAW (ARR) {
Move (ARR);
ctx.clearRect (0.0, w, h);
Arr.Foreach (R= &GT;
{
CTX.FillRect (R.CX-R.W /2, R.CY-R.H /2, R.W, R.H);
})
RequestanimationFrame (()= &gt;
{Draw (Arr)});
}
FUNCTION MOVE (ARR) {
DetectCollision (ARR);
Arr.Foreach (RECT= &GT;
{
DetectBorder (RECT);
Rect.Prevx= rect.cx;
Rect.Prevy= Rect.Cy;
rect.cx += rect.sx;
Rect.cy += rect.Sy;
})
}
FUNCTION DETECTBORDER (RECT) {
if (rect.cx + rect.w /2 &gt;
= W || rect.cx -rect.w /2 &lt;
= 0) rect.sx= -rect.SX;
if (rect.cy + rect.h /2 &gt;
= H || Rect.cy -rect.h /2 &lt;
= 0) rect.sy= -rect.sy;
}
Function DetectCollision ([RECT1, RECT2]) {
LET DX= RECT1.CX -RECT2.CX; //Distance between centers by x
Let DY= RECT1.CY -RECT2.CY; //Distance between y centers
Let Rx= (rect1.w + rect2.w) /2; //Minimum distance by x
Let Ry= (rect1.h + rect2.h) /2; //Minimum Distance by Y
if (math.abs (DX) &LT;
RX &
&
Math.abs (DY) &LT;
RY) {//if there is a collision
if (math.abs (rect1.prevx -rect2.prevx) &gt;
= Rx) {//If there was no connection, then the collision occurred by side boards
rect1.sx= -rect1.sx;
rect2.sx= -rect2.sx;
//To determine the collision parties:
//if (dx &gt;
0) {
//rect1.sidex= 'left';
//rect2.sidex= 'right';
//} ELSE {
//rect1.sidex= 'right';
//rect2.sidex= 'left';
//}
}
if (math.abs (rect1.prevy -rect2.prevy) &gt;
= RY) {//if there was no altogether, then the top-bottom collision
rect1.sy= -rect1.sy;
rect2.sy= -rect2.sy;
//if (DY &GT;
0) {
//rect1.sidey= 'top';
//Rect2.sidey= 'Bottom';
//} ELSE {
//rect1.sidey= 'bottom';
//rect2.sidey= 'top';
//}
}
//If the alignment was not, then the collision in the corners
}
} ``````
``````&lt;
canvas id= "Game" &gt;
&Lt;
/canvas &gt;
``````

"But this adjustment can be added to the code, having a position in the previous step." -or, as an option: divide the calculation with drawing to independent ACS. Cycles (then the object offset will== the product of its speed during the frame time, because the set of iterations will remain only on a relatively slow draw).

yar852021-08-25 00:58:09

@ Yar85 I did not understand. Divide on independent asynchronous cycles? The displacement of the object is equal to the distance, and the frame and so determines the unit of time. This is the distance (SX, SY) and there is speed. And if the object on the way is less than this step, then considering the result of this step, it will be incomprehensible from where this intersection began (after all, the centers of objects can be changed in places). In this case, one can study the previous position according to the specified axis and according to it to calculate the parties "entry" in the intersection. However, it may be that in one step both objects will be afraid each other if each of them is less than step.

Leonid2021-08-25 00:58:09

It is not desirable to grow the step of each frame in an idea that the frame is the minimum possible and optimal unit to calculate the new coordinates, processing the inspection and so on. You can, of course, after the occurrence of the intersection, retrospectively walk in the cycle, a multiple of one pixel, for example, to study the moment of entry, but why?)))

Leonid2021-08-25 00:58:09

"Frame and so defines a unit of time" -only on paper. And in reality, with rich graphics "heavy" scenes, the skipping frames intervene (see how asynchronous microstatic queues and RAF). Therefore, prof.-realization (in products where canvas animations are in an incorrect place) often use the separation of calculations (quickly, stable) and drawing (slowly, frames of frames are possible): Sometimes the calculations are a separate task in ASINA. Queues, sometimes it is a sync. The code works on the flag from Asynch. Tasks are not the essence ... It is important that the condition should not entirely depend on the RAF render.

yar852021-08-24 04:19:10

Plus, computing computation allows optimization. For example, it is not always necessary to recalculate on each frame (discharge the frequency of calculations can be significantly lifted by the performance without sacrificing the frames). Alternatively, you can define the omission of iterations by the argument of the Callback RAF and the time of the last frame, but these are extra calculations: sometimes it is permissible, and sometimes there is no ... IMHO, you should not say that adding computing is always a good solution (the best code is one that is not performed). Simplification /reduction of code work -what is worth striving for fast and smooth animations, IMHO.

yar852021-08-24 04:28:27

Remarkable here only feature ``` DetectCollision. ``` . All explanations added in the comments to this function. Additionally, it should be borne in mind that the inaccurate detection of the collision here is possible if the discrete movement step of objects is greater than half the width or height of one of the objects. But this adjustment can be added to the code, having a position in the previous step.

With collision, both objects change the direction of movement according to the corresponding coordinate. Therefore, if one object catches the other, the effect looks unnatural. Additional improvements are needed here.

In order to determine how sides were collision, you can set the condition ``` if (DX > 0) rect1.sidex= 'left'; ``` ...

``````const canvas= document.getelementByid ('Game');
Const w= canvas.width= 600;
const H= CANVAS.Height= 200;
Const CTX= canvas.getContext ('2D');
const RECT1= {
W: 40,
H: 40,
CX: 200,
CY: 50,
SX: 1,
SY: -2.
}
const RECT2= {
W: 20,
H: 60,
CX: 400,
CY: 120,
SX: 2,
SY: 1.
}
Draw ([RECT1, RECT2]);
FUNCTION DRAW (ARR) {
Move (ARR);
ctx.clearRect (0.0, w, h);
Arr.Foreach (R= &GT;
{
CTX.FillRect (R.CX-R.W /2, R.CY-R.H /2, R.W, R.H);
})
RequestanimationFrame (()= &gt;
{Draw (Arr)});
}
FUNCTION MOVE (ARR) {
DetectCollision (ARR);
Arr.Foreach (RECT= &GT;
{
DetectBorder (RECT);
Rect.Prevx= rect.cx;
Rect.Prevy= Rect.Cy;
rect.cx += rect.sx;
Rect.cy += rect.Sy;
})
}
FUNCTION DETECTBORDER (RECT) {
if (rect.cx + rect.w /2 &gt;
= W || rect.cx -rect.w /2 &lt;
= 0) rect.sx= -rect.SX;
if (rect.cy + rect.h /2 &gt;
= H || Rect.cy -rect.h /2 &lt;
= 0) rect.sy= -rect.sy;
}
Function DetectCollision ([RECT1, RECT2]) {
LET DX= RECT1.CX -RECT2.CX; //Distance between centers by x
Let DY= RECT1.CY -RECT2.CY; //Distance between y centers
Let Rx= (rect1.w + rect2.w) /2; //Minimum distance by x
Let Ry= (rect1.h + rect2.h) /2; //Minimum Distance by Y
if (math.abs (DX) &LT;
RX &
&
Math.abs (DY) &LT;
RY) {//if there is a collision
if (math.abs (rect1.prevx -rect2.prevx) &gt;
= Rx) {//If there was no connection, then the collision occurred by side boards
rect1.sx= -rect1.sx;
rect2.sx= -rect2.sx;
//To determine the collision parties:
//if (dx &gt;
0) {
//rect1.sidex= 'left';
//rect2.sidex= 'right';
//} ELSE {
//rect1.sidex= 'right';
//rect2.sidex= 'left';
//}
}
if (math.abs (rect1.prevy -rect2.prevy) &gt;
= RY) {//if there was no altogether, then the top-bottom collision
rect1.sy= -rect1.sy;
rect2.sy= -rect2.sy;
//if (DY &GT;
0) {
//rect1.sidey= 'top';
//Rect2.sidey= 'Bottom';
//} ELSE {
//rect1.sidey= 'bottom';
//rect2.sidey= 'top';
//}
}
//If the alignment was not, then the collision in the corners
}
} ``````
``````&lt;
canvas id= "Game" &gt;
&Lt;
/canvas &gt;
``````

"But this adjustment can be added to the code, having a position in the previous step." -or, as an option: divide the calculation with drawing to independent ACS. Cycles (then the object offset will== the product of its speed during the frame time, because the set of iterations will remain only on a relatively slow draw).

yar852021-08-25 00:58:09

@ Yar85 I did not understand. Divide on independent asynchronous cycles? The displacement of the object is equal to the distance, and the frame and so determines the unit of time. This is the distance (SX, SY) and there is speed. And if the object on the way is less than this step, then considering the result of this step, it will be incomprehensible from where this intersection began (after all, the centers of objects can be changed in places). In this case, one can study the previous position according to the specified axis and according to it to calculate the parties "entry" in the intersection. However, it may be that in one step both objects will be afraid each other if each of them is less than step.

Leonid2021-08-25 00:58:09

It is not desirable to grow the step of each frame in an idea that the frame is the minimum possible and optimal unit to calculate the new coordinates, processing the inspection and so on. You can, of course, after the occurrence of the intersection, retrospectively walk in the cycle, a multiple of one pixel, for example, to study the moment of entry, but why?)))

Leonid2021-08-25 00:58:09

"Frame and so defines a unit of time" -only on paper. And in reality, with rich graphics "heavy" scenes, the skipping frames intervene (see how asynchronous microstatic queues and RAF). Therefore, prof.-realization (in products where canvas animations are in an incorrect place) often use the separation of calculations (quickly, stable) and drawing (slowly, frames of frames are possible): Sometimes the calculations are a separate task in ASINA. Queues, sometimes it is a sync. The code works on the flag from Asynch. Tasks are not the essence ... It is important that the condition should not entirely depend on the RAF render.

yar852021-08-24 04:19:10

Plus, computing computation allows optimization. For example, it is not always necessary to recalculate on each frame (discharge the frequency of calculations can be significantly lifted by the performance without sacrificing the frames). Alternatively, you can define the omission of iterations by the argument of the Callback RAF and the time of the last frame, but these are extra calculations: sometimes it is permissible, and sometimes there is no ... IMHO, you should not say that adding computing is always a good solution (the best code is one that is not performed). Simplification /reduction of code work -what is worth striving for fast and smooth animations, IMHO.

yar852021-08-24 04:28:27