Search code examples
objective-ciosnsmutablearrayuitouchtouchesbegan

change [touches anyObject] to touches with any objects in array


so I have a mutable array that holds several circles which are UIViews. right now I have my touches began method setup like this.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];

    CGPoint touchLocation = [touch locationInView:self.view];

    for (Circle *circle in playerOneCircles)
    {
        if ([circle.layer.presentationLayer hitTest:touchLocation])
        {
            [circle playerTap:nil];
            break;
        } 
    }   
}

this works fine. but it gives problems with overlapping views. I want other UIviews to also respond to the touchesbegan method (that would then trigger other methods). but if 2 objects would overlap then my touchesbegan would trigger the wrong method.

so I would like to define multiple UITouches that only respond to certain objects instead of anyObject. how would I have to define the UITouch to only work with objects from my mutable array?


Solution

  • EDIT

    Added comments to answer your comment to explain the code.

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        // We want to find all the circles that contain the touch point.
        // A circle does not have to be "on top" (or even visible) to be touched.
        // All circles that contain the touch point will be added to the touchedCircles set.
        NSMutableSet *touchedCircles = [NSMutableSet set];
    
        // To support multiple touches, we have to look at every touch object.
        for (UITouch *touch in touches) {
            CGPoint touchLocation = [touch locationInView:self.view];
            // Search through our collection of circle objects.  Any circle that
            // contains this touch point gets added to our collection of touched
            // circles.  If you need to know which UITouch is "touching" each circle,
            // you will need to store that as well.
            for (Circle *circle in playerOneCircles) {
                if ([circle containsPoint:touchLocation]) {
                    [touchedCircles addObject:circle];
                }
            }
        }
    
        // We have completed our search for all touches and all circles.  If
        // and circle was touched, then it will be in the set of touchedCircles.
        if (touchedCircles.count) {
            // When any circle has been touched, we want to call some special method
            // to process the touched circle.  Send the method the set of circles, so it
            // knows which circles were touched.
            [self methodAWithTouchedCircles:touchedCircles];
        } else {
            // None of our circles were touched, so call a different method.
            [self methodB];
        }
    }
    

    You would implement containsPoint for a Circle something like this...

    - (BOOL)containsPoint:(CGPoint)point
    {
        // Since each of our objects is a circle, to determine if a point is inside
        // the circle, we just want to know if the distance between that point and
        // the center of the circle is less than the radius of the circle.
        // If your circle is really contained inside a view, you can compute the radius
        // as one-half the width of the frame.
        // Otherwise, your circle may actually have its own radius property, in which case
        // you can just use the known radius.
        CGFloat radius = self.frame.size.width *.5;
    
        // This is just the Pythagorean Theorem, or instance formula.
        // distance = sqrt((x0-x1)^2 + (y0-y1)^2)
        // and we want to check that
        //     distance < radius
        // By simple algebra, that is the same as checking
        //     distance^2 < radius^2
        // which saves us from having to compute the square root.
        CGFloat diffX = self.center.x - point.x;
        CGFloat diffY = self.center.y - point.y;
        return (diffX*diffX) + (diffY*diffY) < radius*radius;
    }