'Animate so that objects don't touch but repel?
I have a project I got from a tutorial. It consist of a loop that that places objects at different points on canvas using a spritsheet. I can figure most of the components but one thing I could not do is make sure that the bubbles don't touch each other, that is to make it repel once they touch or get close to one another.
Here is an example of when two objects are just crossing over each other:
as you can see the carrot is crossing over to the pink circle; is there way to make it repel instead? The play code is here:
https://codepen.io/ahdee/pen/abVyNRo
CSS
.bubble-wrap {
overflow: hidden;
height: 1600px;
}
.bubbles {
position: relative;
background: salmon;
}
.bubble {
position: absolute;
width: 152px;
height: 152px;
border-radius: 50%;
box-shadow:
0 15px 35px rgba(0, 0, 0, 0.1),
0 3px 10px rgba(0, 0, 0, 0.1);
background-image: url(https://www.dropbox.com/s/dok32aojteb42c9/logo-spritesheet.png?dl=1);
background-size: 1076px 1076px;
}
.logo1 { background-position: 0 0; }
.logo2 { background-position: -154px 0; }
.logo3 { background-position: -308px 0; }
.logo4 { background-position: -462px 0; }
.logo5 { background-position: -616px 0; }
.logo6 { background-position: -770px 0; }
.logo7 { background-position: -924px 0; }
.logo8 { background-position: 0 -154px; }
.logo9 { background-position: -154px -154px; }
.logo10 { background-position: -308px -154px; }
.logo11 { background-position: -462px -154px; }
.logo12 { background-position: -616px -154px; }
.logo13 { background-position: -770px -154px; }
.logo14 { background-position: -924px -154px; }
.logo15 { background-position: 0 -308px; }
.logo16 { background-position: -154px -308px; }
.logo17 { background-position: -308px -308px; }
.logo18 { background-position: -462px -308px; }
.logo19 { background-position: -616px -308px; }
.logo20 { background-position: -770px -308px; }
.logo21 { background-position: -924px -308px; }
.logo22 { background-position: 0 -462px; }
.logo23 { background-position: -154px -462px; }
.logo24 { background-position: -308px -462px; }
.logo25 { background-position: -462px -462px; }
.logo26 { background-position: -616px -462px; }
.logo27 { background-position: -770px -462px; }
.logo28 { background-position: -924px -462px; }
.logo29 { background-position: 0 -616px; }
.logo30 { background-position: -154px -616px; }
.logo31 { background-position: -308px -616px; }
.logo32 { background-position: -462px -616px; }
.logo33 { background-position: -616px -616px; }
body {
background: #E6EEF7;
}
JS
const SCROLL_SPEED = 0.02;
const NOISE_SPEED = 0.00014;
const NOISE_AMOUNT = 1000;
const CANVAS_WIDTH = 800;
const bubblesEl = document.querySelector('.bubbles');
const links = ["http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
, "http://www.example.com"
];
const bubbleSpecs = [
{ s: 1, x: 1134, y: 750 },
{ s: .6, x: 1620, y: 271 },
{ s: .6, x: 1761, y: 372 },
{ s: .6, x: 2499, y: 79 },
{ s: .6, x: 2704, y: 334 },
{ s: .6, x: 2271, y: 356 },
{ s: .6, x: 795, y: 226 },
{ s: .6, x: 276, y: 256 },
{ s: .6, x: 1210, y: 365 },
{ s: .6, x: 444, y: 193 },
{ s: .6, x: 2545, y: 387 },
{ s: .8, x: 1303, y: 193 },
{ s: .8, x: 907, y: 88 },
{ s: .8, x: 633, y: 320 },
{ s: .8, x: 323, y: 60 },
{ s: .8, x: 129, y: 357 },
{ s: .8, x: 1440, y: 342 },
{ s: .8, x: 1929, y: 293 },
{ s: .8, x: 2135, y: 198 },
{ s: .8, x: 2276, y: 82 },
{ s: .8, x: 2654, y: 182 },
{ s: .8, x: 2783, y: 60 },
{ x: 1519, y: 118 },
{ x: 1071, y: 233 },
{ x: 1773, y: 148 },
{ x: 2098, y: 385 },
{ x: 2423, y: 244 },
{ x: 901, y: 385 },
{ x: 624, y: 111 },
{ x: 75, y: 103 },
{ x: 413, y: 367 },
{ x: 2895, y: 271 },
{ x: 1990, y: 75 }
];
class Bubbles {
constructor(specs) {
this.bubbles = [];
specs.forEach((spec, index) => {
this.bubbles.push(new Bubble(index, spec));
})
requestAnimationFrame(this.update.bind(this));
}
update() {
this.bubbles.forEach(bubble => bubble.update());
this.raf = requestAnimationFrame(this.update.bind(this))
}
}
class Bubble {
constructor(index, {x, y, s = 1}) {
this.index = index;
this.x = x;
this.y = y;
this.scale = s;
this.noiseSeedX = Math.floor(Math.random() * 64000);
this.noiseSeedY = Math.floor(Math.random() * 64000);
this.link = document.createElement("a");
this.el = document.createElement("div");
this.el.className = `bubble logo${this.index + 1}`;
this.link.appendChild(this.el);
this.link.href = links[index];
this.link.target = '_blank';
bubblesEl.appendChild(this.link);
}
update() {
this.noiseSeedX += NOISE_SPEED;
this.noiseSeedY += NOISE_SPEED;
let randomX = noise.simplex2(this.noiseSeedX, 0);
let randomY = noise.simplex2(this.noiseSeedY, 0);
this.x -= SCROLL_SPEED;
this.xWithNoise = this.x + (randomX * NOISE_AMOUNT);
this.yWithNoise = this.y + (randomY * NOISE_AMOUNT)
if (this.x < -200) {
this.x = CANVAS_WIDTH;
}
this.el.style.transform = `translate(${this.xWithNoise}px, ${this.yWithNoise}px) scale(${this.scale})`;
}
}
// For perlin noise
noise.seed(Math.floor(Math.random() * 64000));
const bubbles = new Bubbles(bubbleSpecs);
html
<div class="bubble-wrap">
<div class="bubbles"></div>
</div>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|

