2

I need to detect touches in a circular shape, the problem is that while the shape looks like a circle the touchable area is still rectangular. How do I detect touches only if the user touches my circle?

This is what I'm doing now:

 // Here I add the Shape
_circle = [SKShapeNode node];
_circle.name = @"circle";
_circle.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[_circle setPath:CGPathCreateWithRoundedRect(CGRectMake(-70, -70, 140, 140), 70, 70, nil)];
_circle.strokeColor = _circle.fillColor = [UIColor colorWithRed:255.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:1.0];
[self addChild:_circle];
//...

// Listening to touches
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInNode:self];
    if (CGRectContainsPoint(_circle.frame, location)) {
        NSLog(@"Circle is touched");
    }
}
lisovaccaro
  • 32,502
  • 98
  • 258
  • 410
  • have a look at this question http://stackoverflow.com/questions/13291919/detect-touches-only-on-non-transparent-pixels-of-uiimageview-efficiently you might want to detect touches on non-transaprent bits only – Rachel Gallen Jul 12 '14 at 15:27
  • The problem is that I'm running a comparison like this on every frame,so probably checking the shape's pixels individually on each frame might be bad for performance – lisovaccaro Jul 12 '14 at 15:30

1 Answers1

0

If you are dealing with an actual circle, you can use math to get the result you want. You could just calculate the distance from the center of the circle to the touch point. If that distance is lower than radius of the circle, then you have a valid touch.

- (bool)pressed:(UITouch*) touch
{
    CGPoint location = [touch locationInNode:self];
    float hyp = sqrtf(powf(_button.position.x  - location.x,2) + powf(_button.position.y - location.y,2));
    if(hyp < _button.frame.size.width/2)
    {
        return true;
    } else {
        return false;
    }
}

However, with a rounded rect, this solution will not work.

You could however take a different approach by using the physics of SpritKit. What you would do is create a transparent node with a physics body, and have it move to the touch location. That should give you a collision between your node and the button.

Of course your button would need a proper physics body as well.

Not the ideal solution I think you were hoping for, but at this point there is not a simple and performance friendly one for SpriteKit.

update

Wanted to add one more option, which again is not ideal, but can completely remove touches outside of the shape. However, it has kind of the inverse issue as some of the edges will not be touch reactive.

What you could do is create a secondary touch object that is a plain rectangle made to be as large as it can without extending outside your rounded rect, and use that to do your touch detection.

Like I said, you'd have the inverse issue as the outer areas your touch rect doesn't cover will not be touch reactive. This functionality may or may not be as desirable, depending on the case. Just figured I'd throw it out there and let you decide.

prototypical
  • 6,731
  • 3
  • 24
  • 34
  • that doesn't seem like a bad idea, I already created the physics body because I was thinking something in that vein. – lisovaccaro Jul 12 '14 at 18:37
  • I already created two physics bodies `_button` and `_touchy`. Basically on a new touch I do `_touchy.position = touchLocation;` How do I check if it's colliding with `_button` afterwards? – lisovaccaro Jul 12 '14 at 18:56
  • That's a physics collision question. Best to not do development in the comments as answers get lost here. You asked a high level question about methods that could be used. What you are asking now is a specific question about physics and collision. Likely many that answer that specifically without me having to reiterate it! haha – prototypical Jul 12 '14 at 19:02
  • I tried collision detection and there are a lot of issues that make it hard to do or an overkill. I ended up calculating the distance from the touch to the center of the circle, just added it to the answer. Thanks – lisovaccaro Jul 13 '14 at 15:29
  • Personally, I feel that unless the object is really large to the point where that dead space in the rect is easy to click accidentally, it's a minor issue. I am going to add one more option, but it has the opposite flaw of making some parts of object not touch reactive. – prototypical Jul 13 '14 at 15:42
  • I see your point. But on my case it's a big circle. I think the best option is the radius one. Collision detection seems to only work when the objects touch due to gravity/physics, when you set the position of a physics body through code collisions aren't detected. – lisovaccaro Jul 13 '14 at 16:02
  • No, it will work. There is a breakout tutorial out there you can google for that has paddle and ball interacting. I just personally think it's overkill if this is a button or something. If it's a game object where precision is essential, it's a quality option depending on performance etc. – prototypical Jul 13 '14 at 16:11