Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to implement collision Physics engine with JavaScript

2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

In this article, the editor introduces in detail "how to achieve the collision physics engine in JavaScript". The content is detailed, the steps are clear, and the details are handled properly. I hope this article "how to achieve the collision physics engine in JavaScript" can help you solve your doubts.

Effect picture:

Let's take a look at how to achieve this effect.

Basic structure

We use canvas here to implement the JavaScript physics engine. First prepare the basic files and styles of the project, and create a new index.html, index.js, and style.css file to write the html structure, engine code, and canvas style of canvas, respectively.

Introduce a style file into the tag of index.html:

"in, add the canvas element, load the index.js file:"

This code defines the element whose id is gameboard and puts it under the element, which is mainly used to set the background color and canvas size. Introduce the index.js file at the bottom of the element so that the code in JS can be executed after the DOM is loaded.

The code in style.css is as follows:

* {box-sizing: border-box; padding: 0; margin: 0; font-family: sans-serif;} main {width: 100vW; height: 100vh; background: hsl (0deg, 0%, 10%);}

The style is simple, remove the outer and inner spacing of all elements, and set the width and height of the element to be the same as the browser visual area, and the background color is dark gray.

Hsl (hue, saturation, brightness) is one of the css color representations, and the parameters are hue, saturation and luminance, respectively.

Draw a small ball

Next, draw the ball, mainly using the canvas-related api.

In index.js, write the following code:

Const canvas = document.getElementById ("gameboard"); const ctx = canvas.getContext ("2d"); canvas.width = window.innerWidth;canvas.height = window.innerHeight;let width = canvas.width;let height = canvas.height;ctx.fillStyle = "hsl (170,100%, 50%)"; ctx.beginPath (); ctx.arc (100,100,60,0,2 * Math.PI); ctx.fill ()

The two-dimensional context is mainly used for drawing operation in the code:

Get the canvas element object through the id of canvas.

To get the drawing context through the canvas element object, getContext () requires a parameter to indicate whether to draw a 2d image or a 3D image using webgl. Select 2d here. Context is similar to a paintbrush that can change its color and draw basic shapes.

Set the width and height of the canvas to the width and height of the browser's visual area, and save it to the width and height variables for later use.

Set the color to context, and then call beginPath () to start the drawing.

Use the arc () method to draw a circle, which receives five parameters, the first two are the x and y coordinates of the center of the circle, the third is the radius length, and the fourth and fifth are the start and end angles, respectively, because arc () is actually used to draw an arc, which forms a circle by drawing an arc of 0 to 360 degrees. The angle here is expressed in radian form, and 0 to 360 degrees can be expressed as 0 to 2 * Math.PI.

Finally, use ctx.fill () to color the circle.

In this way, we have successfully drawn a circle, and we treat it as a ball here:

Move the ball

However, at this time, the ball is still still, if you want it to move, then you have to modify its center coordinates, the specific modified value is related to the speed of motion. Before moving the ball, take a look at how canvas animates:

The principle of Canvas animation is similar to that of traditional film. In a period of time, drawing an image, updating the position or shape of the image, clearing the canvas, and redrawing the image can produce a continuous picture at a speed of 60 frames when such operations are performed 60 times or more in a second.

Then in JavaScript, the browser provides the window.requestAnimationFrame () method, which receives a callback function as a parameter. Each execution of the callback function is equivalent to a frame of animation. We need to call it continuously through recursion or loop, and the browser will execute the callback function 60 times in 1 second as many times as possible. Then with it, we can redraw the canvas to achieve the moving effect of the ball.

Because the call to window.requestAnimationFrame () is basically continuous, we can also call it a game Game loop.

Next, let's take a look at the infrastructure of how to write animation:

Function process () {window.requestAnimationFrame (process);} window.requestAnimationFrame (process)

The process () function here is a callback function that is executed 60 times a second, and after each execution, continue to call window.requestAnimationFrame (process) for the next loop. If you want to move the ball, you need to write the code to draw the ball and modify the x, y coordinates of the center of the circle into the process () function.

In order to update the coordinates, we save the center coordinates of the ball to variables to modify them, and then define two new variables, representing the velocity vx in the x-axis direction and the velocity vy in the y-axis direction, and then put the drawing operations related to context into process ():

Let x = 100 Math.PI y = 100 Math.PI vx = 12 Math.PI vy = 25 ctx.fill function process () {ctx.fillStyle = "hsl (170,100%, 50%)"; ctx.beginPath (); ctx.arc (x, y, 60,0,2 * Math.PI); ctx.fill (); window.requestAnimationFrame (process);} window.requestAnimationFrame (process)

To calculate the moving distance of the center coordinates x and y, we need speed and time, and the speed is here, so how do we get the time? Window.requestAnimationFrame () passes the number of milliseconds (that is, timestamp) of the current time to the callback function. We can save the timestamp of this call, and then calculate how many seconds it took to execute this frame of animation on the next call, and then calculate the moving distance based on this number of seconds and the upward speed of the x and y axes, and add them to x and y to get the latest position. Note that the time here is the interval between the last function call and this function call, not the total number of seconds between the first function call and the current function call, so it is equivalent to time increment. You need to add the previous values of x and y. The code is as follows:

Let startTime;function process (now) {if (! startTime) {startTime = now;} let seconds = (now-startTime) / 1000; startTime = now; / / Update location x + = vx * seconds; y + = vy * seconds; / / clear canvas ctx.clearRect (0,0, width, height); / / draw balls ctx.fillStyle = "hsl (170,100%, 50%)"; ctx.beginPath () Ctx.arc (x, y, 60,0,2 * Math.PI); ctx.fill (); window.requestAnimationFrame (process);}

Process () now takes the current timestamp as a parameter and does the following:

Calculate the time interval between the last function call and this function call, and record the timestamp of this call for the next calculation in seconds.

The moving distance is calculated according to the speed in the x and y direction and the time just calculated.

Call clearRect () to clear the rectangular area canvas, where the parameters, the first two are the upper-left coordinates, the last two are width and height, passing the width and height of canvas will clear the whole canvas.

Redraw the ball.

Now the ball can move:

Refactoring code

The above code is suitable for the situation where there is only one ball. If there are multiple balls to draw, you have to write a lot of repetitive code. In this case, we can abstract the ball into a class with operations such as drawing, updating position, and so on. There are also coordinate, speed, radius and other attributes. The reconstructed code is as follows:

Class Circle {constructor (context, x, y, r, vx, vy) {this.context = context; this.x = x; this.y = y; this.r = r; this.vx = vx; this.vy = vy;} / / draw the ball draw () {this.context.fillStyle = "hsl (170,100%, 50%)"; this.context.beginPath () This.context.arc (this.x, this.y, this.r, 0,2 * Math.PI); this.context.fill ();} / * Update canvas * @ param {number} seconds * / update (seconds) {this.x + = this.vx * seconds; this.y + = this.vy * seconds;}}

The code inside is the same as before, so I'm not going to repeat it here. It's important to note that the context brush property of the Circle class is passed in through the constructor, and the code that updates the location is placed in the update () method.

For the entire canvas drawing process, it can also be abstracted into a class as a game or engine controller, such as putting it into a class called Gameboard:

Class Gameboard {constructor () {this.startTime; this.init ();} init () {this.circles = [new Circle (ctx, 100,100,60,12,25), new Circle (ctx, 180,180,30,70,45),]; window.requestAnimationFrame (this.process.bind (this));} process (now) {if (! this.startTime) {this.startTime = now } let seconds = (now-this.startTime) / 1000; this.startTime = now; for (let I = 0; I

< this.circles.length; i++) { this.circles[i].update(seconds); } ctx.clearRect(0, 0, width, height); for (let i = 0; i < this.circles.length; i++) { this.circles[i].draw(ctx); } window.requestAnimationFrame(this.process.bind(this)); }}new Gameboard(); 在 Gameboard 类中: startTime 保存了上次函数执行的时间戳的属性,放到了构造函数中。 init() 方法创建了一个 circles 数组,里边放了两个示例的小球,这里先不涉及碰撞问题。然后调用 window.requestAnimationFrame() 开启动画。注意这里使用了 bind() 来把 Gameboard 的 this 绑定到回调函数中,以便于访问 Gameboard 中的方法和属性。 process() 方法也写到了这里边,每次执行时会遍历小球数组,对每个小球进行位置更新,然后清除画布,再重新绘制每个小球。 最后初始化 Gameboard 对象就可以开始执行动画了。 这个时候有两个小球在移动了。 碰撞检测 为了实现仿真的物理特性,多个物体间碰撞会有相应的反应,第一步就是要先检测碰撞。我们先再多加几个小球,以便于碰撞的发生,在 Gameboard 类的 init() 方法中再添加几个小球: this.circles = [ new Circle(ctx, 30, 50, 30, -100, 390), new Circle(ctx, 60, 180, 20, 180, -275), new Circle(ctx, 120, 100, 60, 120, 262), new Circle(ctx, 150, 180, 10, -130, 138), new Circle(ctx, 190, 210, 10, 138, -280), new Circle(ctx, 220, 240, 10, 142, 350), new Circle(ctx, 100, 260, 10, 135, -460), new Circle(ctx, 120, 285, 10, -165, 370), new Circle(ctx, 140, 290, 10, 125, 230), new Circle(ctx, 160, 380, 10, -175, -180), new Circle(ctx, 180, 310, 10, 115, 440), new Circle(ctx, 100, 310, 10, -195, -325), new Circle(ctx, 60, 150, 10, -138, 420), new Circle(ctx, 70, 430, 45, 135, -230), new Circle(ctx, 250, 290, 40, -140, 335),]; 然后给小球添加一个碰撞状态,在碰撞时,给两个小球设置为不同的颜色: class Circle { constructor(context, x, y, r, vx, vy) { // 其它代码 this.colliding = false; } draw() { this.context.fillStyle = this.colliding ? "hsl(300, 100%, 70%)" : "hsl(170, 100%, 50%)"; // 其它代码 }} 现在来判断小球之间是否发生了碰撞,这个条件很简单,判断两个小球圆心的距离是否小于两个小球的半径之和就可以了,如果小于等于则发生了碰撞,大于则没有发生碰撞。 x1、y1 和 x2、y2 分别两个小球的圆心坐标。在比较时,可以对半径和进行平方运算,进而省略对距离的开方运算 r1 和 r2 为两球的半径。 在 Circle 类中,先添加一个isCircleCollided(other)方法,接收另一个小球对象作为参数,返回比较结果: isCircleCollided(other) { let squareDistance = (this.x - other.x) * (this.x - other.x) + (this.y - other.y) * (this.y - other.y); let squareRadius = (this.r + other.r) * (this.r + other.r); return squareDistance (circle.colliding = false)); for (let i = 0; i < this.circles.length; i++) { for (let j = i + 1; j < this.circles.length; j++) { this.circles[i].checkCollideWith(this.circles[j]); } }} 因为小球在碰撞后就应立即弹开,所以我们一开始要把所有小球的碰撞状态设置为 false,之后在循环中,对每个小球进行检测。这里注意到内层循环是从 i + 1 开始的,这是因为在判断 1 球和 2 球是否碰撞后,就无须再判断 2 球 和 1 球了。 之后在 process() 方法中,执行检测,注意检测应该发生在使用 for 循环更新小球位置的后边才准确: for (let i = 0; i < this.circles.length; i++) { this.circles[i].update(seconds);}this.checkCollision(); 现在,可以看到小球在碰撞时,会改变颜色了。

Boundary collision

After the above code is executed, the ball will cross the boundary and run outside, so let's deal with the boundary collision problem first. In order to detect the boundary collision, we need to deal with all four faces, and judge whether there is a collision with the boundary according to the center coordinate and radius. For example, when colliding with the left boundary, the x coordinate of the center of the circle is less than or equal to the length of the radius, while when colliding with the right boundary, the x coordinate of the center should be greater than or equal to the rightmost coordinate of the canvas (that is, the width value) minus the length of the radius. The upper boundary is similar to the lower boundary, except that the center y coordinate and the height value of the canvas are used. When the collision occurs in the horizontal direction (that is, the left and right boundary), the motion direction of the ball changes, it only needs to reverse the velocity vy in the vertical direction, and the vx is reversed in the vertical direction.

Now look at the implementation of the code, add a checkEdgeCollision () method to the Gameboard class, and write the following code according to the rules described above:

CheckEdgeCollision () {this.circles.forEach ((circle) = > {/ / left and right walls collide if (circle.x)

< circle.r) { circle.vx = -circle.vx; circle.x = circle.r; } else if (circle.x >

Width-circle.r) {circle.vx =-circle.vx; circle.x = width-circle.r;} / / collision between the upper and lower walls if (circle.y

< circle.r) { circle.vy = -circle.vy; circle.y = circle.r; } else if (circle.y >

Height-circle.r) {circle.vy =-circle.vy; circle.y = height-circle.r;}});}

In the code, in addition to the inverse operation of the speed, the coordinates of the ball are changed to be close to the boundary to prevent it from being exceeded during the collision. Next, add boundary collision detection to process ():

This.checkEdgeCollision (); this.checkCollision ()

At this point, you can see that the ball can bounce when it touches the boundary:

But the collision between the balls has not been dealt with, before dealing with, first review the basic operation of the vector, math students can skip directly, only look at the relevant code.

Basic operation of vector

Because the velocity vector (or vector) needs to be manipulated during a collision, the vector is represented in a form similar to coordinates, such as

< 3, 5 >

(the vector is represented here), it has length and direction, there are certain rules for its operation, this tutorial needs to use vector addition, subtraction, multiplication, point multiplication and standardized operations.

To add vectors, you only need to add the x and y coordinates of the two vectors, for example:

< 3 , 5 >

+

< 1 , 2 >

=

< 4 , 7 >

+ =

Subtraction is similar to addition by subtracting x and y coordinates, for example:

< 3 , 5 >

< 1 , 2 >

=

< 2 , 3 >

-= − =

Multiplication, which refers to the multiplication of vectors and scalars, which refers to ordinary numbers, and the result is to multiply x and y by scalars, for example: 3 ×

< 3 , 5 >

=

< 9 , 15 >

3\ times = 3 × =.

Point multiplication is a way of multiplying two vectors, similar to cross multiplication, but it is not used in this example. Point multiplication actually calculates the projection of one vector on another vector. It is calculated by the product of x of two vectors plus the product of y. It returns a scalar, that is, the length of the projection of the first vector on the second vector, for example:

< 3 , 5 >

< 1 , 2 >

= 3 × 1 × 5 × 2 × 13\ cdot = 3\ times 1 × 5\ times 2 × 13 ⋅ = 3 × 1 × 2 × 13

Standardization is to remove the length of the vector, leaving only the direction, so that the length of the vector is 1, which is called the unit vector. The process of standardization is to divide x and y by the length of the vector, because the vector represents the distance from the origin (0,0). So you can use the calculated length directly, for example

< 3, 4 >

The standardized results are as follows:

< 3 , 5 >

< 1 , 2 >

= 3 × 1 × 5 × 2 × 13\ cdot = 3\ times 1 × 5\ times 2 × 13 ⋅ = 3 × 1 × 2 × 13.

After understanding the basic operation of the vector, let's create a Vector utility class to facilitate us to operate on the vector. Its code implements these operation rules:

Class Vector {constructor (x, y) {this.x = x; this.y = y;} / * Vector addition * @ param {Vector} v * / add (v) {return new Vector (this.x + v.x, this.y + v.y) } / * param {Vector} v * / substract (v) {return new Vector (this.x-v.x, this.y-v.y);} / * Vector and scalar multiplication * @ param {Vector} s * / multiply (s) {return new Vector (this.x * s, this.y * s) * @ param {Vector} v * / dot (v) {return this.x * v.x + this.y * v.y;} / * Vector normalization (excluding length) * @ param {number} distance * / normalize () {let distance = Math.sqrt (this.x * this.x + this.y * this.y) Return new Vector (this.x / distance, this.y / distance);}}

There is no special syntax or operation in the code, so I won't repeat it here. Let's take a look at the collision problem of small balls.

Collision treatment

The most important part of collision processing is to calculate the speed and direction after collision. Usually the simplest collision problem is the collision of two objects on the same horizontal plane, which is called one-dimensional collision, because only the velocity in the same direction needs to be calculated, and our current program ball is moving in a two-dimensional plane. the probability of frontal collision between balls is very small (that is, in the same direction of motion), most of them are oblique collisions (shoulder-to-shoulder collisions in different directions). It is necessary to calculate the velocity and direction in both horizontal and vertical directions, which belongs to the problem of two-dimensional collision. However, in fact, in the collision between small balls, there is only a force on the centroid (the connection of the two circles), but there is no force in the tangent direction of the collision contact, then we only need to know the velocity change in the direction of the concentric line. this translates into an one-dimensional collision.

When calculating the velocity after collision, obey the law of conservation of momentum and the law of conservation of kinetic energy. The formulas are as follows:

Law of conservation of momentum

Law of conservation of kinetic energy

M1 and m2 are the masses of the two balls, v1 and v2 are the velocity vectors before the collision, and v1' and v2' are the velocity vectors after the collision. According to these two formulas, the velocity formula after the collision of two small balls can be deduced.

If the mass of the ball is not considered, or the mass is the same, it is actually the exchange of speed between the two balls, that is:

Here, we add mass to the ball, and then apply the formula to calculate the speed of the ball after collision. First, add the mass mass attribute to the ball in the Circle class:

Class Circle {constructor (context, x, y, r, vx, vy, mass = 1) {/ / other codes this.mass = mass;}}

Then, at the initialization ball of the Gameboard class, add mass to each ball:

This.circles = [new Circle (ctx, 30,50,30,-100,390,30), new Circle (ctx, 60,180,20,180,275,20), new Circle (ctx, 120,100,60,120,262,100), new Circle (ctx, 150,180,10,-130,138,10), new Circle (ctx, 190,210,10,138,280,10), new Circle (ctx, 220,240,10,142,350,10) New Circle (ctx, 100,260,10,135,-460,10), new Circle (ctx, 120,285,10,-165,370,10), new Circle (ctx, 140,290,10,125,230,10), new Circle (ctx, 160,380,10), new Circle (ctx, 180,310,10,115,440,10), new Circle (ctx, 100,310,10,195,325,10), new Circle (ctx) 60,150,10,-138,420,10), new Circle (ctx, 70,430,45,135,-230,45), new Circle (ctx, 250,290,40,-140,335,40),]

Add the changeVelocityAndDirection (other) method to the Circle class to calculate the speed after the collision, which receives another small ball object as a parameter, and calculates the speed and direction of the collision thickness of the two balls, which is the core of the whole engine. Let's see how it is implemented bit by bit. First, the velocity of the two balls is expressed by the Vector vector:

ChangeVelocityAndDirection (other) {/ / create the velocity vector of two balls let velocity1 = new Vector (this.vx, this.vy); let velocity2 = new Vector (other.vx, other.vy);}

Because we already use vx and vy to represent the horizontal and vertical velocity vectors, we can pass them directly to the constructor of Vector. Velocity1 and velocity2 represent the velocity vectors of the current ball and the collision ball, respectively.

Next, we get the vector of the direction of the centroid, that is, the difference between the coordinates of the two centers:

Let vNorm = new Vector (this.x-other.x, this.y-other.y)

Next, get the unit vector in the direction of the centroid and the unit vector in the tangent direction. These unit vectors represent the direction of the centroid and tangent:

Let unitVNorm = vNorm.normalize (); let unitVTan = new Vector (- unitVNorm.y, unitVNorm.x)

UnitVNorm is the unit vector of the centroid direction, and unitVTan is the unit vector of the tangent direction. The tangent direction actually exchanges the x and y coordinates of the concentric vector and reverses the y coordinates. Based on these two unit vectors, point multiplication is used to calculate the projection of the ball velocity in these two directions:

Let v1n = velocity1.dot (unitVNorm); let v1t = velocity1.dot (unitVTan); let v2n = velocity2.dot (unitVNorm); let v2t = velocity2.dot (unitVTan)

The result of the calculation is a scalar, that is, the value of velocity without direction. V1n and V1T represent the current velocity of the ball in the centroid and tangent direction, while V2n and V2t represent the velocity of the collision ball. After calculating the velocity values of the two balls, we have the variable values needed for the velocity formula after the collision, and apply the formula directly to the code:

Let v1nAfter = (v1n * (this.mass-other.mass) + 2 * other.mass * V2n) / (this.mass + other.mass); let v2nAfter = (v2n * (other.mass-this.mass) + 2 * this.mass * V1n) / (this.mass + other.mass)

V1nAfter and v2nAfter are the velocities of the two balls after the collision, respectively. Now you can judge that if v1nAfter is less than v2nAfter, the first and second balls will be farther and farther away, so you don't have to deal with the collision:

If (v1nAfter

< v2nAfter) { return;} 然后再给碰撞后的速度加上方向,计算在连心线方向和切线方向上的速度,只需要让速度标量跟连心线单位向量和切线单位向量相乘: let v1VectorNorm = unitVNorm.multiply(v1nAfter);let v1VectorTan = unitVTan.multiply(v1t);let v2VectorNorm = unitVNorm.multiply(v2nAfter);let v2VectorTan = unitVTan.multiply(v2t); 这样有了两个小球连心线上的新速度向量和切线方向上的新速度向量,最后把连心线上的速度向量和切线方向的速度向量进行加法操作,就能获得碰撞后小球的速度向量: let velocity1After = v1VectorNorm.add(v1VectorTan);let velocity2After = v2VectorNorm.add(v2VectorTan); 之后我们把向量中的 x 和 y 分别还原到小球的 vx 和 vy 属性中: this.vx = velocity1After.x;this.vy = velocity1After.y;other.vx = velocity2After.x;other.vy = velocity2After.y; 最后在 checkCollideWith() 方法的 if 语句中调用此方法,即在检测到碰撞时: checkCollideWith(other) { if (this.isCircleCollided(other)) { this.colliding = true; other.colliding = true; this.changeVelocityAndDirection(other); // 在这里调用 }} 这时,小球的碰撞效果就实现了。 非弹性碰撞 现在小球之间的碰撞属于完全弹性碰撞,即碰撞之后不会有能量损失,这样小球永远不会停止运动,我们可以让小球在碰撞之后损失一点能量,来模拟更真实的物理效果。要让小球碰撞后有能量损失,可以使用恢复系数,它是一个取值范围为 0 到 1 的数值,每次碰撞后,乘以它就可以减慢速度,如果恢复系数为 1 则为完全弹性碰撞,为 0 则是完全非弹性碰撞,之间的数值为非弹性碰撞,现实生活中的碰撞都是非弹性碰撞。 先看一下边界碰撞,这个比较简单,假设边界的恢复系数为 0.8,然后在每次对速度取反的时候乘以它就可以了,把 Gameboard checkEdgeCollision()方法作如下改动: checkEdgeCollision() { const cor = 0.8; // 设置恢复系统 this.circles.forEach((circle) =>

{/ / left and right walls collide with if (circle.x

< circle.r) { circle.vx = -circle.vx * cor; // 加上恢复系数 circle.x = circle.r; } else if (circle.x >

Width-circle.r) {circle.vx =-circle.vx * cor; / / plus recovery factor circle.x = width-circle.r;} / / collision between the upper and lower walls if (circle.y

< circle.r) { circle.vy = -circle.vy * cor; // 加上恢复系数 circle.y = circle.r; } else if (circle.y >

Height-circle.r) {circle.vy =-circle.vy * cor; / / plus recovery factor circle.y = height-circle.r;}});}

Next, set the recovery coefficient of the ball, add a recovery coefficient cor attribute to the Circle class, and each ball can set a different value to make them have different elasticity, and then set a random recovery coefficient when initializing the ball:

Class Circle {constructor (context, x, y, r, vx, vy, mass = 1, cor = 1) {/ / other code this.cor = cor }} class Gameboard {init () {this.circles = [new Circle (ctx, 30,50,30,-100,390,30,0.7), new Circle (ctx, 60,180,20,180,-275,20,0.7), new Circle (ctx, 120,100,60,120,262,100,0.3), new Circle (ctx, 150,180,10,-130,138,10,0.7), new Circle (ctx) 190,210,10,138,-280,10,0.7), new Circle (ctx, 220,240,10,142,350,10,0.7), new Circle (ctx, 100,260,10,135,-460,10,0.7), new Circle (ctx, 120,285,10,-165,370,10,0.7), new Circle (ctx, 140,290,10,125,230,100.7), new Circle (ctx) 160,380,10,0.7), new Circle (ctx, 180,310,10,115,440,10,0.7), new Circle (ctx, 100,310,10,195,-325,10,0.7), new Circle (ctx, 60,150,10,-138,420,10,0.7), new Circle (ctx, 70,430,45,135,230,45,0.7) New Circle (ctx, 250,290,40,-140,335,40,0.7),] }}

After adding the recovery coefficient, the velocity calculation after the collision of the ball also needs to be changed. You can simply multiply v1nAfter and v2nAfter by the recovery coefficient of the ball, or you can use the velocity formula with the recovery coefficient.

Then convert the formula to code, and in the changeVelocityAndDirection () method of the Circle class, replace the calculation formulas of v1nAfter and v2nAfter:

Let cor = Math.min (this.cor, other.cor); let v1nAfter = (this.mass * v1n + other.mass * v2n + cor * other.mass * (v2n-V1n)) / (this.mass + other.mass); let v2nAfter = (this.mass * v1n + other.mass * v2n + cor * this.mass * (v1n-V2n)) / (this.mass + other.mass)

It should be noted here that when two small balls collide, the recovery coefficient should be the minimum of both. According to common sense, the less elastic one will have the same effect whether it is to hit others or others to hit it. Now the speed of the ball will slow down after the collision, but it is still a little short, we can add gravity to let the ball fall naturally.

Gravity force

It is relatively simple to add gravity. First, define the gravity acceleration constant globally, and then when the ball updates the vertical velocity, the cumulative gravity acceleration is fine:

Const gravity = 980 seconds; this.y Circle {update (seconds) {this.vy + = gravity * seconds; / / Gravity acceleration this.x + = this.vx * seconds; this.y + = this.vy * seconds;}}

The acceleration of gravity is about, but because our canvas is in pixels, using 9.8 will look like there is no gravity, or it will look like a ball from a distance. At this time, the acceleration of gravity can be magnified by a certain multiple to achieve a more realistic effect.

Read here, this "how to achieve collision physics engine JavaScript" article has been introduced, want to master the knowledge of this article also need to practice and use in order to understand, if you want to know more related articles, welcome to follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report