使用 spritekit 为 2d 平台游戏添加进出移动平台的便利性
Adding ease in and out to moving platforms with spritekit for 2d platformer
你好,
我正在使用 spritekit 为 iOS 制作一个 2d 平台游戏。我有移动平台,可以让我的角色随平台移动。
我不能只使用 skactions 来移动我的平台,因为角色不会随平台移动。
问题:
我将如何添加缓入和缓出功能以拥有平台???模拟:SKactionTimeMode.easeInEaseOut
当前解:
我面前没有代码,但是对于 left/right 移动平台,这几乎就是我正在做的事情。这将是平台 update() 方法中的 运行。
If platform.position.x < xPositionIWantNodeToStopGoingLeft {
velAmount = -velAmount
}
else if platform.position.x > xPositionIWantNodeToStopGoingRight {
velAmount = -velAmount
}
platform.physicsBody?.velocity = SKVector(dx: velAmount, dy: velAmount
platform.position.y = staticYPosition
澄清一下,这很管用。如果有更好的方法来做到这一点,我会洗耳恭听。但这会产生锯齿状的停止和转弯感觉。我想要轻松进出的感觉,让平台感觉更自然。
感谢您的帮助!!!
对于物理,玩一下 body 的摩擦力和线性阻尼。您甚至可以使用 SKAction 运行 块来减少或增加摩擦。
你可以这样做:
physicsBody.friction = (10 - physicsBody.velocity.dx) > 0 ? (10 - physicsBody.velocity.dx) / 10 : 0
基本上当 velocity.dx < 10 时它会产生摩擦,您可能需要将 10 调整为您喜欢的数量
缓入缓出函数
如果我们把平台从一侧移动到另一侧的时间算作一个单位(可能是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
对于 ease in out 有一个方便的功能,在大多数 ease 应用程序中使用 f(t) = t * t / ((t * t) + (1 - t) * ( 1 - t))
有些 t*t
是幂,t
的 2 次方或 t^2 。在 swift 它的 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 x 1 框)。
红线表示直线运动f(t)=t
(恒速)。在你移动的任何时间点,击中直线向下移动,你可以找到移动的距离。
绿线表示缓动函数f(t)=t*t/(t*t+(1-t)*(1-t))
,作用相同。在任何时间点扫描以找到绿线并向下移动以获取距离。函数 f(t) 会为您完成。
在 maxSpeed 的情况下,距离 0.5 处的直线陡度发生变化,斜度越大表示行进速度越快。
你好,
我正在使用 spritekit 为 iOS 制作一个 2d 平台游戏。我有移动平台,可以让我的角色随平台移动。
我不能只使用 skactions 来移动我的平台,因为角色不会随平台移动。
问题:
我将如何添加缓入和缓出功能以拥有平台???模拟:SKactionTimeMode.easeInEaseOut
当前解:
我面前没有代码,但是对于 left/right 移动平台,这几乎就是我正在做的事情。这将是平台 update() 方法中的 运行。
If platform.position.x < xPositionIWantNodeToStopGoingLeft {
velAmount = -velAmount
}
else if platform.position.x > xPositionIWantNodeToStopGoingRight {
velAmount = -velAmount
}
platform.physicsBody?.velocity = SKVector(dx: velAmount, dy: velAmount
platform.position.y = staticYPosition
澄清一下,这很管用。如果有更好的方法来做到这一点,我会洗耳恭听。但这会产生锯齿状的停止和转弯感觉。我想要轻松进出的感觉,让平台感觉更自然。
感谢您的帮助!!!
对于物理,玩一下 body 的摩擦力和线性阻尼。您甚至可以使用 SKAction 运行 块来减少或增加摩擦。
你可以这样做:
physicsBody.friction = (10 - physicsBody.velocity.dx) > 0 ? (10 - physicsBody.velocity.dx) / 10 : 0
基本上当 velocity.dx < 10 时它会产生摩擦,您可能需要将 10 调整为您喜欢的数量
缓入缓出函数
如果我们把平台从一侧移动到另一侧的时间算作一个单位(可能是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
对于 ease in out 有一个方便的功能,在大多数 ease 应用程序中使用 f(t) = t * t / ((t * t) + (1 - t) * ( 1 - t))
有些 t*t
是幂,t
的 2 次方或 t^2 。在 swift 它的 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 x 1 框)。
红线表示直线运动f(t)=t
(恒速)。在你移动的任何时间点,击中直线向下移动,你可以找到移动的距离。
绿线表示缓动函数f(t)=t*t/(t*t+(1-t)*(1-t))
,作用相同。在任何时间点扫描以找到绿线并向下移动以获取距离。函数 f(t) 会为您完成。
在 maxSpeed 的情况下,距离 0.5 处的直线陡度发生变化,斜度越大表示行进速度越快。