Touch location coordinates squeezed

Apprentice
Posts: 9
Joined: 2011.07
Post: #1
Hello all,

I have a strange problem maybe somebody can help me with. I'm placing a controller near the status bar area and it's not working right. I'm using base SDK 4.3 and Cocos 0.99.5 and deployment target set to iOS 3.0. The following happens on the actual device. I've tested on both a 2nd gen and 3rd gen iPod Touch. It actually works fine in the simulator registering touches in the right places right up to the edge.

What happens is this. I have two controllers one at each end (one near the home button and the other near the status bar in portrait mode). This circular controller area is 40 points wide on the iPhone/Touch. At the home button side I can get touch locations in nodespace of -11 to +20. (Should be -20 to +20). I can't get any closer than 9 points to that edge and have it detect the touch. The actual touch coordinate is y=471 at that end. Ok seems somewhat normal to have an area that isn't sensitive to touch.

At the other end is where the real problem lies. At the status bar end I have the status bar hidden (By using both the plist and with the standard [application setStatusBarHidden:YES animated:NO] code added to applicationDidFinishLaunching). Now when I try to touch the controller at this end the closest I can get to the edge is 20 points. Also the touch coordinate is y=1 which corresponds to -19 in my controllers nodespace. So my controller jumps to the edge of the screen even though I'm touching a tiny spot 20 pixel from the edge. This is also right in the center on the controller, so the controller shouldn't even move (it follows the touch) and should be at y=0 in the controllers nodespace.

Now why are my view's touch coordinates starting at y=1 below where the status bar normally ends at what should be y=21? The coordinates go from 1 to 480 so there isn't a direct mapping to the touch coordinates and the actual openGL coordinates. The 'location in window' is y=1 and the 'location in view' is also y=1 (from the UITouch object when a touch is registered 20 points from the edge of the screen). It's as though the touch coordinates are squished.

Here's the relevant code:

Code:
- (void) applicationDidFinishLaunching:(UIApplication*)application
{

[application setStatusBarHidden:YES animated:NO];
// Init the window
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

// Try to use CADisplayLink director
// if it fails (SDK < 3.1) use the default director
if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )
[CCDirector setDirectorType:kCCDirectorTypeDefault];

CCDirector *director = [CCDirector sharedDirector];

// Init the View Controller
viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
viewController.wantsFullScreenLayout = YES;

//
// Create the EAGLView manually
// 1. Create a RGB565 format. Alternative: RGBA8
//    2. depth format of 0 bit. Use 16 or 24 bit for 3d effects, like CCPageTurnTransition
//
//
EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
pixelFormat:kEAGLColorFormatRGB565    // kEAGLColorFormatRGBA8
depthFormat:0     // GL_DEPTH_COMPONENT16_OES
];

// attach the openglView to the director
[director setOpenGLView:glView];

// Set multiple touches on
[glView setMultipleTouchEnabled:YES];

//    // Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices
if( ! [director enableRetinaDisplay:YES] )
CCLOG(@"Retina Display Not supported");

//
// VERY IMPORTANT:
// If the rotation is going to be controlled by a UIViewController
// then the device orientation should be "Portrait".
//
// IMPORTANT:
// By default, this template only supports Landscape orientations.
// Edit the RootViewController.m file to edit the supported orientations.
//
//
// commented out following lines to force portrait mode.
//#if GAME_AUTOROTATION == kGameAutorotationUIViewController
[director setDeviceOrientation:kCCDeviceOrientationPortrait];
//#else
//    [director setDeviceOrientation:kCCDeviceOrientationLandscapeLeft];
//#endif

[director setAnimationInterval:1.0/60];
[director setDisplayFPS:YES];

// make the OpenGLView a child of the view controller
[viewController setView:glView];

// make the View Controller a child of the main window
[window addSubview: viewController.view];
[window makeKeyAndVisible];

// Default texture format for PNG/BMP/TIFF/JPEG/GIF images
// It can be RGBA8888, RGBA4444, RGB5_A1, RGB565
// You can change anytime.
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];

// Removes the startup flicker
[self removeStartupFlicker];

// Run the intro Scene
[[CCDirector sharedDirector] runWithScene: [MyScene node]];
}[hr]
@implementation RootViewController

/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
}
return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/

/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
*/

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOr​ientation {

//
// There are 2 ways to support auto-rotation:
// - The OpenGL / cocos2d way
// - Faster, but doesn't rotate the UIKit objects
// - The ViewController way
// - A bit slower, but the UiKit objects are placed in the right place
//

#if GAME_AUTOROTATION==kGameAutorotationNone
//
// EAGLView won't be autorotated.
// Since this method should return YES in at least 1 orientation,
// we return YES only in the Portrait orientation
//
return ( interfaceOrientation == UIInterfaceOrientationPortrait );

#elif GAME_AUTOROTATION==kGameAutorotationCCDirector
//
// EAGLView will be rotated by cocos2d
//
// Sample: Autorotate only in landscape mode
//
if( interfaceOrientation == UIInterfaceOrientationLandscapeLeft ) {
[[CCDirector sharedDirector] setDeviceOrientation: kCCDeviceOrientationLandscapeRight];
} else if( interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
[[CCDirector sharedDirector] setDeviceOrientation: kCCDeviceOrientationLandscapeLeft];
}

// Since this method should return YES in at least 1 orientation,
// we return YES only in the Portrait orientation
return ( interfaceOrientation == UIInterfaceOrientationPortrait );

#elif GAME_AUTOROTATION == kGameAutorotationUIViewController
//
// EAGLView will be rotated by the UIViewController
//
// Sample: Autorotate only in landscpe mode
//
// return YES for the supported orientations

return ( UIInterfaceOrientationIsLandscape( interfaceOrientation ) );

#else
#error Unknown value in GAME_AUTOROTATION

#endif // GAME_AUTOROTATION

// Shold not happen
return NO;
}

//
// This callback only will be called when GAME_AUTOROTATION == kGameAutorotationUIViewController
//
#if GAME_AUTOROTATION == kGameAutorotationUIViewController
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrient​ation duration:(NSTimeInterval)duration
{
//
// Assuming that the main window has the size of the screen
// BUG: This won't work if the EAGLView is not fullscreen
///
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGRect rect;

if(toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
rect = screenRect;

else if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
rect.size = CGSizeMake( screenRect.size.height, screenRect.size.width );

CCDirector *director = [CCDirector sharedDirector];
EAGLView *glView = [director openGLView];
float contentScaleFactor = [director contentScaleFactor];

if( contentScaleFactor != 1 ) {
rect.size.width *= contentScaleFactor;
rect.size.height *= contentScaleFactor;
}
glView.frame = rect;
}
#endif // GAME_AUTOROTATION == kGameAutorotationUIViewController

- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}

- (void)dealloc {
[super dealloc];
}

@end[hr]
And here's the beginning of my ccTouchBegan method:

Code:
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint location = [[CCDirector sharedDirector] convertToGL:[touch locationInView:[touch view]]];
location = [self convertToNodeSpace:location];
Quote this message in a reply
Apprentice
Posts: 9
Joined: 2011.07
Post: #2
I also tested this with Apple's Touches test sample project. I get the same problem. The touch range goes from 0 to 470. However the 0 point begins 20 points from the edge of the screen at the status bar end (even with the status bar hidden). The point 470 also is about 10 points from the home button edge. This is on an actual device. It works perfectly fine in the simulator!
This gives a touch range of 480 points over a space of 460 pixels. So touch events near the status bar are out of whack by 20 points...
Quote this message in a reply
Apprentice
Posts: 9
Joined: 2011.07
Post: #3
This is on a 2nd gen and 3rd gen ipod Touch. Can somebody test on an iPhone 4? The iPhone 4 should have twice the touch resolution and I'm wondering if they fixed this other issue as well.

I also tested the free game "Touch Hockey: FS5" and it has the exact same issue. You can't grab the paddle near the status bar area unless you're a good 20 points in from the edge. Yet the opposite side near the home button can grab a paddle right near the screen edge.
Quote this message in a reply
Apprentice
Posts: 9
Joined: 2011.07
Post: #4
From Apple:

"Apple is aware of the problem, and a bug report has been filed. This is possibly related to the OS's tendency to register touches several pixels above the physical contact point. It's not always possible to see values at the very extremes of the device due to a lack of sensors beyond the edges of the screen.

For the time being, you could work around the issue by offsetting the touches back to the expected range. Make sure to key that offsetting code to the version of iOS on which they determined the bounds, since that will change when/if Apple fixes this bug."
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  how to convert screen coordinates to world coordinates ishaq 4 6,491 Mar 8, 2009 10:11 AM
Last Post: RhinosoRoss