I have created an SKSpriteNode
called let's say Map that has an edge path that I have defined (some simple polygon shape).
What I am trying to figure out is how to add several other edge paths that would act as interior edges of the Map. As if the "map" as a whole did in fact have holes. Some sort of inner boundary shapes that could act with Map as a whole: one edge path (as shown below)
©
I understand that there is a method that allows for creating an SKPhysicsBody
with bodies (some NSArray), like such
Map.physicsBody = [SKPhysicsBody bodyWithBodies:bodiesArray];
Does this method in fact generate what I have shown in the image? Assuming that the bodiesArray
contains 3 SKSpriteNode
's each with a defined path from using such method:
+ (SKPhysicsBody *)bodyWithEdgeChainFromPath:(CGPathRef)path
, with creating the path like such
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 intended "holes", but I am tying to avoid creating more nodes than I need. If anyone can confirm what I am trying to do is correct, or perhaps suggest an alternative that I am unaware of.
NOTE: IF what I am doing is correct but I am missing something, I would appreciate it if someone can 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 would be great). Thanks!
EDIT 1:
Below is the code snippet that I am using as an attempt to create the "inner boundaries". This issue here, is that while both the outer and inner rect's are drawn and shown, when I add the inner rect to the Map bodyWithBodies
, it takes full control of the collision detection, removing all contact control from the outer rect shell. When I remove the bodyWithBodies
it goes back to normal with showing both rects, the outer has collision detection (does not allow me to pass 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..by just adding a new node with the same properties as the outer rect:
SKPhysicsBody *innerRectBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:innerRect];
innerRectBody.collisionBitMask = playerCategory;
innerRectBody.categoryBitMask = wallCategory;
SKNode *innerBoundary = [SKNode node];
innerBoundary.physicsBody = innerRectBody;
[myWorld addChild: innerBoundary];
...but I would very much like a cleaner solution that does not require additional nodes..thoughts?
you are doing nothing wrong here i come with an example where i created two edge rect bodies with two physics bodies
//adding bodies after some time 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 edge bodies comes with low cpu overhead so don't worry about performance untill your polygon don't have so many edges.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With