# Coordinate and positioning problem on iOS with cocos2d-x

I'm using cocos2d-x alongside with Marmalade and running some tests and tutorials before starting an actual project with them. So far things are working reasonably well on the windows simulator, Android and even on Blackberry's Playbook, but on iOS devices (iPhone and iPad) the positioning seems to be off.

To make things clearer, I put together a scene that just draws an image in the middle of the screen. It worked as expected on everything else, but this is the result I got on an iPhone:

To get the coordinates for the center of the screen I'm using the VisibleRect class from the TestCpp sample. It just uses sharedOpenGLView to get the visible size and visible origin, and calculate the center from that.

CCSprite* test = CCSprite::create("Ball.png", CCRectMake(0, 0, 80, 80) );
test->setPosition( ccp(VisibleRect::center().x, VisibleRect::center().y) );



Also I have a noBorder policy set on AppDelegate:

CCEGLView::sharedOpenGLView()->setDesignResolutionSize(designSize.width, designSize.height, kResolutionNoBorder);


One funny thing is that I tried to deploy the TestCpp sample project to some iOS devices and it worked reasonably well on the iPhone, but on the iPad the application was only being drawn on a small portion of the screen - just like what happened on the iPhone when I tried using the ShowAll policy.

Try this:

CCSize winSize = CCDirector::sharedDirector()->getWinSize();
CCSprite* test = CCSprite::create("Ball.png", CCRectMake(0, 0, 80, 80) );
test->setPosition( ccp(winSize.width * 0.5, winSize.height * 0.5) );



It works for me.

also try using this sizes:

CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();


You will get the visible size and the origin, so you can calculate the real size of the screen, I hope it helps.

• Hey, thanks for the aswer! So, the VisibleRect class got size and origin from CCEGLView (e.g. CCEGLView::sharedOpenGLView()->getVisibleSize() ). I tried switching to getting those values from sharedDirector, but it didn't do much difference. However I did find out that my problem is actually related to the landscape orientation on iOS. Portrait works as it should, but on landscape, width and height are swapped (as well as x and y on touch events). I'll investigate things further and bring this matter to the cocos2d-x forums and I'll report back here when I come to a conclusion. – Vexille Jul 18 '13 at 19:11
• I'm glad to help, if you get an answer, please post it! – nosmirck Jul 23 '13 at 17:22
• Still no answer from the cocos2d-x forums... I'll try bumping the topic once and see if anybody can help. I really hope to get this solved, seems to be a pretty big issue. – Vexille Jul 23 '13 at 20:10
• maybe this could help you cocos2d-x.org/projects/cocos2d-x/wiki/Device_Orientation – nosmirck Jul 23 '13 at 20:22
• Nah, I've looked through that page before. Problem is, it's deprecated (see the "need to be updated" thing in the title). the setDeviceOrientation() method doesn't even exist in CCDirector anymore... Anyway, this is the topic I created in the forums: cocos2d-x.org/boards/6/topics/31964 – Vexille Jul 23 '13 at 20:32

Alright, after more digging I finally came across a more definitive solution. I posted the solution in my forum post on the issue on cocos2d-x's forum, but I'll post it here too just in case.

So the real issue is that on iOS devices, device orientation isn't reported correctly, and on Landscape mode, the screen coordinates will have the width and height values swapped. To fix that, I basically used the solution described by Tim Closs in this forum post for rotating the projection matrix, with minor tweaks:

New method in AppDelegate:

    /**
* Update the projection, based on an input angle, and store back the new w, h
*
* @param angle 0, 90, 180 or 270
* @param w the new width of the virtual display
* @param h the new height of the virtual display
*/
virtual void updateProjection(float angle, float& w, float& h);


Method implementation:

void AppDelegate::updateProjection(float angle, float& w, float& h) {
if (IwGLGetInt(IW_GL_VIRTUAL_WIDTH) >= 0) {
w = (float)IwGLGetInt(IW_GL_VIRTUAL_WIDTH);
h = (float)IwGLGetInt(IW_GL_VIRTUAL_HEIGHT);
}
else {
w = (float)s3eSurfaceGetInt(S3E_SURFACE_WIDTH);
h = (float)s3eSurfaceGetInt(S3E_SURFACE_HEIGHT);
}

if ((angle == 90.0f) || (angle == 270.0f)) {
// Swap w and h
float oh = h;
h = w;
w = oh;
}

CCEGLView::sharedOpenGLView()->setFrameSize(w, h);
kmGLMatrixMode(KM_GL_PROJECTION);
kmGLRotatef((float)angle, 0, 0, 1);
kmMat4 orthoMatrix;
kmMat4OrthographicProjection(&orthoMatrix, 0, w, 0, h, -1024, 1024 );
kmGLMultMatrix(&orthoMatrix);
kmGLMatrixMode(KM_GL_MODELVIEW);
}


Call to AppDelegate::updateProjection in AppDelegate::applicationDidFinishLaunching:

bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
CCDirector *pDirector = CCDirector::sharedDirector();
pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());
pDirector->setProjection(kCCDirectorProjection2D);

// Set projection
float w, h;
float angle = s3eSurfaceGetInt(S3E_SURFACE_DEVICE_BLIT_DIRECTION) * 90.0f;

// Workaround for ios devices, force rotation
int os = s3eDeviceGetInt(S3E_DEVICE_OS);
if (os == S3E_OS_ID_IPHONE || os == S3E_OS_ID_OSX)
angle = 90;

updateProjection(angle, w, h);

// Rest of method ...
}


The original solution also defined the virtual dimensions on marmalade's icf file, thus overriding cocos2d-x's scaling system, but I chose to stick with what cocos2d-x provides and it works just as well. The biggest difference was explicitely setting the angle to 90 for all iOS devices, since the original problem is that landscape orientation wasn't being detected in the first place.

Also it should be noted that after implementing this solution, all my other workarounds for this issue became unnecessary, thus had to be removed for the correct behavior to take place.

Hope this can be of help to someone!