SpriteKit SKPhysicsBody with Inner Edges

I created an SKSpriteNode called let say Map , which has an edge path that I defined (some simple polygon shape).

I am trying to figure out how to add a few other paths that will act as the inner edges of the Map . As if the “map” as a whole really had holes. Some forms of the inner border that can work with the Map as a whole: one path to the edge (as shown below)

enter image description here ©

I understand that there is a method that allows you to create SKPhysicsBody with bodies (some NSArray), for example,

 Map.physicsBody = [SKPhysicsBody bodyWithBodies:bodiesArray]; 

Does this method really generate what I showed in the image? Assuming bodiesArray contains 3 SKSpriteNode each with a specific path from using this method:

 + (SKPhysicsBody *)bodyWithEdgeChainFromPath:(CGPathRef)path 

creating a path like

  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 

I understand that an alternative would be to create 3 separate nodes with the location and shape of the alleged “holes”, but I am attached to avoid creating more nodes than I need. If someone can confirm what I'm trying to do, that’s right, or maybe offer an alternative that I don’t know about.

NOTE : IF what I am doing is correct, but I am missing something, I would appreciate if someone could show me the correct way to do what I am trying to do (even a simple example of a square with an inner smaller square was would be great). Thanks!

EDIT 1 : Below is a snippet of code that I use as an attempt to create “inner borders”. The problem here is that when both the outer and inner rectangles are drawn and displayed, when I add the inner rectangle to the Map bodyWithBodies , it fully controls collision detection, removing all contact management from the outer straight shell. When I delete bodyWithBodies , it returns to its normal state, showing both rectangles, the outer one has collision detection (does not allow me to go through), while the inner one has nothing ... so close

 // 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]; } 

EDIT 2 This approach works. Just adding a new node with the same properties as the outer rectangle:

 SKPhysicsBody *innerRectBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:innerRect]; innerRectBody.collisionBitMask = playerCategory; innerRectBody.categoryBitMask = wallCategory; SKNode *innerBoundary = [SKNode node]; innerBoundary.physicsBody = innerRectBody; [myWorld addChild: innerBoundary]; 

... but I would really like a cleaner solution that does not require additional nodes. thoughts?

+5
source share
2 answers

you are not doing anything here, I came up with an example where I created two extreme bodies with two physical bodies

// add bodies after a while using 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]; 

Remember that edges with red ends have low processor performance, so don't worry about performance until your polygon has so many edges.

+1
source

Your code to create the path and then use it in the physical body looks like it would work. Like your physical body from bodies. Unfortunately, I do not know that SKPhysicsBody can really support holes because you cannot flip the normals of the body. The way I read the documentation for apples is that it is designed to do things such as take two circle shapes and turn them into one body, rather than create a complex shape. The problem is that having a hole inside your larger shape would mean ignoring the collision in that area.

Below are some alternatives.

One of the options is that you can create your stages from several figures. For example, if you break the map into two parts (with a line passing through each figure) and create physical bodies for these purposes. Then make them overlapped and turn them into one body, then this may work. I made a diagram showing this (have mercy on its terrible quality, which you can still understand what it does (hopefully)). enter image description here

Another option would be to do it with a texture, it might hurt the preformation a bit, but if you can do it then it probably will work well.

 Map.physicsBody = SKPhysicsBody(texture: Map.texture, size: Map.size) 
0
source

Source: https://habr.com/ru/post/1242264/


All Articles