Cocos2D iPhone/Objective C Documentation

So even if you did manage to preserve the aspect ratio leaving bars at the top and bottom, would it even pass Apple review?

Well, all I can say is, my game is vector and has a black background, so the “bars” will be more like absence of art… If Apple rejects my update because of this, then it will be an indication that it is time for me to take down my game from the app store and abandon iOS completely.

I am currently working on modifying the CCDirectorIOS class to change the projection viewport scaling and positioning, I think it’s going to work… I hope… I’ll post my results as soon as I have something.

Cool, let us know how it goes!

Ok, I got it working, implementing “designWidth” and “designHeight” being my 768x1024 gameplay area… Basically I subclassed the CCDirector and overwrote a few methods which scaled the viewport to the aspect ratio, and then scaled the size of the buffer before it’s gets drawn.

Here’s the code:

AppDelegate:

self.director = (Director *)[Director sharedDirector];
[self.director setView:glView];
[self.director setDisplayStats:NO];
[self.director setAnimationInterval:1.0f / 60.0f];
[self.director enableRetinaDisplay:YES];
[self.director setProjection:kCCDirectorProjection2D];

Director.h

@interface Director : CCDirectorDisplayLink

-(CGSize)designSize;

@end

Director.m

#import "Director.h"

static const float designWidth = 768.0f;
static const float designHeight = 1024.0f;

@interface Director ()
@property (nonatomic) float scaleX;
@property (nonatomic) float scaleY;
@end

@interface CCDirectorIOS ()
-(void) setNextScene;
-(void) showStats;
-(void) calculateDeltaTime;
-(void) calculateMPF;
-(void) updateContentScaleFactor;
@end

@implementation Director

-(CGSize)winSize {
    return [self designSize];
}

-(CGSize)designSize {
    return CGSizeMake(designWidth, designHeight);
}

-(void)scaleToFit {
    CGSize size = _winSizeInPixels;
    self.scaleX = size.width / designWidth;
    self.scaleY = size.height / designHeight;
}

-(void)setProjection:(ccDirectorProjection)projection {
    [self scaleToFit];
    [super setProjection:projection];
}

-(void)setViewport {
    CGSize size = _winSizeInPixels;

    float targetAspectRatio = designWidth / designHeight;

    int width = (int)size.width;
    int height = (int)(width / targetAspectRatio);

    if (height > size.height) {
        height = size.height;
        width = (int)(height * targetAspectRatio);
    }

    int x = (size.width - width) / 2;
    int y = (size.height - height) / 2;
    glViewport(x, y, width, height);
}

-(void)drawScene {
    /* calculate "global" dt */
    [self calculateDeltaTime];

    CCGLView *openGLview = (CCGLView*)[self view];

    [EAGLContext setCurrentContext: [openGLview context]];

    /* tick before glClear: issue #533 */
    if( ! _isPaused )
        [_scheduler update: _dt];

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /* to avoid flickr, nextScene MUST be here: after tick and before draw.
     XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */
    if( _nextScene )
        [self setNextScene];

    kmGLPushMatrix();
    kmGLScalef(self.scaleX, self.scaleY, 1.0f);

    [_runningScene visit];

    [_notificationNode visit];

    if( _displayStats )
        [self showStats];

    kmGLPopMatrix();

    _totalFrames++;

    [openGLview swapBuffers];

    if( _displayStats )
        [self calculateMPF];
}

-(CGPoint)convertToGL:(CGPoint)uiPoint {
    kmMat4 transform;

    kmMat4 projection;
    kmGLGetMatrix(KM_GL_PROJECTION, &projection);

    kmMat4 modelview;
    kmGLGetMatrix(KM_GL_MODELVIEW, &modelview);

    kmMat4Multiply(&transform, &projection, &modelview);

    kmMat4 transformInv;
    kmMat4Inverse(&transformInv, &transform);

    // Calculate z=0 using -> transform*[0, 0, 0, 1]/w
    kmScalar zClip = transform.mat[14]/transform.mat[15];
    CGSize size = _winSizeInPoints;
    CGFloat scaledHeight = size.width / (designWidth / designHeight);
    CGFloat viewportYScale = size.height / scaledHeight;
    kmScalar xClip = (2.0 * uiPoint.x / size.width) - 1.0;
    kmScalar yClip = (1.0 - (2.0 * (uiPoint.y / size.height))) * viewportYScale;
    kmVec3 clipCoord = {xClip, yClip, zClip};

    kmVec3 glCoord;
    kmVec3TransformCoord(&glCoord, &clipCoord, &transformInv);

    //    NSLog(@"uiPoint: %@, glPoint: %@", NSStringFromCGPoint(uiPoint), NSStringFromCGPoint(ccp(glCoord.x, glCoord.y)));
    return ccp(glCoord.x / self.scaleX, glCoord.y / self.scaleY);
}

@end
1 Like

Nice @patrick99e99, glad you got it working! Now lets hope Apple aren’t too fussy about it! :crossed_fingers:

Awesome work guys!

1 Like

So, I have everything working… but the last problem I am finding is if I go into system preferences and set display zoom to “zoomed”… it seems like my touch detection gets kind of wonky.

Do you happen to know if there is any kind of offset that is applied to UITouch events or anything that I need to cancel out?

Sorry buddy, no idea.

https://medium.com/fantageek/pixel-and-point-in-ios-222b925cf1ae no idea if this article will help but definitely seems that the screen size is rescaled in zoomed mode. Maybe you could compare nativeBounds with your (768,1024) size and make adjustmnets?

Turns out how I was scaling my touches to the projection area was the problem… So I updated the code above with the new implementation. Now it works fine with zoomed in or not.

1 Like

Great work!