4

我已经创建了一个SKShapeNode并且我已经分配了一个physicsBody给它。但是,当有接触时它不会被触发。

代码创建SKShapeNode

-(SKShapeNode*)gravityline{
    //SKSpriteNode *lolo=[[SKSpriteNode alloc]init];
    SKShapeNode *lolo = [[SKShapeNode alloc] init];
    CGPoint fff=CGPointMake(ray1.position.x, ray1.position.y);
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, fff.x, fff.y);
    CGPathAddLineToPoint(path, 0,rayoriginpoint.x,rayoriginpoint.y );
    CGPathCloseSubpath(path);
    lolo.path = path;
    lolo.name=@"gravityline";
    lolo.strokeColor=[SKColor greenColor];
    lolo.glowWidth=.1;
    CGPathRelease(path);
    lolo.physicsBody=[SKPhysicsBody bodyWithEdgeFromPoint:fff toPoint:rayoriginpoint];
    //lolo.physicsBody=[SKPhysicsBody bodyWithEdgeLoopFromPath:path];
    //lolo.physicsBody=[SKPhysicsBody bodyWithPolygonFromPath:path];
    lolo.physicsBody.categoryBitMask=raylightCategory;
    lolo.physicsBody.collisionBitMask=batCategory;
    lolo.physicsBody.contactTestBitMask=batCategory;
    lolo.physicsBody.usesPreciseCollisionDetection=YES;
    lolo.physicsBody.linearDamping=0;
    lolo.physicsBody.restitution=1.0;
    lolo.physicsBody.dynamic=NO;

    return lolo;
}

这是触发代码:

- (void)didBeginContact:(SKPhysicsContact *)contact
{
    SKPhysicsBody *firstBody, *secondBody;
    if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
    {
        firstBody = contact.bodyA;
        secondBody = contact.bodyB;
    }
    else
    {
        firstBody = contact.bodyB;
        secondBody = contact.bodyA;
    }
    if (firstBody.categoryBitMask == raylightCategory && secondBody.categoryBitMask==batCategory)
    {
        NSLog(@"Contact with bat have been made");
        [secondBody.node removeFromParent];
    }
}

如果有人知道我做错了什么,为什么SKShapeNode没有激活physicsBody,请告诉我。

4

2 回答 2

0

您的代码并没有完全显示您的“gravityLine”正在与什么相撞。我只能从它的描述中推测它没有检测到与圆形物体(球和球棒)的碰撞。

“gravityLine”方法似乎返回了一个由基于边缘的形状定义的 SKShapeNode:

lolo.physicsBody=[SKPhysicsBody bodyWithEdgeFromPoint:fff toPoint:rayoriginpoint];

当谈到碰撞时,阅读 Apple 的 Sprite Kit Programming Guide 很重要,特别是它对三种形状的解释。

1) 动态体积模拟具有可能受系统中的力和碰撞影响的体积和质量的物理对象。使用动态体积来表示场景中需要四处移动和相互碰撞的项目。

2) 静态体积类似于动态体积,但其速度被忽略,不受力或碰撞的影响。但是,因为它仍然有体积,所以其他物体可以从它反弹或与之交互。使用静态体积来表示在场景中占用空间但不应被模拟移动的项目。例如,您可以使用静态体积来表示迷宫的墙壁。虽然将静态和动态体积视为不同的实体很有用,但在实践中,这两种不同的模式可以应用于任何基于体积的物理体。这很有用,因为您可以有选择地启用或禁用身体的效果。

3) 边是静态的无体积体。边缘永远不会被模拟移动,它们的质量无关紧要。边缘用于表示场景内的负空间(例如另一个实体内的空心点)或不可跨越的、不可见的细边界。例如,边缘经常用于表示场景的边界。边缘和体积之间的主要区别在于,边缘允许在其自身边界内移动,而体积被视为实体对象。如果边通过其他方式移动,它们只与体积交互,而不与其他边交互。

根据上述信息,如果您阅读了使用bodyWithEdgeFromPoint:toPoint:方法的文档,您将看到您正在创建一个“基于边缘”的物理体。

返回值

一个新的基于边缘的物理体。

讨论

一条边没有体积或质量,总是被视为动态属性等于 NO。边缘只能与基于体积的物理实体发生碰撞。

要使碰撞起作用,您必须确保边缘与基于体积的物理体发生碰撞。每个物理体形创建方法都记录了它创建的形状是什么类型。

如果您正在使用与边缘碰撞的基于体积的物理体,那么另一种可能性可能是由于所涉及对象的大小或速度。同样,阅读 Apple 的文档可以清楚地说明这一点。

为小型或快速移动对象指定高精度碰撞: 当 Sprite Kit 执行碰撞检测时,它首先确定场景中所有物理体的位置。然后它确定是否发生了碰撞或接触。这种计算方法速度很快,但有时会导致错过碰撞。一个小物体可能移动得如此之快,以至于它完全穿过另一个物理物体,而没有动画帧使两者相互接触。

如果您有必须碰撞的物理实体,您可以提示 Sprite Kit 使用更精确的碰撞模型来检查相互作用。这种模式比较昂贵,所以应该谨慎使用。当任一身体使用精确碰撞时,会接触并测试多个运动位置,以确保检测到所有接触

ship.physicsBody.usesPreciseCollisionDetection = YES;

其他可能性也可能会导致碰撞,例如您分配给物理体的路径的错误位置信息。重要的是要了解,当您设置节点的路径时,形状是使用节点的局部坐标系设置的。重要的是要记住 Sprite Kit 中的原点位于左下角(而不是 UIKit 的左上角),并且当您将路径分配给节点的物理主体时,路径是相对于节点的锚点放置的.

例如:

SKShapeNode *ball = [[SKShapeNode alloc] init];
CGRect ballFrame = CGRectMake(-25.0, -25.0, 50.0, 50.0);
[ball setPath:[UIBezierPath bezierPathWithOvalInRect:ballFrame].CGPath];
[ball setPosition:CGPointMake(100.0, 450.0)];
[ball setFillColor:[UIColor redColor]];
[ball setPhysicsBody:[SKPhysicsBody bodyWithCircleOfRadius:25.0]];

如果我将“ballFrame”的原点设置为 (0,0),那么半径为 25.0 的物理体的圆将不会与球的形状重合,因为物理体的左下角将是放置在球的锚点处,即球的局部坐标系中的点 x = 0 和 y = 0 处。

于 2014-02-19T03:53:28.593 回答
0

这肯定行不通:

lolo.physicsBody=[SKPhysicsBody bodyWithEdgeFromPoint:fff toPoint:rayoriginpoint];

如果有的话,这将返回一个已经分配给不同节点的主体。但我想它只是返回零。

此注释行也不起作用:

//lolo.physicsBody=[SKPhysicsBody bodyWithEdgeLoopFromPath:path];

边缘形状将创建静态(如:不可移动)实体。因此这个节点不会在物理中移动,如果我没记错的话,你也不会从与静态物体的接触中得到接触响应,只有动态物体。

这个应该工作:

//lolo.physicsBody=[SKPhysicsBody bodyWithPolygonFromPath:path];

但是,您在这里将主体设置为静态主体:

lolo.physicsBody.dynamic=NO;

因此,与创建带有边缘循环的主体一样的规则适用。

于 2014-01-02T14:19:07.487 回答