Ashraf
Ashraf

Reputation: 2632

Check if UIImage is on the top of view

I have a small question, I have a code to generate 200 UIImages in random positions and rotations.

I need to detect the touch event on these images, but I need to check if the touched UIImage is not covered by any other image (even if they intersect in a small area).

Can anybody help me on this?

BTW : I'm trying to do something similar to this game : http://www.dressup247.com/game/1014/Bank-Note-Stack.html

Upvotes: 1

Views: 472

Answers (3)

beryllium
beryllium

Reputation: 29767

I would suggest to make all images as UIButton's with background image and set for all buttons one action. One more advise - set tag order for every button from most low-lying to most high-lying (and store biggest tag in some iVar). You can do it when layout is generated. It allows you to detect how many views lay over tapped view.

Use CGRectIntersectsRect intersecting views.

-(IBAction)banknotTapped:(UIButton*)sender{
    int tag = sender.tag

    NSMutableArray *highestViews = [NSMutableArray array];

    for (int i=sender.tag; i < biggestTag; ++i){
       UIView *v = [self.view viewWithTag:i];
       if (CGRectIntersectsRect(sender.frame, v.frame) ) // it allows to find intersecting views 
           [highestViews addObject:v];
    }
}

Now highestViews will contain all highest views that intersect with sender.

Note: tags allow you to detect views, but if you will delete images from superview then it can lead to problems since tag order will broken. Hide views instead of deleting or follow @Costique method in order to determine views order.

Upvotes: 3

Tommy
Tommy

Reputation: 100622

While I'd suggest that it would be faster to do this mathematically, defining the banknotes as rectangles and testing for overlap using something like the separating axes theorem, that's obviously not what you're asking and not suitable for general case images.

So I'd suggest that you create a CGBitmapContext the same size as your play area and that when seeding your play area, for each note you place you do something like:

  • assign new, as yet unused colour to the bank note
  • draw it to the bitmap context at its destination position, but as a solid object of the assigned colour — so you preserve the outline of the original shape but at each pixel you draw either the solid, assigned colour or no colour at all
  • count how many pixels in the entire context are now the assigned colour, store that with your object representing the note

Subsequently, when the game starts run through the buffer and count how many of each assigned colour. All notes that have the same number stored as are currently visible are on top. Whenever a note is removed, redraw all the others in order and do the colour count once.

Note that you're not doing the colour count on the total buffer once per note, just once in total. So it's a fixed cost and probably occurs less often than once per tap.

Probably the easiest way to do the drawing as a single colour is to create a mask version of each graphic when it's loaded and then to draw that with a suitable tint. There's an introduction to alpha masks here; you'll probably want to create a custom bitmap image context rather than using the implicit one returned by UIGraphicsGetCurrentContext and to post filter to test the output alpha — pushing down to 0 if its less than some threshold, up to 255 otherwise.

Upvotes: 1

Costique
Costique

Reputation: 23722

You can use the following snippet to determine the order of a subview in its parent view:

NSUInteger order = [containerView.subviews indexOfObjectIdenticalTo: subview];

The less the order, the "higher" the subview is. The topmost subview will have zero order.

Upvotes: 1

Related Questions