Sphere Collider
HTML
<canvas width="200" height="200" id="c"></canvas>
CSS
canvas {
border: 1px solid silver;
}
JavaScript
class Circle {
constructor(x, y, r, color="black") {
this.x = x;
this.y = y;
this.r = r;
this.color = color;
}
draw(ctx) {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0, 2*Math.PI);
ctx.fill();
}
}
class CircleCollider {
static collides(c1, c2) {
if (!(c1 instanceof Circle) ||Â !(c2 instanceof Circle)) {
return false;
}
const dx = c1.x - c2.x;
const dy = c1.y - c2.y;
return dx*dx + dy*dy <= (c1.r + c2.r)**2;
}
static block(circle, fixed) {
if (!CircleCollider.collides(circle, fixed)) {
return {x: circle.x, y: circle.y};
}
var dx = fixed.x - circle.x;
var dy = fixed.y - circle.y;
const len = Math.sqrt(dx**2 + dy**2);
dx /= len;
dy /= len;
return {
x: fixed.x - dx * (fixed.r + circle.r),
y: fixed.y - dy * (fixed.r + circle.r)
}
}
}
const ctx = c.getContext("2d");
const fixedCircles = [];
for (let i = 0; i < 5; i++) {
fixedCircles.push(new Circle(Math.random() * c.width, Math.random() * c.height, 15))
}
const mouseCircle = new Circle(0, 0, 10, "#f00");
function render() {
ctx.clearRect(0, 0, c.width, c.height);
for (const c of fixedCircles) {
c.draw(ctx);
}
mouseCircle.draw(ctx);
window.requestAnimationFrame(render);
}
window.requestAnimationFrame(render)
c.addEventListener('mousemove', (evt) => {
mouseCircle.x = evt.clientX - mouseCircle.r;
mouseCircle.y = evt.clientY - mouseCircle.r;
for (const fixed of fixedCircles) {
const blocked = CircleCollider.block(mouseCircle, fixed);
mouseCircle.x = blocked.x;
mouseCircle.y = blocked.y;
}
});