所以我有一个物体,它有一个physicsBody,重力会影响它。它也是动态的。
目前,当用户触摸屏幕时,我运行以下代码:
applyForce(0,400)
物体向上移动约200次,然后由于重力而下降。这种情况只会在少数时候发生。其他情况下,它会导致对象在Y方向上仅移动50个单位。
我找不到模式..。我把我的项目放在dropbox上,这样只要有人愿意看,它就可以打开。
https://www.dropbox.com/sh/z0nt79pd0l5psfg/bJTbaS2JpY
编辑:这似乎发生在球员在撞击后轻微弹离地面的片刻。有没有办法让玩家完全不弹跳?
编辑2:我尝试使用摩擦力参数来解决这个问题,只允许玩家在摩擦力=0时“跳跃”(你可能会认为这是所有玩家在空中的情况),但摩擦力似乎一直大于0。我如何才能检测到玩家是否正在触摸物体(除了使用y位置)?
谢谢
发布于 2013-11-07 21:39:41
建议的解决方案
如果你想实现一个跳转特性,我建议你使用applyImpulse
而不是applyForce
。下面是两者之间的区别,如Sprite Kit Programming Guide中所述
您可以选择施加力或脉冲:
根据施加力和处理模拟的下一帧之间经过的模拟时间量,将在一段时间内应用力。因此,要对实体应用连续力,需要在每次处理新帧时进行适当的方法调用。力通常用于连续效果。
脉冲对物体的速度进行瞬时改变,这与经过的模拟时间无关。脉冲通常用来立即改变物体的速度。
跳跃实际上是物体速度的瞬间变化,这意味着你应该施加脉冲而不是力。要使用applyImpulse:
方法,请计算出所需的速度瞬时变化,乘以物体的质量,并将其用作函数的impulse
参数。我想你会看到更好的结果。
意外行为的解释
如果在update:
函数外部调用applyForce:
,则会发生力乘以施加力和处理模拟下一帧之间所经过的时间量的情况。这个乘数不是常量,所以每次以这种方式调用applyForce:
时,您都会看到不同的速度变化。
发布于 2013-11-18 05:52:52
@godel9有一个很好的建议解决方案,尽管在我自己的测试中,对意外行为的解释是不正确的。
从SKPhysicsBody Class Reference
力应用于单个模拟步骤(一帧)。
回到关于-update方法的SKScene Class Reference's部分:
只要场景显示在视图中且未暂停,
...it就会在每帧中恰好调用一次。
因此,我们可以假设在SKScene的-update方法中调用-applyForce:应该不会造成问题。但正如观察到的那样,尽管施加了比重力大得多的向上力(400牛顿对9.81),但这种力并没有超过重力。
我创建了一个测试项目,它将创建两个节点,一个自然下降,将affectedByGravity设置为TRUE,另一个使用相同的预期重力向量(x方向为0牛顿,y方向为-9.81 )调用-applyForce。然后,我计算了每个节点在一个时间步中的速度差,以及时间步的长度。然后,我记录了加速度(速度的变化/时间的变化)。
下面是我的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文档经常建议不要进行精确的物理计算(具体见“伪造数字”一节),但这种不一致花了我很长时间才确定下来。希望这能有所帮助!
https://stackoverflow.com/questions/19834932
复制相似问题