所以我有一个物体有物理体,重力影响它。它也是动态的。
目前,当用户触摸屏幕时,我运行代码:
applyForce(0,400)
物体向上移动约200,然后由于重力下降。这只会在某些时候发生。其他时候,它导致物体仅在Y方向上移动50个单位。
我找不到一个模式......我把我的项目放在Dropbox上,如果有人愿意看它就可以打开它。
https://www.dropbox.com/sh/z0nt79pd0l5psfg/bJTbaS2JpY
编辑:似乎这种情况发生在玩家在撞击后稍微从地面反弹一段时间后。有没有办法让玩家不会反弹?
编辑2:我尝试使用摩擦参数来解决这个问题,并且只允许玩家在摩擦力为0时“跳跃”(你会认为这将是玩家空降的所有情况)但是摩擦似乎是始终大于0。我怎么能检测到玩家是否正在触摸一个物体(除了使用y位置)?由于
答案 0 :(得分:51)
建议的解决方案
如果您尝试实施跳转功能,建议您查看applyImpulse
而不是applyForce
。这是两者之间的差异,如Sprite Kit Programming Guide:
您可以选择施加力量或冲动:
根据施加力和处理模拟的下一帧之间经过的模拟时间量,施加力一段时间。因此,要对主体应用连续的力,每次处理新帧时都需要进行适当的方法调用。力量通常用于连续效果。
脉冲使身体的速度瞬间变化,与已经过的模拟时间量无关。脉冲通常用于立即改变身体的速度。
跳跃实际上是身体速度的瞬间变化,这意味着你应该施加冲动而不是力量。要使用applyImpulse:
方法,找出所需的瞬时瞬时变化,乘以身体的质量,并将其作为impulse
参数添加到函数中。我想你会看到更好的结果。
意外行为的说明
如果你在applyForce:
函数之外调用update:
,那么正在发生的事情就是你的力量乘以你施加力量和下一帧之间经过的时间量。处理模拟。此乘数不是常数,因此每次以这种方式调用applyForce:
时,您都会看到速度的不同变化。
答案 1 :(得分:18)
@ godel9有一个很好的建议解决方案,但在我自己的测试中,对意外行为的解释是不正确的。
来自SKPhysicsBody Class Reference:
该力用于单个模拟步骤(一帧)。
回顾有关-update方法的SKScene Class Reference's部分:
...每帧只调用一次,只要场景出现在视图中并且没有暂停。
因此我们可以假设在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文档经常表明不建议进行精确的物理计算(具体见“捏造数字”一节),但这种不一致需要我花费很长时间才能确定。希望这有帮助!