введение
изучениеJavaScript
когда вы видитепрактический пример, я подумал, можем ли мы сделать что-то вродеWindows
Эффект пузырей защиты экрана, после продолжительных размышлений и попыток, окончательный эффект выглядит следующим образом:
идеи
На самом деле описанный выше эффект заключается в моделировании нецентрального столкновения нескольких маленьких шариков в идеальной физической среде (центральное столкновение является частным случаем).Так называемая идеальная физическая ситуация представляет собой замкнутую систему без внешней силы, а интерьер подчиняется закону сохранения импульса и энергии, закону сохранения. гипотетический мячAи мячBКачество𝑀𝑎
а также𝑀𝖻
, начальные скорости равны𝑉𝑎
а также𝑉𝖻
, скорости после столкновения𝑉𝑎'
а также𝑉𝖻'
, состояние момента столкновения двух шаров следующее:
в𝑉𝑠𝑎
а также𝑉𝑠𝖻
- относительная скорость двух шаров вдоль линии, соединяющей центры шаров,𝑉𝑡𝑎
а также𝑉𝑡𝖻
скорость двух шаров в направлении, перпендикулярном центру шара. После столкновения, так как между двумя шариками нет силового взаимодействия в направлении, перпендикулярном центру шарика, скорость остается неизменной, или𝑉𝑡𝑎
а также𝑉𝑡𝖻
, скорость вдоль линии, соединяющей центр сферы, равна𝑉𝑠𝑎'
а также𝑉𝑠𝖻'
. Используйте следующие физические формулы:
Закон сохранения энергии:
𝑀𝑎•𝑉𝑎²/2+𝑀𝖻•𝑉𝖻²/2=𝑀𝑎•𝑉𝑎'²/2+𝑀𝖻•𝑉𝖻'²/2
Векторные операции:
𝑉𝑎²= 𝑉𝑠𝑎²+𝑉𝑡𝑎²
𝑉𝖻²= 𝑉𝑠𝖻²+𝑉𝑡𝖻²
𝑉𝑎'²= 𝑉𝑠𝑎'²+𝑉𝑡𝑎²
𝑉𝖻'² = 𝑉𝑠𝖻'² + 𝑉𝑡𝖻²
Делается вывод, что:
𝑀𝑎•𝑉𝑠𝑎²/2+𝑀𝖻•𝑉𝑠𝖻²/2=𝑀𝑎•𝑉𝑠𝑎'²/2+𝑀𝖻• 𝑉𝑠𝖻'²/2
Вернемся к закону сохранения импульса:
𝑀𝑎•𝑉𝑠𝑎+𝑀𝖻•𝑉𝑠𝖻=𝑀𝑎•𝑉𝑠𝑎'+𝑀𝖻•𝑉𝑠𝖻'
Делается вывод, что:
𝑉𝑠𝑎'=(𝑉𝑠𝑎•(𝑀𝑎-𝑀𝖻)+2•𝑀𝖻•𝑉𝑠𝖻)/(𝑀𝑎+𝑀𝖻)
𝑉𝑠𝖻 '= (𝑉𝑠𝖻 • (𝑀𝖻-𝑀𝑎) + 2 • 𝑀𝑎 • 𝑉𝑠𝑎) / (𝑀𝑎 + 𝑀𝖻)
Последняя скорость после синтеза столкновения𝑉𝑎'
а также𝑉𝖻'
Ничего страшного!
Код
// 小球对象构造函数
function Ball(x, y, speedX, speedY, color, radius, density) {
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
this.color = color;
this.radius = radius;
this.density = density;
}
// 绘制
Ball.prototype.draw = function () {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
ctx.fill();
}
// 边界碰撞检测
Ball.prototype.borderCollisionDetect = function () {
if ((this.x + this.radius) >= width && this.speedX > 0) {
this.speedX *= -1;
}
if ((this.x - this.radius) <= 0 && this.speedX < 0) {
this.speedX *= -1;
}
if ((this.y + this.radius) >= height && this.speedY > 0) {
this.speedY *= -1;
}
if ((this.y - this.radius) <= 0 && this.speedY < 0) {
this.speedY *= -1;
}
}
// 创建小球对象
function createBalls() {
require(['utils'], function (utils) {
while (balls.length < 8) {
var ball = new Ball(
utils.random(0, width), // x
utils.random(0, height), // y
utils.random(1, 8), // speedX
utils.random(1, 8), // speedY
'rgb('+utils.random(0, 255) +','+ utils.random(0, 255)+','+ utils.random(0, 255) +')',
30, // radius
1 // density
);
balls.push(ball);
}
});
}
// 更新小球速度和位置
function update() {
for (let i = 0; i < balls.length; i++) {
balls[i].borderCollisionDetect();
for (let j = i + 1; j < balls.length; j++) {
if (ballsCollisionDetect(balls[i], balls[j])) {
collide(balls[i], balls[j]);
}
}
// 更新位置
balls[i].x += balls[i].speedX;
balls[i].y += balls[i].speedY;
}
}
// 碰撞检测
function ballsCollisionDetect(ball1, ball2) {
// 当前距离
var dx = ball1.x - ball2.x;
var dy = ball1.y - ball2.y;
var distance = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
// 预测下一时刻会不会碰撞
let dx_next = ball1.x + ball1.speedX - ball2.x - ball2.speedX;
let dy_next = ball1.y + ball1.speedY - ball2.y - ball2.speedY;
let distance_next = Math.sqrt(Math.pow(dx_next, 2) + Math.pow(dy_next, 2));
if (distance_next < ball1.radius + ball2.radius && distance_next < distance) {
return true;
}
return false;
}
// 更新碰撞后的状态
function collide(ball1, ball2) {
require(['Vector2d'], function (Vector2d) {
// 初始速度向量
let speed_ball1_initial = new Vector2d(ball1.speedX, ball1.speedY);
let speed_ball2_initial = new Vector2d(ball2.speedX, ball2.speedY);
// 球心方向单位向量
let s = new Vector2d(ball2.x - ball1.x, ball2.y - ball1.y);
s = s.normalize();
// 垂直球心方向单位向量
let t = s.rotate(Math.PI / 2);
// 速度在球心向量上的分速度投影
let speed_ball1_initial_sc = speed_ball1_initial.dotProduct(s)/s.length();
let speed_ball2_initial_sc = speed_ball2_initial.dotProduct(s)/s.length();
// 速度在垂直球心向量上的分速度投影
let speed_ball1_initial_tc = speed_ball1_initial.dotProduct(t)/t.length();
let speed_ball2_initial_tc = speed_ball2_initial.dotProduct(t)/t.length();
// 碰撞后球心方向上的分速度
let speed_ball1_final_sc = (speed_ball1_initial_sc * (ball1.density * Math.pow(ball1.radius,3) - ball2.density * Math.pow(ball2.radius,3)) + 2 * (ball2.density * Math.pow(ball2.radius,3)) * speed_ball2_initial_sc)
/ (ball1.density * Math.pow(ball1.radius,3) + ball2.density * Math.pow(ball2.radius,3));
let speed_ball2_final_sc = (speed_ball2_initial_sc * (ball2.density * Math.pow(ball2.radius,3) - ball1.density * Math.pow(ball1.radius,3)) + 2 * (ball1.density * Math.pow(ball1.radius,3)) * speed_ball1_initial_sc)
/ (ball1.density * Math.pow(ball1.radius,3) + ball2.density * Math.pow(ball2.radius,3));
// 碰撞后球心方向上的分速度向量
let speed_ball1_final_s = s.scale(speed_ball1_final_sc);
let speed_ball2_final_s = s.scale(speed_ball2_final_sc);
// 碰撞后垂直球心方向上的分速度向量
let speed_ball1_final_t = t.scale(speed_ball1_initial_tc);
let speed_ball2_final_t = t.scale(speed_ball2_initial_tc);
// 结束速度向量
let speed_ball1_final = speed_ball1_final_s.add(speed_ball1_final_t);
let speed_ball2_final = speed_ball2_final_s.add(speed_ball2_final_t);
// 更新速度
ball1.speedX = speed_ball1_final.x;
ball1.speedY = speed_ball1_final.y;
ball2.speedX = speed_ball2_final.x;
ball2.speedY = speed_ball2_final.y;
});
}
дефект
Этот код черезwindow.requestAnimationFrame()
Метод выполняется в цикле для достижения эффекта анимации, а количество его обратных вызовов составляет 60 раз в секунду, поэтому для некоторых «слишком быстрых» шаров будет ситуация «столкновения малой частью» при ударе о границу. Кроме того, этот код рассматривает только случай столкновения двух шаров и не рассматривает сцену одновременного столкновения более трех шаров.
Эпилог
Этот код для обученияJavaScript
Настоящие боевые упражнения могут углубить понимание и овладение языком. Посмотреть полный кодАдрес GitHub.
Ссылка на ссылку
Woohoo. Используя blog.net/detail/397. …
Блог woohoo.cn on.com/Ken KO fox/AR…
Тина 0152.blog.163.com/blog/static…
51testing.com/HTML/66/you-8…