Instantly share code, notes, and snippets.

Last active June 17, 2024 07:27
Show Gist options
• Save joshuabradley012/bd2bc96bbe1909ca8555a792d6a36e04 to your computer and use it in GitHub Desktop.
An example of 2D collisions using JavaScript Canvas
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

### GMartigny commented Aug 1, 2020

Hi,
I liked reading your article. It's well explained and has some real interesting detail. Your code is squeaky clean !
I too have done a lot of animation with `<canvas>` and I though I will share with you what I learned too.

The elephant in the room is the collision. Of course, it's the most difficult part. Lots of your issues comes from Euler physics (adding speed to position each loop) and can be solved with Verlet integration. It's more complex, but a lot more stable.

Objects have a "position" and a "previous position" properties. Each frame, you move an object by the difference between the two. The magic trick is, you just need to change the "position" to change the velocity.
In case of collision, both particles repeal each other by the distance they overlap multiplied by some ratio.
Check out this pen I made using this technique.

Finally, I would say that immutability is a great thing, but not always the best solution. Here, you're using a lot of memory by duplicating your objects each time you do any operation. I don't have any definitive answer. With a small amount of particles on an decent computer it shouldn't matter anyway.

`<canvas>` are awesome and you figured out all you need to know to do any 2D animation scene. Keep at it.

### cyrilf commented Aug 13, 2020

Thanks! 👏
I really appreciate your article. 👌

There is a small typo left. Here's how to fix it.

• Solution 1:
```-const collidingBalls = ({ width = 400, height = 400, parent = document.body, count = 50 }) => {
+const collidingBalls = ({ width = 400, height = 400, parent = document.body, count = 50 } = {}) => {```
• Solution 2:
```-collidingBalls();
+collidingBalls({});```

Cool

### joshuabradley012 commented Oct 12, 2020 • edited

@GMartigny thank you so much for the kind words and advice! I will certainly be looking into Vertlet Integration and how it can improve my solution.

@cyrilf I'm not sure I see the mistake? The code works correctly as far as I can tell, what error are you solving for?

### cyrilf commented Oct 13, 2020

@joshuabradley012 if I copy/paste your gist into a codepen the following error appears: `Uncaught TypeError: Cannot read property 'width' of undefined` (line 219).
It is due to the fact that the function `collidingBalls` is expecting an object as an argument but got undefined (so the deconstructing is failing).That's what my two solutions above are trying to solve.

### joshuabradley012 commented Oct 13, 2020

@cyrilf got it! Thank you. Updating now.

### StarTraX commented Dec 9, 2022 • edited

I found your site when searching for code that I could modify to simulate gas molecules impacting a rough surface for a research project. It's brilliant, but....
After a few minutes running the average speed of the balls starts to increase, and fairly soon goes ballistic. This is a bit of a show-stopper for me as I will need it to run in a stable way for tens of minutes. I assume the issue derives from rounding errors, which will be pretty hard to trace, but I wonder if you have addressed this issue and maybe have a remedy?
PS, I'm running on a Mac in Safari and Chrome.

### joshuabradley012 commented Apr 20, 2023

@StarTraX I've noticed the same issue. I also believe it derives from rounding errors, but I've noticed it runs differently on different OSs as well, so there may be a frame timing issue.

I have not addressed this issue, unfortunately.

### kelvinpraises commented Jan 26, 2024

@StarTraX and @joshuabradley012, it seems that whenever the mass multiplier evaluates to anything greater than 1, it adds entropy and speed into the system. So, putting the multiplier under 1 reduces both the randomness and acceleration.