Question

Any simple method to test if an SKPhysicsBody entirely contains another?

Something like bodyA contains every point of bodyB, or so.

Just wanted to ask you before implement some 2D math helpers to do this with additional "meta"-CGPaths attached to a given node or something.

Was it helpful?

Solution 3

Made a category for this.

BOOL putInto = [bodyA containsBody:bodyB];

Get the category SKPhysicsBody+Containment from GitHub, it works only for path-path containment for now, gonna finish it up soon for circles as well.

The solution is two fold.

The first part is CGPath works. You get CGPathRef representation of bodyA transformed state, then iterate over each point of the bodyB, and test for containment. This works fine for path-path type tests, but not for circle-circle, and even less for circle-path.

The second part is to wrap this up into an SKPhysicsBody category, to encapsulate all the implementation details. This is surprisingly pauinful.

When you ask for an SKPhysicsBody instance from SKPhysicsBody class, you'd expect an SKPhysicsBody object in return. According to some design decision at Apple, it will spit you up a PKPhysicsBodyinstance (part of internal PhysicsKit), which of course won't have any instance method from the category you made for SKPhysicsBody. Extending that class can be carried out only via method / property swizzlings, so this issue put a weight on this containment category.

OTHER TIPS

There is no straightforward method, but there are some that you may find useful. If your bodies are rectangular and match their nodes' frames, this might be worth trying:

BOOL isContained = CGRectContainsRect(bodyA.node.frame, bodyB.node.frame); // bodyA is the container, bodyB is examined for being contained

If your bodies are polygons created with completely arbitrary paths, then finding their containment is going to be a complex task. It's a long shot, but you may get some initial approximation using the above method combined with CGPathGetBoundingBox - that will return rectangles around your polygons, which you can then check for overlapping (use CGRectInset as needed).

There is also an SKPhysicsWorld method that comes close: -(SKPhysicsBody *)bodyInRect:(CGRect)rect, yet it only returns an SKPhysicsBody that intersects a rectangle.

I know this thread is super old but it's 2017 and I was searching for an answer and ended up finding my own by tinkering with my code. Hopefully this helps someone out! It works with circles and ovals.

-(void)didBeginContact:(SKPhysicsContact *)contact {

// get the path of the physics body ( contact bodyA )
CGPathRef path = CGPathCreateWithEllipseInRect(CGRectMake(contact.bodyA.node.position.x - contact.bodyA.node.frame.size.width/2, contact.bodyA.node.position.y - contact.bodyA.node.frame.size.height/2, contact.bodyA.node.frame.size.width, contact.bodyA.node.frame.size.height), nil);

// check if that path contains the physics body point of BodyB
if (CGPathContainsPoint(path, NULL, contact.bodyB.node.position, FALSE)) {

    NSLog(@"CONTAINS POINT player body B");

}

}`

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top