缓出功能
如果我们将平台从一侧移动到另一侧的时间视为一个单位(可能是 10 秒或 17 帧,没关系,我们现在以单位工作)。
我们对距离做同样的事情。平台必须在一个单位时间内移动一个单位距离。
这个回答时间是t,位置是时间的函数,写成f(t)是时间t的平台位置。
对于简单的线性运动,函数就是f(t)=t。因此,在时间t=0 移动的距离为 0,在时间 0.5(中途)时,距离为 0.5(中途),依此类推。
所以让我们把它变成更实用的东西。
请原谅我之前从未使用过它的swift(我相信你可以纠正我弄错的任何语法)。
// First normalise the distance and time (make them one unit long)
// get the distance
let distance = Double(xPositionStopGoingLeft - xPositionStopGoingRight);
// use that and the velocity to get the time to travel
let timeToTravel = distance / Double(velAmountX);
// first we have a frame ticker
gameTick += 1; // that ticks for every frame
// We can assume that the platform is always moving back and forth
// Now is the unit time where at now = 2 the platform has move there and back
// at 3 it has move across again and at 4 back again.
let now = Double(gameTick) / timeToTravel; // normalize time.
// get the remainder of 2 as from 0-1 is moving forward and 1-2 is back
let phase = now % 2.0;
// We also need the unit time for the function f(t)=t
let t = abs(phase - 1);
if phase >= 1 { t = 1 - t } // reverse for return
// implement the function f(t) = t where f(t) is dist
let dist = t
// and convert back to pixel distance
platform.position.x = Int(dist * distance + Double(xPositionStopGoingLeft));
这就是线性平台。要改变运动,我们需要做的就是改变函数f(t)=?,在上面它的行let dist = t
为了便于使用,有一个方便的功能可用于大多数简单的应用程序f(t) = t * t / ((t * t) + (1 - t) * ( 1 - t))
有一些 t*t 是幂,t 是 2 或 t^2 的幂。迅速将其pow(t,2) 重写为代码
let dist = pow(t,2) / (pow(t,2) + pow((1-t),2);
这在开始和结束时提供了很好的轻松因为经过的距离和时间是恒定的,所以中间点t = 0.5 的速度必须更大才能赶上缓慢的开始和结束。 (旁注,获取上述函数的导数可以让你锻炼每个时间点的速度f'(t) = speed(t) = 2(-(t-1)t)^(2-1) /(t^2+(1-t)^2)^2)
这个函数太好了,0.5 时刻的速度为 2,与功率相同(对于直线行程,它是 1)。该函数的一个方便属性是中间点的速度始终与功率相同。如果你想让它在中点移动得非常快,比如快 4 倍,那么你可以使用 4 的力量
让 dist = pow(t,4) / (pow(t,4) + pow((1-t),4);
如果你只想让它加速一点,比如中心速度的 1.2 倍,那么功率是 1.2
let dist = pow(t,1.2) / (pow(t,1.2) + pow((1-t),1.2);
所以现在我们可以引入另一个术语,maxSpeed,它是归一化的 maxSpeed(更准确地说,它是 t=0.5 时的速度,因为它可能比 1 慢,但我们需要最大速度就可以了)
let maxSpeed = Double(velAmountX + 3) / Double(velAmountX); // 3 pixels per frame faster
还有函数f(t) = t^m / (t^m + (1-t)^m),其中m是maxSpeed。
作为代码
让 dist = pow(t,maxSpeed ) / (pow(t,maxSpeed ) + pow((1-t),maxSpeed);
把这些放在一起
// the next 3 lines can be constats
let distance = Double(xPositionStopGoingLeft - xPositionStopGoingRight);
let timeToTravel = distance / Double(velAmountX);
let maxSpeed = Double(velAmountX + 3) / Double(velAmountX);
gameTick += 1; // that ticks for every frame
let now = Double(gameTick) / timeToTravel; // normalize time.
let phase = now % 2.0;
let t = abs(phase - 1);
if phase >= 1 { t = 1 - t } // reverse for return
// the next line is the ease function
let dist = pow(t, maxSpeed) / (pow(t, maxSpeed) + pow((1-t) ,maxSpeed);
// position the platform
platform.position.x = Int(dist * distance + Double(xPositionStopGoingLeft));
现在您可以随时计算平台的位置。如果您想减慢整个游戏的速度并将帧步进到一半,它仍然可以工作。如果你加快游戏速度gameTick += 2 它仍然有效。
最大速度也可以低于线速度。如果您希望平台在中心t=0.5 设置为maxSpeed = 0.5 的正常速度的一半,并且在中点处速度将是一半。为了让一切工作在开始和结束时轻松自如,冲进冲出会更快。 (也适用于反向)
也许是一种视觉表现形式的帮助
图片显示了平台随着时间的推移来回移动。距离约为60像素,时间可以是1分钟。所以在 1 分钟时,它会是右边的 2 分钟在左边,依此类推。
然后我们通过只查看运动的一个部分来标准化运动和时间。
图表表示从左到右的移动,距离为1,时间为1。它刚刚被缩放以适合单位框(1乘1框)。
红线代表直线运动f(t)=t(恒速)。在任何时间点你越过这条线向下移动,你可以找到行进的距离。
绿线代表缓动函数f(t)=t*t/(t*t+(1-t)*(1-t)),它的工作原理是一样的。在任何时间点扫描以找到绿线并向下移动以获得距离。函数 f(t) 会为你做这件事。
使用 maxSpeed 时,距离 0.5 处的线的陡度会发生变化,更陡的坡度代表更快的行驶。