如何对齐4个圆圈
How to align 4 circles
我正在尝试对齐这 4 个圆圈(顶部 2 个圆圈低于那个 2 个圆圈)。我尝试更改它失败的边距样式,它正在垂直创建 4 个圆圈。我需要在顶部下方有 2 个圆圈,2 个圆圈应该在网页的右侧。任何人都可以帮助如何水平对齐这 4 个圆圈 2*2。
const ctx = document.getElementById("Canvas").getContext("2d");
const ctx2 = document.getElementById("Canvas2").getContext("2d");
const ctx3 = document.getElementById("Canvas3").getContext("2d");
const ctx4 = document.getElementById("Canvas4").getContext("2d");
const containerR = 80;
const size = containerR * 2
ctx.canvas.width = ctx.canvas.height = size;
ctx2.canvas.width = ctx2.canvas.height = size;
ctx3.canvas.width = ctx3.canvas.height = size;
ctx4.canvas.width = ctx4.canvas.height = size;
ctx.globalAlpha = 0.6;
ctx2.globalAlpha = 0.8;
ctx3.globalAlpha = 0.8;
ctx4.globalAlpha = 0.8;
const getBall = (x, y, dx, dy, r, color) => ({x, y, dx, dy, r, color});
const balls = [
getBall(size / 2, size - 30, -0.1, -0.1, 4, "Green"),
getBall(size / 3, size - 50, 0.1, 0.1, 4, "Green"),
getBall(size / 4, size - 60, -0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, -0.1, 4, "Green"),
];
const drawBall = (ball) => {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx.fillStyle = ball.collider ? "red" : ball.color;
ctx.fill();
ctx.closePath();
ctx2.beginPath();
ctx2.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx2.fillStyle = ball.collider ? "red" : ball.color;
ctx2.fill();
ctx2.closePath();
ctx3.beginPath();
ctx3.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx3.fillStyle = ball.collider ? "red" : ball.color;
ctx3.fill();
ctx3.closePath();
ctx4.beginPath();
ctx4.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx4.fillStyle = ball.collider ? "red" : ball.color;
ctx4.fill();
ctx4.closePath();
}
const updatePos = (ball) => {
ball.x += ball.dx;
ball.y += ball.dy;
const dx = ball.x - containerR;
const dy = ball.y - containerR;
if (Math.sqrt(dx * dx + dy * dy) >= containerR - ball.r) {
const v = Math.sqrt(ball.dx * ball.dx + ball.dy * ball.dy);
const angleToCollisionPoint = Math.atan2(-dy, dx);
const oldAngle = Math.atan2(-ball.dy, ball.dx);
const newAngle = 2 * angleToCollisionPoint - oldAngle;
ball.dx = -v * Math.cos(newAngle);
ball.dy = v * Math.sin(newAngle);
}
}
const collides = (a, b) => (Math.hypot(Math.abs(a.x - b.x), Math.abs(a.y - b.y)) < (a.r + b.r));
function engine() {
//console.clear(); // Clear console test messages
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx2.clearRect(0, 0, ctx2.canvas.width, ctx2.canvas.height);
ctx3.clearRect(0, 0, ctx3.canvas.width, ctx3.canvas.height);
ctx4.clearRect(0, 0, ctx4.canvas.width, ctx4.canvas.height);
balls.forEach((a, ai) => {
a.collider = undefined;
balls.forEach((b, bi) => {
if (bi === ai) return; // Don't look at self
if (collides(a, b)) a.collider = b; // Store the colliding B ball
});
updatePos(a);
drawBall(a);
});
requestAnimationFrame(engine);
}
engine();
<canvas id="Canvas"
style = "background: #eee;
margin-top: 5%;
margin-left: 60%;
border-radius: 50%;
box-shadow: 0 0 0 4px #000;
align-content: right;"></canvas>
<canvas id ="Canvas2"
style = "background: #eee;
margin-top: 8%;
margin-left: 60%;
border-radius: 50%;
box-shadow: 0 0 0 4px #000;
align-content: right;"></canvas>
<canvas id ="Canvas3"
style = "background: #eee;
margin-top: 6%;
margin-left: 75%;
border-radius: 50%;
box-shadow: 0 0 0 4px #000;
align-content: right;"></canvas>
<canvas id ="Canvas4"
style = "background: #eee;
margin-top: 6%;
margin-left: 75%;
margin-bottom: 50%;
border-radius: 50%;
box-shadow: 0 0 0 4px #000;
align-content: right;"></canvas>
我建议将您的样式移动到 CSS 以减少重复的样式。
例如:
const ctx = document.getElementById("Canvas").getContext("2d");
const ctx2 = document.getElementById("Canvas2").getContext("2d");
const ctx3 = document.getElementById("Canvas3").getContext("2d");
const ctx4 = document.getElementById("Canvas4").getContext("2d");
const containerR = 80;
const size = containerR * 2
ctx.canvas.width = ctx.canvas.height = size;
ctx2.canvas.width = ctx2.canvas.height = size;
ctx3.canvas.width = ctx3.canvas.height = size;
ctx4.canvas.width = ctx4.canvas.height = size;
ctx.globalAlpha = 0.6;
ctx2.globalAlpha = 0.8;
ctx3.globalAlpha = 0.8;
ctx4.globalAlpha = 0.8;
const getBall = (x, y, dx, dy, r, color) => ({x, y, dx, dy, r, color});
const balls = [
getBall(size / 2, size - 30, -0.1, -0.1, 4, "Green"),
getBall(size / 3, size - 50, 0.1, 0.1, 4, "Green"),
getBall(size / 4, size - 60, -0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, -0.1, 4, "Green"),
];
const drawBall = (ball) => {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx.fillStyle = ball.collider ? "red" : ball.color;
ctx.fill();
ctx.closePath();
ctx2.beginPath();
ctx2.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx2.fillStyle = ball.collider ? "red" : ball.color;
ctx2.fill();
ctx2.closePath();
ctx3.beginPath();
ctx3.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx3.fillStyle = ball.collider ? "red" : ball.color;
ctx3.fill();
ctx3.closePath();
ctx4.beginPath();
ctx4.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx4.fillStyle = ball.collider ? "red" : ball.color;
ctx4.fill();
ctx4.closePath();
}
const updatePos = (ball) => {
ball.x += ball.dx;
ball.y += ball.dy;
const dx = ball.x - containerR;
const dy = ball.y - containerR;
if (Math.sqrt(dx * dx + dy * dy) >= containerR - ball.r) {
const v = Math.sqrt(ball.dx * ball.dx + ball.dy * ball.dy);
const angleToCollisionPoint = Math.atan2(-dy, dx);
const oldAngle = Math.atan2(-ball.dy, ball.dx);
const newAngle = 2 * angleToCollisionPoint - oldAngle;
ball.dx = -v * Math.cos(newAngle);
ball.dy = v * Math.sin(newAngle);
}
}
const collides = (a, b) => (Math.hypot(Math.abs(a.x - b.x), Math.abs(a.y - b.y)) < (a.r + b.r));
function engine() {
//console.clear(); // Clear console test messages
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx2.clearRect(0, 0, ctx2.canvas.width, ctx2.canvas.height);
ctx3.clearRect(0, 0, ctx3.canvas.width, ctx3.canvas.height);
ctx4.clearRect(0, 0, ctx4.canvas.width, ctx4.canvas.height);
balls.forEach((a, ai) => {
a.collider = undefined;
balls.forEach((b, bi) => {
if (bi === ai) return; // Don't look at self
if (collides(a, b)) a.collider = b; // Store the colliding B ball
});
updatePos(a);
drawBall(a);
});
requestAnimationFrame(engine);
}
engine();
.canvas-wrapper {
display: flex;
flex-wrap: wrap;
}
.canvas-wrapper div {
width: 50%;
margin-bottom: 10px;
}
.canvas-wrapper canvas {
background: #eee;
border-radius: 50%;
box-shadow: 0 0 0 4px #000;
max-width: 80%;
box-sizing: border-box;
}
<div class="canvas-wrapper">
<div><canvas id="Canvas"></canvas></div>
<div><canvas id ="Canvas2"></canvas></div>
<div><canvas id ="Canvas3"></canvas></div>
<div><canvas id ="Canvas4"></canvas></div>
</div>
为了对齐布局,我使用了一些 CSS flexbox 功能,在这些功能中,可以以所有可能的方式对齐它们。
在此处了解有关 flexbox 的更多信息:https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox 并查看我的示例以快速入门。
const ctx = document.getElementById("Canvas").getContext("2d");
const ctx2 = document.getElementById("Canvas2").getContext("2d");
const ctx3 = document.getElementById("Canvas3").getContext("2d");
const ctx4 = document.getElementById("Canvas4").getContext("2d");
const containerR = 80;
const size = containerR * 2
ctx.canvas.width = ctx.canvas.height = size;
ctx2.canvas.width = ctx2.canvas.height = size;
ctx3.canvas.width = ctx3.canvas.height = size;
ctx4.canvas.width = ctx4.canvas.height = size;
ctx.globalAlpha = 0.6;
ctx2.globalAlpha = 0.8;
ctx3.globalAlpha = 0.8;
ctx4.globalAlpha = 0.8;
const getBall = (x, y, dx, dy, r, color) => ({
x,
y,
dx,
dy,
r,
color
});
const balls = [
getBall(size / 2, size - 30, -0.1, -0.1, 4, "Green"),
getBall(size / 3, size - 50, 0.1, 0.1, 4, "Green"),
getBall(size / 4, size - 60, -0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, -0.1, 4, "Green"),
];
const drawBall = (ball) => {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx.fillStyle = ball.collider ? "red" : ball.color;
ctx.fill();
ctx.closePath();
ctx2.beginPath();
ctx2.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx2.fillStyle = ball.collider ? "red" : ball.color;
ctx2.fill();
ctx2.closePath();
ctx3.beginPath();
ctx3.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx3.fillStyle = ball.collider ? "red" : ball.color;
ctx3.fill();
ctx3.closePath();
ctx4.beginPath();
ctx4.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx4.fillStyle = ball.collider ? "red" : ball.color;
ctx4.fill();
ctx4.closePath();
}
const updatePos = (ball) => {
ball.x += ball.dx;
ball.y += ball.dy;
const dx = ball.x - containerR;
const dy = ball.y - containerR;
if (Math.sqrt(dx * dx + dy * dy) >= containerR - ball.r) {
const v = Math.sqrt(ball.dx * ball.dx + ball.dy * ball.dy);
const angleToCollisionPoint = Math.atan2(-dy, dx);
const oldAngle = Math.atan2(-ball.dy, ball.dx);
const newAngle = 2 * angleToCollisionPoint - oldAngle;
ball.dx = -v * Math.cos(newAngle);
ball.dy = v * Math.sin(newAngle);
}
}
const collides = (a, b) => (Math.hypot(Math.abs(a.x - b.x), Math.abs(a.y - b.y)) < (a.r + b.r));
function engine() {
//console.clear(); // Clear console test messages
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx2.clearRect(0, 0, ctx2.canvas.width, ctx2.canvas.height);
ctx3.clearRect(0, 0, ctx3.canvas.width, ctx3.canvas.height);
ctx4.clearRect(0, 0, ctx4.canvas.width, ctx4.canvas.height);
balls.forEach((a, ai) => {
a.collider = undefined;
balls.forEach((b, bi) => {
if (bi === ai) return; // Don't look at self
if (collides(a, b)) a.collider = b; // Store the colliding B ball
});
updatePos(a);
drawBall(a);
});
requestAnimationFrame(engine);
}
engine();
.row {
display: flex;
}
.container {
display: flex;
flex-direction: column;
}
#Canvas, #Canvas2, #Canvas3, #Canvas4 {
background: #eee;
border-radius: 50%;
border: solid 4px #000;
margin: 10px;
}
.canvas-holder {
display: flex;
flex-direction: column;
align-items: center;
}
<div class="container">
<div class="row">
<div class="canvas-holder">
<canvas id="Canvas"></canvas>
<span>Circle one</span>
</div>
<div class="canvas-holder">
<canvas id="Canvas2"></canvas>
<span>Circle two</span>
</div>
</div>
<div class="row">
<div class="canvas-holder">
<canvas id="Canvas3"></canvas>
<span>Circle tree</span>
</div>
<div class="canvas-holder">
<canvas id="Canvas4"></canvas>
<span>Circle four</span>
</div>
</div>
</div>
我正在尝试对齐这 4 个圆圈(顶部 2 个圆圈低于那个 2 个圆圈)。我尝试更改它失败的边距样式,它正在垂直创建 4 个圆圈。我需要在顶部下方有 2 个圆圈,2 个圆圈应该在网页的右侧。任何人都可以帮助如何水平对齐这 4 个圆圈 2*2。
const ctx = document.getElementById("Canvas").getContext("2d");
const ctx2 = document.getElementById("Canvas2").getContext("2d");
const ctx3 = document.getElementById("Canvas3").getContext("2d");
const ctx4 = document.getElementById("Canvas4").getContext("2d");
const containerR = 80;
const size = containerR * 2
ctx.canvas.width = ctx.canvas.height = size;
ctx2.canvas.width = ctx2.canvas.height = size;
ctx3.canvas.width = ctx3.canvas.height = size;
ctx4.canvas.width = ctx4.canvas.height = size;
ctx.globalAlpha = 0.6;
ctx2.globalAlpha = 0.8;
ctx3.globalAlpha = 0.8;
ctx4.globalAlpha = 0.8;
const getBall = (x, y, dx, dy, r, color) => ({x, y, dx, dy, r, color});
const balls = [
getBall(size / 2, size - 30, -0.1, -0.1, 4, "Green"),
getBall(size / 3, size - 50, 0.1, 0.1, 4, "Green"),
getBall(size / 4, size - 60, -0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, -0.1, 4, "Green"),
];
const drawBall = (ball) => {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx.fillStyle = ball.collider ? "red" : ball.color;
ctx.fill();
ctx.closePath();
ctx2.beginPath();
ctx2.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx2.fillStyle = ball.collider ? "red" : ball.color;
ctx2.fill();
ctx2.closePath();
ctx3.beginPath();
ctx3.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx3.fillStyle = ball.collider ? "red" : ball.color;
ctx3.fill();
ctx3.closePath();
ctx4.beginPath();
ctx4.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx4.fillStyle = ball.collider ? "red" : ball.color;
ctx4.fill();
ctx4.closePath();
}
const updatePos = (ball) => {
ball.x += ball.dx;
ball.y += ball.dy;
const dx = ball.x - containerR;
const dy = ball.y - containerR;
if (Math.sqrt(dx * dx + dy * dy) >= containerR - ball.r) {
const v = Math.sqrt(ball.dx * ball.dx + ball.dy * ball.dy);
const angleToCollisionPoint = Math.atan2(-dy, dx);
const oldAngle = Math.atan2(-ball.dy, ball.dx);
const newAngle = 2 * angleToCollisionPoint - oldAngle;
ball.dx = -v * Math.cos(newAngle);
ball.dy = v * Math.sin(newAngle);
}
}
const collides = (a, b) => (Math.hypot(Math.abs(a.x - b.x), Math.abs(a.y - b.y)) < (a.r + b.r));
function engine() {
//console.clear(); // Clear console test messages
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx2.clearRect(0, 0, ctx2.canvas.width, ctx2.canvas.height);
ctx3.clearRect(0, 0, ctx3.canvas.width, ctx3.canvas.height);
ctx4.clearRect(0, 0, ctx4.canvas.width, ctx4.canvas.height);
balls.forEach((a, ai) => {
a.collider = undefined;
balls.forEach((b, bi) => {
if (bi === ai) return; // Don't look at self
if (collides(a, b)) a.collider = b; // Store the colliding B ball
});
updatePos(a);
drawBall(a);
});
requestAnimationFrame(engine);
}
engine();
<canvas id="Canvas"
style = "background: #eee;
margin-top: 5%;
margin-left: 60%;
border-radius: 50%;
box-shadow: 0 0 0 4px #000;
align-content: right;"></canvas>
<canvas id ="Canvas2"
style = "background: #eee;
margin-top: 8%;
margin-left: 60%;
border-radius: 50%;
box-shadow: 0 0 0 4px #000;
align-content: right;"></canvas>
<canvas id ="Canvas3"
style = "background: #eee;
margin-top: 6%;
margin-left: 75%;
border-radius: 50%;
box-shadow: 0 0 0 4px #000;
align-content: right;"></canvas>
<canvas id ="Canvas4"
style = "background: #eee;
margin-top: 6%;
margin-left: 75%;
margin-bottom: 50%;
border-radius: 50%;
box-shadow: 0 0 0 4px #000;
align-content: right;"></canvas>
我建议将您的样式移动到 CSS 以减少重复的样式。
例如:
const ctx = document.getElementById("Canvas").getContext("2d");
const ctx2 = document.getElementById("Canvas2").getContext("2d");
const ctx3 = document.getElementById("Canvas3").getContext("2d");
const ctx4 = document.getElementById("Canvas4").getContext("2d");
const containerR = 80;
const size = containerR * 2
ctx.canvas.width = ctx.canvas.height = size;
ctx2.canvas.width = ctx2.canvas.height = size;
ctx3.canvas.width = ctx3.canvas.height = size;
ctx4.canvas.width = ctx4.canvas.height = size;
ctx.globalAlpha = 0.6;
ctx2.globalAlpha = 0.8;
ctx3.globalAlpha = 0.8;
ctx4.globalAlpha = 0.8;
const getBall = (x, y, dx, dy, r, color) => ({x, y, dx, dy, r, color});
const balls = [
getBall(size / 2, size - 30, -0.1, -0.1, 4, "Green"),
getBall(size / 3, size - 50, 0.1, 0.1, 4, "Green"),
getBall(size / 4, size - 60, -0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, -0.1, 4, "Green"),
];
const drawBall = (ball) => {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx.fillStyle = ball.collider ? "red" : ball.color;
ctx.fill();
ctx.closePath();
ctx2.beginPath();
ctx2.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx2.fillStyle = ball.collider ? "red" : ball.color;
ctx2.fill();
ctx2.closePath();
ctx3.beginPath();
ctx3.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx3.fillStyle = ball.collider ? "red" : ball.color;
ctx3.fill();
ctx3.closePath();
ctx4.beginPath();
ctx4.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx4.fillStyle = ball.collider ? "red" : ball.color;
ctx4.fill();
ctx4.closePath();
}
const updatePos = (ball) => {
ball.x += ball.dx;
ball.y += ball.dy;
const dx = ball.x - containerR;
const dy = ball.y - containerR;
if (Math.sqrt(dx * dx + dy * dy) >= containerR - ball.r) {
const v = Math.sqrt(ball.dx * ball.dx + ball.dy * ball.dy);
const angleToCollisionPoint = Math.atan2(-dy, dx);
const oldAngle = Math.atan2(-ball.dy, ball.dx);
const newAngle = 2 * angleToCollisionPoint - oldAngle;
ball.dx = -v * Math.cos(newAngle);
ball.dy = v * Math.sin(newAngle);
}
}
const collides = (a, b) => (Math.hypot(Math.abs(a.x - b.x), Math.abs(a.y - b.y)) < (a.r + b.r));
function engine() {
//console.clear(); // Clear console test messages
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx2.clearRect(0, 0, ctx2.canvas.width, ctx2.canvas.height);
ctx3.clearRect(0, 0, ctx3.canvas.width, ctx3.canvas.height);
ctx4.clearRect(0, 0, ctx4.canvas.width, ctx4.canvas.height);
balls.forEach((a, ai) => {
a.collider = undefined;
balls.forEach((b, bi) => {
if (bi === ai) return; // Don't look at self
if (collides(a, b)) a.collider = b; // Store the colliding B ball
});
updatePos(a);
drawBall(a);
});
requestAnimationFrame(engine);
}
engine();
.canvas-wrapper {
display: flex;
flex-wrap: wrap;
}
.canvas-wrapper div {
width: 50%;
margin-bottom: 10px;
}
.canvas-wrapper canvas {
background: #eee;
border-radius: 50%;
box-shadow: 0 0 0 4px #000;
max-width: 80%;
box-sizing: border-box;
}
<div class="canvas-wrapper">
<div><canvas id="Canvas"></canvas></div>
<div><canvas id ="Canvas2"></canvas></div>
<div><canvas id ="Canvas3"></canvas></div>
<div><canvas id ="Canvas4"></canvas></div>
</div>
为了对齐布局,我使用了一些 CSS flexbox 功能,在这些功能中,可以以所有可能的方式对齐它们。
在此处了解有关 flexbox 的更多信息:https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox 并查看我的示例以快速入门。
const ctx = document.getElementById("Canvas").getContext("2d");
const ctx2 = document.getElementById("Canvas2").getContext("2d");
const ctx3 = document.getElementById("Canvas3").getContext("2d");
const ctx4 = document.getElementById("Canvas4").getContext("2d");
const containerR = 80;
const size = containerR * 2
ctx.canvas.width = ctx.canvas.height = size;
ctx2.canvas.width = ctx2.canvas.height = size;
ctx3.canvas.width = ctx3.canvas.height = size;
ctx4.canvas.width = ctx4.canvas.height = size;
ctx.globalAlpha = 0.6;
ctx2.globalAlpha = 0.8;
ctx3.globalAlpha = 0.8;
ctx4.globalAlpha = 0.8;
const getBall = (x, y, dx, dy, r, color) => ({
x,
y,
dx,
dy,
r,
color
});
const balls = [
getBall(size / 2, size - 30, -0.1, -0.1, 4, "Green"),
getBall(size / 3, size - 50, 0.1, 0.1, 4, "Green"),
getBall(size / 4, size - 60, -0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, 0.1, 4, "Green"),
getBall(size / 2, size / 5, 0.1, -0.1, 4, "Green"),
];
const drawBall = (ball) => {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx.fillStyle = ball.collider ? "red" : ball.color;
ctx.fill();
ctx.closePath();
ctx2.beginPath();
ctx2.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx2.fillStyle = ball.collider ? "red" : ball.color;
ctx2.fill();
ctx2.closePath();
ctx3.beginPath();
ctx3.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx3.fillStyle = ball.collider ? "red" : ball.color;
ctx3.fill();
ctx3.closePath();
ctx4.beginPath();
ctx4.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
ctx4.fillStyle = ball.collider ? "red" : ball.color;
ctx4.fill();
ctx4.closePath();
}
const updatePos = (ball) => {
ball.x += ball.dx;
ball.y += ball.dy;
const dx = ball.x - containerR;
const dy = ball.y - containerR;
if (Math.sqrt(dx * dx + dy * dy) >= containerR - ball.r) {
const v = Math.sqrt(ball.dx * ball.dx + ball.dy * ball.dy);
const angleToCollisionPoint = Math.atan2(-dy, dx);
const oldAngle = Math.atan2(-ball.dy, ball.dx);
const newAngle = 2 * angleToCollisionPoint - oldAngle;
ball.dx = -v * Math.cos(newAngle);
ball.dy = v * Math.sin(newAngle);
}
}
const collides = (a, b) => (Math.hypot(Math.abs(a.x - b.x), Math.abs(a.y - b.y)) < (a.r + b.r));
function engine() {
//console.clear(); // Clear console test messages
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx2.clearRect(0, 0, ctx2.canvas.width, ctx2.canvas.height);
ctx3.clearRect(0, 0, ctx3.canvas.width, ctx3.canvas.height);
ctx4.clearRect(0, 0, ctx4.canvas.width, ctx4.canvas.height);
balls.forEach((a, ai) => {
a.collider = undefined;
balls.forEach((b, bi) => {
if (bi === ai) return; // Don't look at self
if (collides(a, b)) a.collider = b; // Store the colliding B ball
});
updatePos(a);
drawBall(a);
});
requestAnimationFrame(engine);
}
engine();
.row {
display: flex;
}
.container {
display: flex;
flex-direction: column;
}
#Canvas, #Canvas2, #Canvas3, #Canvas4 {
background: #eee;
border-radius: 50%;
border: solid 4px #000;
margin: 10px;
}
.canvas-holder {
display: flex;
flex-direction: column;
align-items: center;
}
<div class="container">
<div class="row">
<div class="canvas-holder">
<canvas id="Canvas"></canvas>
<span>Circle one</span>
</div>
<div class="canvas-holder">
<canvas id="Canvas2"></canvas>
<span>Circle two</span>
</div>
</div>
<div class="row">
<div class="canvas-holder">
<canvas id="Canvas3"></canvas>
<span>Circle tree</span>
</div>
<div class="canvas-holder">
<canvas id="Canvas4"></canvas>
<span>Circle four</span>
</div>
</div>
</div>