Ios 使用spritekit for 2d platformer为移动平台添加轻松进出功能
那么你好, 我正在用spritekit为iOS制作一个2d平台。我有移动平台,允许我的角色随平台移动 我不能只用skactions来移动我的平台,因为角色不会随平台移动 问题:Ios 使用spritekit for 2d platformer为移动平台添加轻松进出功能,ios,swift,sprite-kit,2d,game-physics,Ios,Swift,Sprite Kit,2d,Game Physics,那么你好, 我正在用spritekit为iOS制作一个2d平台。我有移动平台,允许我的角色随平台移动 我不能只用skactions来移动我的平台,因为角色不会随平台移动 问题: 我将如何添加一个Easy in and out功能,以便拥有这些平台???模拟:SKactionTimeMode.easeInEaseOut 当前解决方案: 我面前没有代码,但对于左/右移动平台,这就是我正在做的。这将在platforms update()方法中运行 If platform.position.xxposi
我将如何添加一个Easy in and out功能,以便拥有这些平台???模拟:SKactionTimeMode.easeInEaseOut 当前解决方案:
我面前没有代码,但对于左/右移动平台,这就是我正在做的。这将在platforms update()方法中运行
If platform.position.xxpositioniwantnodetostoppingright{
velAmount=-velAmount
}
platform.physicsBody?.velocity=SKVector(dx:velAmount,dy:velAmount
platform.position.y=静态位置
澄清一下,这很好用。如果有更好的方法,我洗耳恭听。但这会产生一种锯齿状的停转感觉。我想要那种进出自如的感觉,让平台感觉更自然
感谢您的帮助!!!对于physic,您可以利用身体的摩擦力和线性阻尼。您甚至可以使用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,我以前从未使用过它(我相信你可以纠正我弄错的任何语法)
这就是线性平台。要改变运动,我们需要做的就是改变函数f(t)=?
,在上面的行中let dist=t
为了方便使用,有一个方便的功能可用于大多数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)=速度(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慢,但出于我们的需要,max speed可以)
函数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分钟时,右侧为1分钟,左侧为2分钟,依此类推
然后,我们通过只观察运动的一部分,使运动和时间正常化
该图形表示从左到右的移动,距离为1,时间为1。它刚刚被缩放以适合单位框(1乘1框)
红线表示直线运动f(t)=t
(恒定速度)。在任何时间点,你移动穿过直线,向下移动,你可以找到移动的距离
绿线表示ease函数f(t)=t*t/(t*t+(1-t)*(1-t))
,其工作原理相同。在任何时间点,扫描以找到绿线并向下移动以获得距离。函数f(t)为您实现这一点
使用maxSpeed,距离0.5处直线的陡度会发生变化,陡度越大表示行驶速度越快。我更新了我的问题,忘记了一行代码,并更新了另外两行代码。基本上每次更新,我都应用速度,使其成为恒定速度。我喜欢
let dist = pow(t,1.2) / (pow(t,1.2) + pow((1-t),1.2);
let maxSpeed = Double(velAmountX + 3) / Double(velAmountX); // 3 pixels per frame faster
// 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));