Skip to content

Latest commit

 

History

History
286 lines (225 loc) · 7.11 KB

level-6-ball-spring-collisions.md

File metadata and controls

286 lines (225 loc) · 7.11 KB

goal

  • The same as in level 4, but using spring collisions and having more accuracy when multiple balls collide simulatenously (apparent after the kick-off at the beginning).
    • Simulate the motion of multiple balls.
    • There is no gravity, our simulation may be interpreted as a top-down view on a billiard table.
    • Collisions can happen with all the walls, and between each of the balls.
    • All balls, except one, are initially stationary.

spring collisions for ball-ball collisions

  • The spring collisions for ball-ball collisions work exactly like the spring collisions when a ball collides with a wall (level 5).

  • The deformation process is modeled by a spring that sits between the two balls with initial length 0 and which is extended when the balls bump deeper into each other.

    level-6-collision-diagram-(1)
    • The extended spring then deaccelerates both balls until they have the same velocity and then pulls them out of each other again, by applying an opposite but equal force on both that is proportional to its extension length, according to Hooke's Law.

equations

$$ \text{--------- constants ---------} $$

$$ \begin{aligned} \text{\hspace{50pt}} w &= \text{const.}\text{\small\color{Gray}\hspace{14pt}(width of the scene)}\\ h &= \text{const.}\text{\small\color{Gray}\hspace{14pt}(height of the scene)}\\ k &= \text{const.}\text{\small\color{Gray}\hspace{14pt}(spring stiffness)}\[14pt] \end{aligned} $$

$$ \text{--------- ball-ball collisions ---------} $$

$$ \text{\small\color{Gray} (for every pair of balls i and j ...)} $$

level-6-collision-diagram-(2)

$$ \begin{aligned} d_x &= x_j - x_i\\ d_y &= y_j - y_i\\ d &= \sqrt{d_x^{,2} + d_y^{,2}} + 0.000001 \quad\begin{gathered}\text{\small\color{Gray}(prevent division}\[-4pt] \text{\small\color{Gray}with zero later)}\end{gathered}\\ s &= r_i + r_j - d\\ \end{aligned} $$

$$ \begin{gathered} \text{collision condition:\hspace{12pt}} 0 < s\[8pt] \end{gathered} $$

$$ \text{\small\color{Gray} (force on ball j)} $$

$$ \begin{aligned} F'{j,x,i} &= \begin{cases} s \cdot k \cdot \dfrac{d_x}{d}, & \text{if collision}\ 0, & \text{otherwise} \end{cases}\[16pt] F'{j,y,i} &= \begin{cases} s \cdot k \cdot \dfrac{d_y}{d}, & \text{if collision}\ 0, & \text{otherwise} \end{cases}\[18pt] \end{aligned} $$

$$ \text{\small\color{Gray} (force on ball i)} $$

$$ \begin{aligned} F'{i,x,j} &= - F'{j,x,i}\ F'{i,y,j} &= - F'{j,y,i}\[10pt] \end{aligned} $$

$$ \text{\small\color{Gray} (for every ball i ...)} $$

$$ \begin{aligned} F'{i,x} &= \sum{\text{other balls } j}F'{i,x,j}\[12pt] F'{i,y} &= \sum_{\text{other balls } j}F'_{i,y,j}\[28pt] \end{aligned} $$

$$ \text{--------- ball-wall collisions ---------} $$

$$ \text{\small\color{Gray} (for every ball i ...)} $$

$$ \text{\small\color{Gray} (left and right wall)} $$

$$ \begin{aligned} F''{i,x} = \begin{cases} F'{i,x} + (r_i-x_i) \cdot k, & \text{if}\quad 0 < r_i-x_i\ F'{i,x} - (x_i+r_i-w) \cdot k,\quad & \text{if}\quad 0 < x_i+r_i-w\ F'{i,x}, & \text{otherwise} \end{cases}\[24pt] \end{aligned} $$

$$ \text{\small\color{Gray} (top and bottom wall)} $$

$$ \begin{aligned} F''{i,y} = \begin{cases} F'{i,y} + (r_i-y_i) \cdot k, &\text{if}\quad 0 < r_i-y_i\ F'{i,y} - (y_i+r_i-h) \cdot k,\quad & \text{if}\quad 0 < y_i+r_i-h\ F'{i,y}, & \text{otherwise} \end{cases}\[24pt] \end{aligned} $$

$$ \text{--------- time step ---------} $$

$$ \text{\small\color{Gray} (for every ball i ...)} $$

$$ \text{\small\color{Gray} (new acceleration, which is constant during the time step)} $$

$$ \begin{aligned} a'{i,x} &= \frac{F''{i,x}}{m}\[8pt] a'{i,y} &= \frac{F''{i,y}}{m}\[8pt] \end{aligned} $$

$$ \text{\small\color{Gray} (new velocity after the time step)} $$

$$ \begin{aligned} v'{i,x} &= v{i,x} + dv_{i,x} & &\leftarrow & dv_{i,x} &= dt \cdot a'{i,x}\[4pt] v'{i,y} &= v_{i,y} + dv_{i,y} & &\leftarrow & dv_{i,y} &= dt \cdot a'_{i,y}\[8pt] \end{aligned} $$

$$ \text{\small\color{Gray} (new position, using the new velocity)} $$

$$ \begin{aligned} x'i &= x_i + dx_i & &\leftarrow & dx_i &= dt \cdot v'{i,x}\[4pt] y'i &= y_i + dy_i & &\leftarrow & dy_i &= dt \cdot v'{i,y}\[14pt] \end{aligned} $$


code equivalent

const balls = [
    {
        x: 30,  // at the left
        y: 0.5 * canvas.h,  // vertically centered
        v_x: 10,  // moving straight to the right
        v_y: 0,   //
        m: 1,
        r: 15,
        color: '#E91E63',
    },
    {
        x: canvas.w - 50,  // at the right
        y: 0.5 * canvas.h,  // vertically centered
        v_x: 0,  // initially stationary
        v_y: 0,  //
        m: 1,
        r: 15,
        color: '#00BCD4',
    },

    // ...

];

const k = 5;  // spring stiffness

function simulateOneStep(dt) {

    for (let ball of balls) {
        ball.F_x = ball.F_y = 0;  // reset/initialize
    }

    forEachPair(balls, (i, j) => {
        const d_x = i.x - j.x;
        const d_y = i.y - j.y;
        const d = Math.sqrt(d_x ** 2 + d_y ** 2) + 0.000001;  // '+0.000001' prevents division with zero later
        const s = i.r + j.r - d;
        if (0 < s) {
            i.F_x += s * k * (d_x / d);
            i.F_y += s * k * (d_y / d);
            j.F_x -= s * k * (d_x / d);
            j.F_y -= s * k * (d_y / d);
        }
    });
    for (let ball of balls) {
        if (ball.x - ball.r < 0) {
            ball.F_x -= (ball.x - ball.r) * k;
        }
        if (ball.x + ball.r - canvas.w > 0) {
            ball.F_x -= (ball.x + ball.r - canvas.w) * k;
        }
        if (ball.y - ball.r < 0) {
            ball.F_y -= (ball.y - ball.r) * k;
        }
        if (ball.y + ball.r - canvas.h > 0) {
            ball.F_y -= (ball.y + ball.r - canvas.h) * k;
        }
    }

    for (let ball of balls) {
        const a_x = ball.F_x / ball.m;
        const a_y = ball.F_y / ball.m;
        ball.v_x += dt * a_x;
        ball.v_y += dt * a_y;
        ball.x += dt * ball.v_x;
        ball.y += dt * ball.v_y;
    }
}

function forEachPair(array, callback) {
    for (let i = 0; i < array.length; i++) {  // loop every item
        for (let j = i + 1; j < array.length; j++) { // loop every item after the current item
            callback(array[i], array[j], i, j);
        }
    }
}

discussion of the time step equations

  • See level 5.

working example

Code Code Live