SpriteKit SKPhysicsBody with Inner Edges

Wil*_*ich 5 game-physics ios sprite-kit skphysicsbody skspritenode

我创建了一个SKSpriteNode名为let的说Map,它具有我定义的边缘路径(一些简单的多边形形状).

我想弄清楚的是如何添加几个其他边缘路径作为Map的内部边缘.好像整个"地图"确实有漏洞.某种内部边界形状可以与Map作为一个整体起作用:一条边缘路径(如下所示)

在此输入图像描述 ©

我知道有一种方法可以创建一个SKPhysicsBodywith body(一些NSArray),就像这样

Map.physicsBody = [SKPhysicsBody bodyWithBodies:bodiesArray];
Run Code Online (Sandbox Code Playgroud)

这种方法实际上是否产生了我在图像中显示的内容?假设bodiesArray包含3 SKSpriteNode的每个都有一个使用这种方法的定义路径:

+ (SKPhysicsBody *)bodyWithEdgeChainFromPath:(CGPathRef)path
Run Code Online (Sandbox Code Playgroud)

,创造这样的道路

        SKSpriteNode *innerNode1 = [SKSpriteNode spriteNodeWithImageNamed:@"map"];

        CGMutablePathRef innerNode1Path = CGPathCreateMutable();

        CGPathMoveToPoint(mapPath, NULL, 1110, 1110);
        CGPathAddLineToPoint(mapPath, NULL, <some x1>, <some y1>);
        CGPathAddLineToPoint(mapPath, NULL, <some x2>, <some y2>);
        CGPathAddLineToPoint(mapPath, NULL, <some x3>, <some y3>);
        . 
        .
        .
        CGPathCloseSubpath(mapPath);

        innerNode1.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:innerNode1Path];
        [bodiesArray addObject:innerNode1];

        // Repeat for other 2 nodes
Run Code Online (Sandbox Code Playgroud)

我知道另一种方法是创建3个单独的节点,其中包含预期"洞"的位置和形状,但我想要避免创建比我需要的节点更多的节点.如果有人能够确认我想要做的是正确的,或者可能提出一个我不知道的替代方案.

注意:如果我正在做的是正确的,但我错过了一些东西,如果有人能告诉我正确的方法来做我想做的事情,我将不胜感激(即使是一个内部较小正方形的正方形的简单例子也是大).谢谢!

编辑1:下面是我用来创建"内部边界"的代码片段.这里的问题是,当绘制和显示外部和内部矩形时,当我将内部矩形添加到Map时bodyWithBodies,它完全控制碰撞检测,从外部rect shell移除所有接触控制.当我移除bodyWithBodies它恢复正常显示两个rects时,外部有碰撞检测(不允许我通过),而内部没有任何东西......如此接近

// 1 Create large outer shell Map
CGRect mapWithRect = CGRectMake(map.frame.origin.x + offsetX, map.frame.origin.y + offsetY, map.frame.size.width * shrinkage, map.frame.size.height * shrinkage);

self.physicsWorld.gravity = CGVectorMake(0.0, 0.0);
self.physicsWorld.contactDelegate = self;

// 2 Create smaller inner boundary 
CGRect innerRect = CGRectMake(100, 100, 300, 300);
SKPhysicsBody *body = [SKPhysicsBody bodyWithEdgeLoopFromRect:innerRect];
body.categoryBitMask = wallCategory;
NSArray *bodyArray = [NSArray arrayWithObject:body];

// 3 Add bodies to main Map body
myWorld.physicsBody = [SKPhysicsBody bodyWithBodies:bodyArray]; 
myWorld.physicsBody.categoryBitMask = wallCategory;


if ( [[levelDict objectForKey:@"DebugBorder"] boolValue]  == YES) { 
    // This will draw the boundaries for visual reference during testing       
    [self debugPath:mapWithRect];
    [self debugPath:innerRect];
}
Run Code Online (Sandbox Code Playgroud)

编辑2 这种方法有效..只需添加一个与外部矩形具有相同属性的新节点:

SKPhysicsBody *innerRectBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:innerRect];
innerRectBody.collisionBitMask = playerCategory;
innerRectBody.categoryBitMask = wallCategory;
SKNode *innerBoundary = [SKNode node];
innerBoundary.physicsBody = innerRectBody;
[myWorld addChild: innerBoundary];
Run Code Online (Sandbox Code Playgroud)

...但我非常希望一个更清洁的解决方案,不需要额外的节点...虽然?

dra*_*eye 1

你在这里没有做错什么,我举了一个例子,我用两个物理体创建了两个边缘矩形体

//使用gcd一段时间后添加主体

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self addBodyA];
    });

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self addBodyB];
    });
-(void)addBodyB
{
    SKSpriteNode *node=[SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(20, 20)];
    node.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:node.frame.size];
    node.position=CGPointMake(550, 420);
    node.physicsBody.restitution=1;
    [self addChild:node];

}
-(void)addBodyA
{
    SKSpriteNode *node=[SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(20, 20)];
    node.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:node.frame.size];
    node.position=CGPointMake(400, 420);
    node.physicsBody.restitution=1;
    [self addChild:node];

}
-(void)addEdgesBodies
{
    SKAction *r=[SKAction rotateByAngle:1.0/60 duration:1.0/60];

    SKSpriteNode *rect=[SKSpriteNode spriteNodeWithColor:[SKColor clearColor] size:CGSizeMake(300,300)];
    rect.physicsBody=[SKPhysicsBody bodyWithEdgeLoopFromRect:rect.frame];
    rect.position=CGPointMake(500, 400);
    [self addChild:rect];


    //
    SKSpriteNode *rect1=[SKSpriteNode spriteNodeWithColor:[SKColor clearColor] size:CGSizeMake(100,100)];
    rect1.physicsBody=[SKPhysicsBody bodyWithEdgeLoopFromRect:rect1.frame];
    rect1.position=CGPointMake(550, 450);
    [self addChild:rect1];


    [rect1 runAction:[SKAction repeatActionForever:r]];

}
 [self addEdgesBodies];
Run Code Online (Sandbox Code Playgroud)

请记住,边体的 CPU 开销较低,因此不必担心性能,直到您的多边形没有那么多边。