我是一个相当新的程序员,但是我试图在不使用任何库的情况下创建自己的物理引擎。这是一款行星际迷你高尔夫游戏。
我已经根据行星的密度和位置使重力正常工作了,我的碰撞检测正常工作,但是当它们碰撞时该怎么办呢?
行星不会移动,但是使用Java脚本执行三角函数来计算合成速度非常困难。
这是我的物理代码,通过requestAnimationFrame执行:
var a = [0, 0];
// p is in the format [x, y, radius, density]
planets.forEach(function (p) {
var d = Math.sqrt((p[0] - ball.coor[0]) ** 2 + (p[1] - ball.coor[1]) ** 2);
var m = p[3] * 4 / 3 * Math.PI * p[2] ** 3;
var f = G * m / d ** 2;
var angle = Math.atan2(p[1] - ball.coor[1], p[0] - ball.coor[0]);
a[0] += f * Math.cos(angle);
a[1] += f * Math.sin(angle);
if (d < p[2] + ball.radius) {
var impulse = [0, 0];
// What to do here?
// This is the closest I got:
var velocitya = Math.atan(b.v[1] / b.v[0]);
var trianglea = Math.abs(velocitya - angle);
var currV = Math.sqrt(b.v[0] ** 2 + b.v[1] ** 2);
var newV = currV * bounciness;
var newa = (Math.PI / 2 - trianglea) * 2 + velocitya;
b.v[0] = newV * Math.cos(newa);
b.v[1] = newV * Math.sin(newa);
// Somehow I just can't get it right.
// It's the JavaScript, not the math concepts.
}
});
ball.v[0] += a[0];
ball.v[1] += a[1];
ball.coor[0] += ball.v[0];
ball.coor[1] += ball.v[1];
ball
只是高尔夫球的对象。
我尝试了各种方法,但是我只是无法使冲突正常工作。似乎与方向和角度一起工作使我感到悲伤。我做了很多研究,但发现没有什么似乎可以正确解决我的问题。
所以这是我的问题:如何使用原始JavaScript计算冲量?
注意:行星不动,弹跳应该是变量。
答案 0 :(得分:1)
好的,我认为这可行。
给出:
我认为步骤如下:
似乎可行。为了清楚起见,我们假设b
(球),p
(行星)和v
(速度)是具有x
和y
成员的对象。>
function impact(b, p, v) {
let a = b.x == p.x
? Math.PI / 2
: Math.atan((b.y - p.y) / (b.x - p.x));
v = rotate(v, -a);
v.x = -v.x;
return rotate(v, a);
}
function rotate(p, a) {
return {
x: p.x * Math.cos(a) - p.y * Math.sin(a),
y: p.y * Math.cos(a) + p.x * Math.sin(a)
);
}
您需要做一些工作才能使用数组等将其转换为您的样式。
如果您想稍微放慢球的速度,您可能也可以弄清楚该怎么做。最简单的方法就是将向量的x和y分量按比例缩小。
答案 1 :(得分:1)
这样的事情行得通吗? (仔细检查语法错误)
var a = [0, 0];
// p is in the format [x, y, radius, density]
planets.forEach(function (p) {
var d = Math.sqrt((p[0] - ball.coor[0]) ** 2 + (p[1] - ball.coor[1]) ** 2);
var r = [0, 0]; //radial vector of length one from ball's center to planet's center
r[0] = (p[0] - ball.coor[0]) / d; // this is the same as cos(angle)
r[1] = (p[1] - ball.coor[1]) / d; // this is the same as sin(angle)
// I removed your implementation, it was using redundant expensive calculations
var m = p[3] * 4 / 3 * Math.PI * p[2] ** 3;
var f = G * m / d ** 2;
a[0] = a[0] + f * r[0];
a[1] = a[1] + f * r[1];
if (d < p[2] + ball.radius) {
var dot_v_r = ball.v[0] * r[0] + ball.v[1] * r[1];
ball.v[0] = bounciness * (ball.v[0] - 2 * dot_v_r * r[0]);
ball.v[1] = bounciness * (ball.v[1] - 2 * dot_v_r * r[1]);
// this is complete elastic reflection of the ball, leaving the planet stationary
// then velocity's magnitude (but not direction) is corrected with bounciness
}
});
ball.v[0] = ball.v[0] + time_step * a[0];
ball.v[1] = ball.v[1] + time_step * a[1];
ball.coor[0] = ball.coor[0] + time_step * ball.v[0];
ball.coor[1] = ball.coor[1] + time_step * ball.v[1];
//time_step is a time step, i.e. how frequently you want to update ball's position and velocity
//you can choose a value that makes the update of frames appropriate.