返回
JavaScript之多小球非对心弹性碰撞模拟
前端
2024-01-15 10:05:46
探索物理奥秘:用 JavaScript 模拟多球碰撞效果
物理模型的建立
当我们着手创造一个逼真的气泡屏保效果时,首先需要做的就是建立一个能够准确模拟小球碰撞物理行为的模型。物理模型的核心元素包括:
- 小球位置: 小球在空间中的 x、y 坐标。
- 小球速度: 表示小球沿 x 和 y 轴的运动速度。
- 小球质量: 反映小球的物质含量,影响碰撞时的能量传递。
碰撞规则的定义
小球碰撞是一个复杂的物理现象,涉及能量和动量的交换。为了在我们的模拟中捕捉到这种行为,我们需要定义一组碰撞规则。在本例中,我们将使用非对心弹性碰撞模型,这意味着小球在碰撞后会损失一些能量。
算法的制定
有了物理模型和碰撞规则后,我们就可以制定一个算法来模拟小球的运动。算法的核心思想是利用微积分来计算小球的位置和速度如何随时间变化。
JavaScript 代码的编写
最后,我们将算法转换为 JavaScript 代码,使用 HTML5 Canvas 元素来渲染小球。以下是代码示例:
// 定义小球类
class Ball {
constructor(x, y, radius, mass, velocity) {
this.x = x;
this.y = y;
this.radius = radius;
this.mass = mass;
this.velocity = velocity;
}
// 更新小球的位置和速度
update() {
this.x += this.velocity.x;
this.y += this.velocity.y;
}
// 绘制小球
draw(ctx) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
ctx.fillStyle = "#000";
ctx.fill();
}
}
// 定义画布元素
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
// 定义小球数组
const balls = [];
// 初始化小球
for (let i = 0; i < 10; i++) {
const x = Math.random() * canvas.width;
const y = Math.random() * canvas.height;
const radius = Math.random() * 10 + 5;
const mass = Math.random() * 10 + 5;
const velocity = { x: Math.random() * 10 - 5, y: Math.random() * 10 - 5 };
const ball = new Ball(x, y, radius, mass, velocity);
balls.push(ball);
}
// 动画循环
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 更新小球的位置和速度
for (let i = 0; i < balls.length; i++) {
balls[i].update();
}
// 检测小球之间的碰撞
for (let i = 0; i < balls.length - 1; i++) {
for (let j = i + 1; j < balls.length; j++) {
const ball1 = balls[i];
const ball2 = balls[j];
// 计算两个小球之间的距离
const dx = ball1.x - ball2.x;
const dy = ball1.y - ball2.y;
const distance = Math.sqrt(dx * dx + dy * dy);
// 如果两个小球之间的距离小于它们的半径之和,则发生碰撞
if (distance < ball1.radius + ball2.radius) {
// 计算两个小球之间的碰撞力
const force = (ball1.mass * ball2.mass) / (distance * distance);
// 计算两个小球之间的碰撞角
const angle = Math.atan2(dy, dx);
// 计算两个小球之间的碰撞速度
const velocity1 = {
x: ball1.velocity.x + force * Math.cos(angle),
y: ball1.velocity.y + force * Math.sin(angle)
};
const velocity2 = {
x: ball2.velocity.x - force * Math.cos(angle),
y: ball2.velocity.y - force * Math.sin(angle)
};
// 更新两个小球的速度
ball1.velocity = velocity1;
ball2.velocity = velocity2;
}
}
}
// 绘制小球
for (let i = 0; i < balls.length; i++) {
balls[i].draw(ctx);
}
// 请求下一次动画帧
requestAnimationFrame(animate);
}
// 启动动画循环
animate();
常见问题解答
1. 如何调整小球的数量和大小?
您可以在 for
循环中修改 10
值以调整小球的数量。要调整小球的大小,请修改 radius
值。
2. 如何更改小球的颜色?
在 draw
方法中,您可以更改 fillStyle
值以更改小球的颜色。
3. 如何使小球在屏幕边缘反弹?
要使小球在屏幕边缘反弹,需要在 update
方法中添加以下代码:
// 如果小球超出屏幕左边界,反弹
if (this.x < this.radius) {
this.velocity.x = -this.velocity.x;
}
// 如果小球超出屏幕右边界,反弹
if (this.x > canvas.width - this.radius) {
this.velocity.x = -this.velocity.x;
}
// 如果小球超出屏幕上边界,反弹
if (this.y < this.radius) {
this.velocity.y = -this.velocity.y;
}
// 如果小球超出屏幕下边界,反弹
if (this.y > canvas.height - this.radius) {
this.velocity.y = -this.velocity.y;
}
4. 如何使小球具有随机速度?
要在创建小球时赋予它们随机速度,请修改 velocity
值:
const velocity = { x: Math.random() * 10 - 5, y: Math.random() * 10 - 5 };
5. 如何使小球碰撞时发出声音?
要使小球碰撞时发出声音,请使用 HTML5 Audio 元素。例如:
// 创建一个 Audio 元素
const audio = new Audio("sound.mp3");
// 在碰撞检测后播放声音
if (distance < ball1.radius + ball2.radius) {
audio.play();
}