16

所以我有一个物体,它有一个物理体,重力会影响它。它也是动态的。

目前,当用户触摸屏幕时,我运行代码:

应用力(0, 400)

物体向上移动大约 200 米,然后由于重力而落下。这只会在某些时候发生。其他时候,它会导致对象仅在 Y 方向移动 50ish 个单位。

我找不到模式......我把我的项目放在保管箱上,这样如果有人愿意看它就可以打开它。

https://www.dropbox.com/sh/z0nt79pd0l5psfg/bJTbaS2JpY

编辑:这似乎发生在玩家在撞击后稍微从地面弹起片刻时发生。有没有办法让玩家完全不反弹?

编辑 2:我尝试使用摩擦参数来解决这个问题,并且只允许玩家在摩擦 = 0 时“跳跃”(你会认为这将是玩家在空中的所有情况)但摩擦似乎大于 0每时每刻。我还能如何检测玩家是否正在触摸物体(除了使用 y 位置)?

谢谢

4

2 回答 2

51

建议的解决方案

如果您正在尝试实现跳转功能,我建议您查看applyImpulse而不是applyForce. 如Sprite Kit Programming Guide中所述,这是两者之间的区别:

您可以选择施加力或冲动:

根据施加力和处理模拟的下一帧之间经过的模拟时间量,施加力的时间长度。因此,要对物体施加连续的力,您需要在每次处理新帧时进行适当的方法调用。力通常用于连续效果。

脉冲对身体的速度产生瞬时变化,与经过的模拟时间量无关。脉冲通常用于立即改变身体的速度。

跳跃实际上是身体速度的瞬时变化,这意味着您应该施加冲动而不是力。要使用该applyImpulse:方法,请计算出所需的瞬时速度变化,乘以身体的质量,并将其用作impulse函数的参数。我想你会看到更好的结果。

意外行为的解释

如果你在applyForce:你的函数之外调用update:,发生的事情是你的力乘以你施加力和处理模拟的下一帧之间所经过的时间量。applyForce:这个乘数不是一个常数,因此每次以这种方式调用时,您都会看到不同的速度变化。

于 2013-11-07T13:39:40.730 回答
19

@godel9 有一个很好的建议解决方案,尽管在我自己的测试中,对意外行为的解释是不正确的。

SKPhysicsBody 类参考

该力应用于单个模拟步骤(一帧)。

参考SKScene 类参考中关于 -update 方法的部分:

...它每帧只调用一次,只要场景在视图中呈现并且没有暂停。

所以我们可以假设在 SKScene 的 -update 方法中调用 -applyForce: 不会导致问题。但正如所观察到的,尽管施加的向上力远大于重力(400 牛顿对 9.81),但该力并未超过重力。

我创建了一个测试项目,该项目将创建两个节点,一个自然下落,将affectedByGravity 设置为TRUE,另一个调用-applyForce,具有相同的预期重力矢量(x 方向为0 牛顿,y 方向为-9.81)。然后我计算了一个时间步中每个节点的速度差异,以及时间步长。然后,我记录了加速度(速度变化/时间变化)。

这是我的 SKScene 子类的一个片段:

- (id)initWithSize:(CGSize)size

{

if (self = [super initWithSize:size])

{

    self.backgroundColor = [UIColor purpleColor];



    SKShapeNode *node = [[SKShapeNode alloc] init];

    node.path = CGPathCreateWithEllipseInRect(CGRectMake(0, 0, 10, 10), nil);

    node.name = @"n";

    node.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:5];

    node.position = CGPointMake(0, 450);

    node.physicsBody.linearDamping = 0;

    node.physicsBody.affectedByGravity = NO;

    [self addChild:node];



    node = [[SKShapeNode alloc] init];

    node.path = CGPathCreateWithEllipseInRect(CGRectMake(0, 0, 10, 10), nil);

    node.name = @"n2";

    node.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:5];

    node.position = CGPointMake(20, 450);

    node.physicsBody.linearDamping = 0;

    [self addChild:node];


}

return self;

}



- (void)update:(NSTimeInterval)currentTime

{

SKNode *node = [self childNodeWithName:@"n"];

SKNode *node2 = [self childNodeWithName:@"n2"];

CGFloat acc1 = (node.physicsBody.velocity.dy - self.previousVelocity) / (currentTime - self.previousTime);

CGFloat acc2 = (node2.physicsBody.velocity.dy - self.previousVelocity2) / (currentTime - self.previousTime);

[node2.physicsBody applyForce:CGVectorMake(0, node.physicsBody.mass * -150 * self.physicsWorld.gravity.dy)];

NSLog(@"x:%f, y:%f, acc1:%f, acc2:%f", node.position.x, node.position.y, acc1, acc2);

self.previousVelocity = node.physicsBody.velocity.dy;

self.previousTime = currentTime;

self.previousVelocity2 = node2.physicsBody.velocity.dy;

}

结果不寻常。与手动施加力的节点相比,模拟中受重力影响的节点的加速度始终乘以 150 倍。我已经尝试过使用不同大小和密度的节点,但存在相同的标量乘数。

由此我必须推断 SpriteKit 内部有一个默认的“像素与米”比率。也就是说,每个“米”正好等于 150 个像素。这有时很有用,否则场景通常太大,这意味着力量反应缓慢(想想从地面看飞机,它的飞行速度非常快,但看起来移动得很慢)。Sprite Kit 文档经常建议不建议进行精确的物理计算(具体见“捏造数字”部分),但这种不一致让我花了很长时间才确定。希望这可以帮助!

于 2013-11-17T21:52:52.440 回答