1

I have been developing a tracking algorithm that would have work quite well if sprite kit didn't hit me with this...

I am trying to determine whether or not a CGPoint lies within the SKPhysicsBody of a given SKNode in my scene. The problem I am having is I can not seem to get SpriteKit to accurately tell me if the physicsbody does in fact contain that point.

Here is a sample of one of the bodies that may contain the point, and how I am testing to see if it does:

        SKSpriteNode *innerMap1 = [SKSpriteNode spriteNodeWithImageNamed:@"test"];
        // FYI - "test" is exactly 363x452. Did that to make sure scaling was not an issue
        innerMap1.physicsBody = [SKPhysicsBody bodyWithTexture:[SKTexture textureWithImageNamed:@"test"] size:CGSizeMake(363, 452)];
        innerMap1.position = CGPointMake(200, 100);
        innerMap1.physicsBody.dynamic = NO;
        innerMap1.name = @"testNode";

I then tried 2 different ways to see if the node contains the following point:

Method 1

    CGPoint controlPoint = CGPointMake(<xf>, <yf>);
    if ([innerMap1 containsPoint:controlPoint]) . . .

Method 2

    SKPhysicsBody *body = [self.physicsWorld bodyAtPoint:controlPoint];
    if ([body.node.name isEqualTo:@"testNode"]) . . .

For whatever reason, both methods are not helpful. Method 1 will just tell me if the point is within the frame box of the node, which defeats the purpose of creating a unique node shape from a texture.... and Method 2 for some strange reason tends to be extremely glitchy and inaccurate. I read there is roughly a 15.5px overscale, but the results I am getting are no where near this minimal.

I could also just manually create a CGMutablePathRef and use the following:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint touchLocation = [touch locationInNode:self.scene];

    if (CGPathContainsPoint(pathRef, nil, touchLocation, NO)) {
        // If we are here it means user did touche physic body.
    }
}

but again, I want custom shapes that dont require individual path boundary building.

SO, my question, is what am I doing wrong? I was quite certain that Method 2 would have been the best solution, or at least work, but I can't seem to understand why it acts so strangely. Perhaps I am missing something with one of the 2 approaches that would fix my issues. I wish there was a method that could return a BOOL for points that lay within an SKTexture, but of course there are none. That is why using the physics body should have been the key - as it represents the exact image dimensions and points. Any suggestions will be greatly appreciated. Thanks!

Will Von Ullrich
  • 2,129
  • 2
  • 15
  • 42
  • maybe try creating a 1px physics body within the physics body youre trying to detect. then try moving it one pixel each direction and see if any collisions are detected. – hamobi Feb 29 '16 at 17:23
  • I could try that I guess - that might work. I figured out though what the issue is if you could please look here http://stackoverflow.com/questions/35705597/prevent-location-offset-with-spritekit-camera-node – Will Von Ullrich Feb 29 '16 at 17:25
  • hard for me to follow whats going on. I've done gameplaykit pathfinding but only when it was a grid map. havent done it with physics objects. sorry – hamobi Feb 29 '16 at 17:27
  • no worries. all it does is take an object and find the path to (in my case) the ball. If there are physics bodies within that path, it finds the shortest distance around it, hence that little red dot. For some reason the camera centerOnNode is greatly impacting the physics body positions. as if they are not moving with the camera – Will Von Ullrich Feb 29 '16 at 17:29

1 Answers1

1

Many time I've found strange issues with CGPathContainsPoint output. So, I've decide to write this workaround:

P.S. (this solution working on Swift 2.x)

let path: UIBezierPath = UIBezierPath.init(CGPath: myPath)
let copyPath = CGPathCreateCopyByStrokingPath(myPath, nil, path.lineWidth, path.lineCapStyle, path.lineJoinStyle, path.miterLimit )
if CGPathContainsPoint(copyPath, nil, myPoint, false) { 
   // ok path contain this point
}
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133