gpt4 book ai didi

javascript - 根据质量和弹跳系数计算球与球碰撞的速度和方向

转载 作者:太空狗 更新时间:2023-10-29 14:44:18 26 4
gpt4 key购买 nike

我根据 this 使用了以下代码

ballA.vx = (u1x * (m1 - m2) + 2 * m2 * u2x) / (m1 + m2);
ballA.vy = (u1y * (m1 - m2) + 2 * m2 * u2y) / (m1 + m2);

ballB.vx = (u2x * (m2 - m1) + 2 * m1 * u1x) / (m1 + m2);
ballB.vy = (u2y * (m2 - m1) + 2 * m1 * u1y) / (m1 + m2);

但它显然不太好,因为该公式是为一维碰撞设计的。

所以我尝试使用 this section 中的以下公式.

但问题是我不知道偏 Angular 是多少,也不知道怎么计算。另外,这个公式中如何考虑弹跳系数?

编辑:我可能没说清楚。上面的代码确实有效,尽管它可能不是预期的行为,因为原始公式是为一维碰撞设计的。因此,我正在尝试的问题是:

  • 什么是 2D 等价物?
  • 如何考虑反弹系数
  • 如何计算方向(用vxvy) 碰撞后的两个球?

最佳答案

我应该首先说:我创建了一个新答案,因为我觉得旧答案因其简单性而有值(value)

正如这里 promise 的那样,这是一个复杂得多的物理引擎,但我仍然觉得它很容易理解(希望如此!否则我只是浪费了我的时间......大声笑),(网址:http://jsbin.com/otipiv/edit#javascript,live)

function Vector(x, y) {
this.x = x;
this.y = y;
}

Vector.prototype.dot = function (v) {
return this.x * v.x + this.y * v.y;
};

Vector.prototype.length = function() {
return Math.sqrt(this.x * this.x + this.y * this.y);
};

Vector.prototype.normalize = function() {
var s = 1 / this.length();
this.x *= s;
this.y *= s;
return this;
};

Vector.prototype.multiply = function(s) {
return new Vector(this.x * s, this.y * s);
};

Vector.prototype.tx = function(v) {
this.x += v.x;
this.y += v.y;
return this;
};

function BallObject(elasticity, vx, vy) {
this.v = new Vector(vx || 0, vy || 0); // velocity: m/s^2
this.m = 10; // mass: kg
this.r = 15; // radius of obj
this.p = new Vector(0, 0); // position
this.cr = elasticity; // elasticity
}

BallObject.prototype.draw = function(ctx) {
ctx.beginPath();
ctx.arc(this.p.x, this.p.y, this.r, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
ctx.stroke();
};

BallObject.prototype.update = function(g, dt, ppm) {

this.v.y += g * dt;
this.p.x += this.v.x * dt * ppm;
this.p.y += this.v.y * dt * ppm;

};

BallObject.prototype.collide = function(obj) {

var dt, mT, v1, v2, cr, sm,
dn = new Vector(this.p.x - obj.p.x, this.p.y - obj.p.y),
sr = this.r + obj.r, // sum of radii
dx = dn.length(); // pre-normalized magnitude

if (dx > sr) {
return; // no collision
}

// sum the masses, normalize the collision vector and get its tangential
sm = this.m + obj.m;
dn.normalize();
dt = new Vector(dn.y, -dn.x);

// avoid double collisions by "un-deforming" balls (larger mass == less tx)
// this is susceptible to rounding errors, "jiggle" behavior and anti-gravity
// suspension of the object get into a strange state
mT = dn.multiply(this.r + obj.r - dx);
this.p.tx(mT.multiply(obj.m / sm));
obj.p.tx(mT.multiply(-this.m / sm));

// this interaction is strange, as the CR describes more than just
// the ball's bounce properties, it describes the level of conservation
// observed in a collision and to be "true" needs to describe, rigidity,
// elasticity, level of energy lost to deformation or adhesion, and crazy
// values (such as cr > 1 or cr < 0) for stange edge cases obviously not
// handled here (see: http://en.wikipedia.org/wiki/Coefficient_of_restitution)
// for now assume the ball with the least amount of elasticity describes the
// collision as a whole:
cr = Math.min(this.cr, obj.cr);

// cache the magnitude of the applicable component of the relevant velocity
v1 = dn.multiply(this.v.dot(dn)).length();
v2 = dn.multiply(obj.v.dot(dn)).length();

// maintain the unapplicatble component of the relevant velocity
// then apply the formula for inelastic collisions
this.v = dt.multiply(this.v.dot(dt));
this.v.tx(dn.multiply((cr * obj.m * (v2 - v1) + this.m * v1 + obj.m * v2) / sm));

// do this once for each object, since we are assuming collide will be called
// only once per "frame" and its also more effiecient for calculation cacheing
// purposes
obj.v = dt.multiply(obj.v.dot(dt));
obj.v.tx(dn.multiply((cr * this.m * (v1 - v2) + obj.m * v2 + this.m * v1) / sm));
};

function FloorObject(floor) {
var py;

this.v = new Vector(0, 0);
this.m = 5.9722 * Math.pow(10, 24);
this.r = 10000000;
this.p = new Vector(0, py = this.r + floor);
this.update = function() {
this.v.x = 0;
this.v.y = 0;
this.p.x = 0;
this.p.y = py;
};
// custom to minimize unnecessary filling:
this.draw = function(ctx) {
var c = ctx.canvas, s = ctx.scale;
ctx.fillRect(c.width / -2 / s, floor, ctx.canvas.width / s, (ctx.canvas.height / s) - floor);
};
}

FloorObject.prototype = new BallObject(1);

function createCanvasWithControls(objs) {
var addBall = function() { objs.unshift(new BallObject(els.value / 100, (Math.random() * 10) - 5, -20)); },
d = document,
c = d.createElement('canvas'),
b = d.createElement('button'),
els = d.createElement('input'),
clr = d.createElement('input'),
cnt = d.createElement('input'),
clrl = d.createElement('label'),
cntl = d.createElement('label');

b.innerHTML = 'add ball with elasticity: <span>0.70</span>';
b.onclick = addBall;

els.type = 'range';
els.min = 0;
els.max = 100;
els.step = 1;
els.value = 70;
els.style.display = 'block';
els.onchange = function() {
b.getElementsByTagName('span')[0].innerHTML = (this.value / 100).toFixed(2);
};

clr.type = cnt.type = 'checkbox';
clr.checked = cnt.checked = true;
clrl.style.display = cntl.style.display = 'block';

clrl.appendChild(clr);
clrl.appendChild(d.createTextNode('clear each frame'));

cntl.appendChild(cnt);
cntl.appendChild(d.createTextNode('continuous shower!'));

c.style.border = 'solid 1px #3369ff';
c.style.display = 'block';
c.width = 700;
c.height = 550;
c.shouldClear = function() { return clr.checked; };

d.body.appendChild(c);
d.body.appendChild(els);
d.body.appendChild(b);
d.body.appendChild(clrl);
d.body.appendChild(cntl);

setInterval(function() {
if (cnt.checked) {
addBall();
}
}, 333);

return c;
}

// start:
var objs = [],
c = createCanvasWithControls(objs),
ctx = c.getContext('2d'),
fps = 30, // target frames per second
ppm = 20, // pixels per meter
g = 9.8, // m/s^2 - acceleration due to gravity
t = new Date().getTime();

// add the floor:
objs.push(new FloorObject(c.height - 10));

// as expando so its accessible in draw [this overides .scale(x,y)]
ctx.scale = 0.5;
ctx.fillStyle = 'rgb(100,200,255)';
ctx.strokeStyle = 'rgb(33,69,233)';
ctx.transform(ctx.scale, 0, 0, ctx.scale, c.width / 2, c.height / 2);

setInterval(function() {

var i, j,
nw = c.width / ctx.scale,
nh = c.height / ctx.scale,
nt = new Date().getTime(),
dt = (nt - t) / 1000;

if (c.shouldClear()) {
ctx.clearRect(nw / -2, nh / -2, nw, nh);
}

for (i = 0; i < objs.length; i++) {

// if a ball > viewport width away from center remove it
while (objs[i].p.x < -nw || objs[i].p.x > nw) {
objs.splice(i, 1);
}

objs[i].update(g, dt, ppm, objs, i);

for (j = i + 1; j < objs.length; j++) {
objs[j].collide(objs[i]);
}

objs[i].draw(ctx);
}

t = nt;

}, 1000 / fps);

真正的“核心”和这个讨论的起源是 obj.collide(obj) 方法。

如果我们深入研究(我这次评论它是因为它比“上一个”复杂得多),您会看到这个等式:equation for inelastic collision , 仍然是这一行中唯一使用的:this.v.tx(dn.multiply((cr * obj.m * (v2 - v1) + this.m * v1 + obj.m * v2)/sm)); 现在我确定你还在说:“zomg wtf!那是同一个单维方程!” 但是当你停下来思考它时,“碰撞“只会发生在一个维度上。这就是为什么我们使用矢量方程来提取适用的组件,并将碰撞仅应用于那些特定的部分,而让其他部分保持不变以继续他们的快乐方式(忽略摩擦并简化碰撞以不考虑动态能量转换力,如在对 CR 的评论)。随着对象复杂性的增加和场景数据点数量的增加,这个概念显然变得更加复杂,以解决诸如畸形、旋转惯性、不均匀的质量分布和摩擦点等问题……但这远远超出了这个范围,它几乎不是值得一提..

基本上,您真正需要“掌握”的概念是 Vector 方程的基础知识(都位于 Vector 原型(prototype)中),它们如何与每个方程相互作用(归一化的实际含义,或获取点/标量积,例如阅读/与知识渊博的人交谈)以及对碰撞如何作用于物体属性(质量、速度等……再次阅读/与知识渊博的人交谈)的基本理解

希望对您有所帮助,祝您好运! -ck

关于javascript - 根据质量和弹跳系数计算球与球碰撞的速度和方向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9424459/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com