弹跳曲线算法

这个是做某JS游戏时遇到的第一个问题,如何生成一个相对符合物理规律的弹跳曲线呢?

现在假定我们有一个物体的初始位置和速度信息等,首先需要做的,就是计算出相应的抛物线。高三课本中讲到的导数在这里就得用上了。


y = ax2 + bx + c

则有
y’ = 2ax + b

设物体的初始位置为(0, h),初始速度水平和竖直方向分别为vx、vy,那么,当x = 0时,我们列出以下方程
h = c
y’ = b = vy / vx

然后在物理上,有
s = at2 / 2
s = vt

在本例中(当物体还没有着地时),即有
y = h + vyt- gt2 / 2
x = vxt

带入之前的方程,有
h + vyt – gt2 / 2 = a(vxt)2 + bvxt + h

解得
a = – g / 2(vx)2
b = vy / vx
c = h

那到此最关键的部分就完成了,然后通过
x2 = (b – √(b2 – 4ab)) / 2a
可计算得落点的位置,通过累加x,可以将这三个解扩充。

下面附我写的JS类
//速度类
function Speed(x, y) {
this.x = x;
this.y = y || 0;
}

/******** 通用函数 ********/

//剩余速度比例
function Remain(x, y) {
this.x = x;
this.y = y;
}

//平面路径
function Route(speed, height, gravity, remain) {
var v = copyObject(speed);

var a = [], b = [], c = [];
var vX = [];

var lastX = 0, lastT = 0;
var lastH = height;

var xAreas = [], tAreas = [0];

var xByT = [];

for (var i = 0; ; i++) {
var aI = a[i] = -0.5 * gravity / sqr(v.x);
var bI = b[i] = v.y / v.x – 2 * aI * lastX;
var cI = c[i] = lastH – aI * sqr(lastX) – bI * lastX;

nowX = (-bI – sqrt(sqr(bI) – 4 * aI * cI)) / (2 * aI);

xAreas.push(nowX);

lastT += (nowX – lastX) / v.x;
tAreas.push(lastT);
vX.push(v.x);
xByT.push(lastX);

if (nowX – lastX < 1) break;

lastX = nowX;

v.x *= remain.x;
v.y = -(2 * aI * lastX + bI) * v.x * remain.y;
lastH = 0;
}

var xAreaI = 0, tAreaI = 0; //为了减小比较数量,此值会在必要时累加.

//通过x坐标获取高度(y)
this.getHeightByX = function (x) {
while (x > xAreas[xAreaI]) xAreaI++;
return a[xAreaI] * sqr(x) + b[xAreaI] * x + c[xAreaI];
};

//通过时间获取坐标
this.getPositionByT = function (t) {
while (t > tAreas[tAreaI + 1]) tAreaI++;

var x = xByT[tAreaI] + vX[tAreaI] * (t – tAreas[tAreaI]);
var y = this.getHeightByX(x);

if ((x !== 0) && !x || (y !== 0) && !y)
return null;
else
return { x: x, y: y };
};

this.reset = function () {
xAreaI = tAreaI = 0;
};
}

function copyObject(obj) {
var newObj = {};
for (child in obj)
newObj[child] = obj[child];
return newObj;
}

function sqr(n) {
return n * n;
}

function sqrt(n) {
return Math.sqrt(n);
}