Optimize My Touch

Discussion in 'iPhone/iPad Programming' started by neil.b, Dec 18, 2008.

  1. macrumors member

    neil.b

    Joined:
    Nov 20, 2008
    #1
    In my app view I'm detecting if the user has touch within one of 16 defined rectangles;

    Code:
    -(int) whichBoxIsTouched:(CGPoint)theTouch
    	{	
    	
    	NSArray *hitBoxArray = [NSArray arrayWithObjects:
    							@"{{64,404},{48,48}}",
    							@"{{112,404},{48,48}}",
    							@"{{160,404},{48,48}}",
    							@"{{208,404},{48,48}}",
    							@"{{64,356},{48,48}}",
    							@"{{112,356},{48,48}}",
    							@"{{160,356},{48,48}}",
    							@"{{208,356},{48,48}}",
    							@"{{64,308},{48,48}}",
    							@"{{112,308},{48,48}}",
    							@"{{160,308},{48,48}}",
    							@"{{208,308},{48,48}}",
    							@"{{64,260},{48,48}}",
    							@"{{112,260},{48,48}}",
    							@"{{160,260},{48,48}}",
    							@"{{208,260},{48,48}}",
    							nil];
    	
    	CGRect theHitRect;
    	for (int i = 0; i < [hitBoxArray count]; i++)
    	{
    		theHitRect = CGRectFromString([hitBoxArray objectAtIndex:i]);
    		if (CGRectContainsPoint(theHitRect, theTouch))
    		{
    			return i;
    		}
    	}
    	//if not found, return out-of-range value
    	return [hitBoxArray count];
    }
    I've been trying to look at ways to optimize the hit test. I thought of putting the CGRects in an array so that I don't have to do the CGRectFromString conversion in the loop but I can't figure out how to store the rect information in an array.

    Can anyone offer a different solution that would be faster than my current method?

    As you can see the hit rectangles are in fact all squares of the same size so maybe that fact can be used.

    Thanks
     
  2. macrumors regular

    Joined:
    Jun 18, 2008
    #2
    Since your hitBoxArray never changes why wouldn't you make that an instance variable and initialize it to be an array of the CGRects that you want instead of re-initializing the that array on every touch and then then converting every string to a CGRect on the fly?
     
  3. macrumors 68000

    Joined:
    Feb 12, 2008
    Location:
    Illinois
    #3
    What he said...if you're still wondering how that would look, here's the code.

    At the top of the class, under the import line and above the implementation, put:
    Code:
    static NSArray *hitBoxArray = nil;
    Now in the init method (or awakefromnib, viewwillappear, etc.) put:

    Code:
    hitBoxArray = [[NSArray init] initWithObjects:
    							CGRectMake(64,404,48,48),
    							CGRectMake(112,404,48,48),
    							CGRectMake(160,404,48,48),
    							CGRectMake(208,404,48,48),
    							CGRectMake(64,356,48,48),
    							CGRectMake(112,356,48,48),
    							CGRectMake(160,356,48,48),
    							CGRectMake(208,356,48,48),
    							CGRectMake(64,308,48,48),
    							CGRectMake(112,308,48,48),
    							CGRectMake(160,308,48,48),
    							CGRectMake(208,308,48,48),
    							CGRectMake(64,260,48,48),
    							CGRectMake(112,260,48,48),
    							CGRectMake(160,260,48,48),
    							CGRectMake(208,260,48,48),
    							nil]];
    Lastly, change what you gave us to:


    Code:
    -(int) whichBoxIsTouched:(CGPoint)theTouch
    	{	
    	for (int i = 0; i < [hitBoxArray count]; i++)
    	{
    		if (CGRectContainsPoint([hitBoxArray objectAtIndex:i], theTouch))
    		{
    			return i;
    		}
    	}
    	//if not found, return out-of-range value
    	return [hitBoxArray count];
    }
    Basically, what he told you, only here's the code for it.
     
  4. thread starter macrumors member

    neil.b

    Joined:
    Nov 20, 2008
    #4
    Thanks for the tips guys. :)

    I thought you couldn't put CGRects in an array - I'd tried a few ways without much success. I'll give your suggestion a try.
     
  5. thread starter macrumors member

    neil.b

    Joined:
    Nov 20, 2008
    #5
    That code throws up two errors.

    Firstly on the arrray init;

    Code:
    error: incompatible type for argument 1 of 'initWithObjects:'
    
    And then in the for...loop;

    Code:
    error: incompatible type for argument 1 of 'initWithObjects:'
    
    Any ideas?
     
  6. thread starter macrumors member

    neil.b

    Joined:
    Nov 20, 2008
    #6
    Sorted it. I created a NSObject class "HitBoxRect" that has a CGRect as a property;

    Interface:

    Code:
    @interface HitBoxRect : NSObject {
    	CGRect rect;
    }
    
    -(id) initWithCGRect:(CGRect)aRect;
    @property (nonatomic) CGRect rect;
    
    @end
    
    Implementation:

    Code:
    #import "HitBoxRect.h"
    
    @implementation HitBoxRect
    @synthesize rect;
    
    -(id) initWithCGRect:(CGRect)aRect
    {
    	rect = aRect;
    	return self;
    }
    
    @end
    Then created a NSMutableArray "hitBoxArray" and populated it;

    Code:
    -(void) initHitBoxArray
    {
    	hitBoxArray = [[NSMutableArray alloc] init];
    	NSArray *boxes = [NSArray arrayWithObjects:
    							@"{{64,404},{48,48}}",
    							@"{{112,404},{48,48}}",
    							@"{{160,404},{48,48}}",
    							@"{{208,404},{48,48}}",
    							@"{{64,356},{48,48}}",
    							@"{{112,356},{48,48}}",
    							@"{{160,356},{48,48}}",
    							@"{{208,356},{48,48}}",
    							@"{{64,308},{48,48}}",
    							@"{{112,308},{48,48}}",
    							@"{{160,308},{48,48}}",
    							@"{{208,308},{48,48}}",
    							@"{{64,260},{48,48}}",
    							@"{{112,260},{48,48}}",
    							@"{{160,260},{48,48}}",
    							@"{{208,260},{48,48}}",
    							nil];
    	
    	CGRect aRect;
    	HitBoxRect *hRect;
    	for (int i = 0; i < [boxes count]; i++)
    	{
    		aRect = CGRectFromString([boxes objectAtIndex:i]);
    		hRect = [[HitBoxRect alloc] initWithCGRect:aRect];
    		[hitBoxArray addObject:hRect];
    		[hRect release];
    	}
    }
    So I can then access the custom objects with;

    Code:
    -(int) whichBoxIsTouched:(CGPoint)theTouch
    {		
    	for (int i = 0; i < [hitBoxArray count]; i++)
    	{
    		if (CGRectContainsPoint([[hitBoxArray objectAtIndex:i] rect], theTouch))
    		{
    			return i;
    		}
    	}
    	//if not found, return out-of-range value
    	return [hitBoxArray count];
    }
    
     

Share This Page