iPhone 5 vs iPhone 4 Screen sizing - iphone

I have been developing a cocos2d app for the iPhone. I have been testing it solely on my iPhone 5. Everything looks great on it, but when I test it on the 3.5 inch simulator iPhone, some buttons go missing and some labels get misplaced.
I was wondering why this happens? I had thought that everything is positioned via the cocos2d grid which then converts it into pixels, so no matter the screen size the layout should look the same.
I think the problem might be due partly to the fact that when I set the position of a menu item, (0,0) puts it at the center of the screen. I don't know why this is.
Any advice on what is going on?
iPhone 5 on the left, simulator (3.5 inch) left.
Here is the code for this screen:
CCSprite *title = [CCSprite spriteWithSpriteFrameName:#"highscoresTitle.png"];
[self addChild:title];
title.position = ccp([CCDirector sharedDirector].winSize.width/2, [CCDirector sharedDirector].winSize.height-title.contentSize.height-15);
background.position = ccp([CCDirector sharedDirector].winSize.width/2, [CCDirector sharedDirector].winSize.height/2);
play = [CCMenuItemSprite itemWithNormalSprite:[CCSprite spriteWithSpriteFrameName:#"playNew.png"] selectedSprite:[CCSprite spriteWithSpriteFrameName:#"playNew.png"] target:self selector:#selector(playScene:)];
play.position = ccp(0, -200);
CCLabelTTF *backLabel = [CCLabelTTF labelWithString:#"BACK" fontName:#"RBNo2-Light-Alternative" fontSize:25];
CCMenuItemLabel *goBack = [CCMenuItemLabel itemWithLabel:backLabel target:self selector:#selector(back:)];
goBack.position = ccp(0, -260);
CCMenuItemSprite *gameicon = [CCMenuItemSprite itemWithNormalSprite:[CCSprite spriteWithSpriteFrameName:#"gameCenter.png"] selectedSprite:[CCSprite spriteWithSpriteFrameName:#"gameCenter.png"] target:self selector:#selector(gameIcon:)];
gameicon.position = ccp(0, -150);
CCMenu *menu = [CCMenu menuWithItems:play,goBack, gameicon, nil];
[self addChild:menu z:0];
for(int i = 0; i<5 && i<length; i++){
NSString *temp = [NSString stringWithFormat:#"%d: %d", i+1,[[highscores objectAtIndex:i]intValue]];
CCLabelTTF *label = [CCLabelTTF labelWithString:temp fontName:#"RBNo2-Light-Alternative" fontSize:20];
label.position = ccp([CCDirector sharedDirector].winSize.width/2, 350-i*30);
label.visible = YES;
[self addChild:label z:100 tag:1];
}
NSString *temp = [NSString stringWithFormat:#"Last Score: %d", newHighscore];
CCLabelTTF *label = [CCLabelTTF labelWithString:temp fontName:#"RBNo2-Light-Alternative" fontSize:20];
label.position = ccp([CCDirector sharedDirector].winSize.width/2, 415);
label.visible = YES;
[self addChild:label z:100 tag:1];
Here is another example with sliders: (iPhone 5 left)
And here is the code for the sliders:
sliderCtl = [[UISlider alloc]initWithFrame:CGRectMake(100, 460, 200, 0)];
//[sliderCtl.layer setAffineTransform:CGAffineTransformMakeRotation(3.141/2)];
[sliderCtl addTarget:self action:#selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
sliderCtl.backgroundColor = [UIColor clearColor];
sliderCtl.value = 1.0;
[[[[CCDirector sharedDirector] openGLView] window] addSubview:sliderCtl];
sliderEff = [[UISlider alloc]initWithFrame:CGRectMake(100, 402, 200, 0)];
[sliderEff addTarget:self action:#selector(effectsSlider:) forControlEvents:UIControlEventValueChanged];
sliderEff.backgroundColor = [UIColor clearColor];
sliderEff.value = 1.0;
[[[[CCDirector sharedDirector] openGLView] window] addSubview:sliderEff];
Thanks a lot.

Most likely, this answer will disappoint you. iPhone 5 has a number of pixels along its long edge that is different from all previous models. The coordinate system you use for placing objects in your scene is point, where 1 pt equals 2 px on devices with Retina displays.
You do make use of winSize which is provided to you by the CCDirector. This indeed helps you calculating relative positions, for example in order to center along the horizontal as I see it in some places of your code, e.g. for label. You alone are responsible for positioning your objects, with some help from anchorPoint, winSize, and related properties.
Specific example: You place goBack at a relative position of -260 pt. Note that your menu is centered on the screen by default. On an iPhone 4S and every previous model, this means an absolute position of 480 pt / 2 - 260 pt = -20 pt. No surprise that button is off screen. You will have to test for winSize.height and adjust accordingly.

I have run into the same issues and am now using the UIDevice Extension library from GitHub at the following link to identify the device. This is a little overkill unless you use other items from the identified device besides just screen size but thought you might be able to use it since I tend to always run into more needs by device type.
https://github.com/erica/uidevice-extension

Related

vertical scrollable CCLayerColor issue

i'm trying to do a scrollable layer with cocos2d
what i want is for the layer to start scrolling from the top to bottom but no matter what i do when it enters the scene the layer is positioned at (0,0) aka..bottom
i've tried a couple of things but nothing seems to work
-(id) init
{
if( (self=[super init] )) {
self.isTouchEnabled = YES;
isDragging = NO;
yvel = 0.0f;
contentHeight = 1000.0f;
scrollLayer = [CCLayerColor layerWithColor:ccc4(200, 200, 200, 240)];
scrollLayer.contentSize = CGSizeMake(320,contentHeight);
scrollLayer.anchorPoint = ccp(0,1);
scrollLayer.position = ccp(0, 480);
[self addChild: scrollLayer];
CCLabelTTF *label = [CCLabelTTF labelWithString:[NSString stringWithFormat:#"test label"]
fontName:#"Marker Felt"
fontSize:24];
label.position=ccp(100, 100);
[scrollLayer addChild:label];
[self scheduleUpdate];
}
return self;
}
the other methods are update and touches handlers so the problem couldn't be there
with this code...shouldn't it initialize with the content at the top left of the screen?
after a painful few hours i finally solved the problem...but i still dont know why it works
instead of scrollLayer.position = ccp(0, 480); i replaced with scrollLayer.position =ccp(0,-contentHeight); and deleted scrollLayer.anchorPoint = ccp(0,1); cuz it wasnt doing anything
and i have absolutely no idea why it works
can someone explain this?

Mirror iPhone on external display with cocos2d

I want to reproduce my iPhone display for demoing purposes. I've tried
this and this, but both give me a black screen. Finally, I headed out to make my own solution. Here's what I have:
// Check for external screen.
if ([[UIScreen screens] count] > 1) {
externalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Internal display is 0, external is 1.
externalScreen = [[[UIScreen screens] objectAtIndex:1] retain];
screenModes = [externalScreen.availableModes retain];
UIScreenMode *desiredMode = [screenModes objectAtIndex:0];
externalScreen.currentMode = desiredMode;
externalWindow.screen = externalScreen;
[screenModes release];
[externalScreen release];
CGRect rect = CGRectZero;
rect.size = desiredMode.size;
externalWindow.frame = rect;
externalWindow.clipsToBounds = YES;
externalWindow.hidden = NO;
[externalWindow makeKeyAndVisible];
[externalWindow setUserInteractionEnabled:YES];
[externalWindow setMultipleTouchEnabled:YES];
//[[CCDirector sharedDirector] attachInView:externalWindow];
Now, I can display on the external display or on my iPhone, but I can't display on both at the same time, because [[CCDirector sharedDirector] attachInView:externalWindow]; will only take one UIWindow. How can I get around this and/or get the displayed image and set it to my external display?
Thanks,
Dave
The only solution i see is to render your scene to a texture and render that texture twice as a full screen quad to the backbuffer, once for each UIWindow

pagingScrollView Slideshow

I have started trying to understand the way apple implements the photoviewer app for the iPhone after watching both videos from WWDC 2009 and 2010 about scrollViews and paging through photographs and I am taking each step very slowly to understand the processes very well before I implement it all into my app.
I have run into a couple of problems at the moment:
Firstly I have it set up to have a paging scroll view to swipe left and right between photos with a bit of space in between like on the videos but when I add an image inside a UIImageView th image is too big for the screen, I have tried adding UIViewContentModeScaleAspectFit; to no effect.
When I go through the for loop to look at each element of the array containing the images the UIViews overlap and show one photograph on top of the other, I would like to know how to separate them into the next section of the paging scroll view.
- (void)loadView{
UIImage *img0 = [UIImage imageNamed:#"29.png"];
UIImage *img1 = [UIImage imageNamed:#"33.png"];
NSMutableArray *imgArray = [[NSMutableArray alloc] initWithObjects:img0, img2, nil];
CGRect pagingScrollViewFrame = [[UIScreen mainScreen] bounds];
pagingScrollViewFrame.origin.x -= 10;
pagingScrollViewFrame.size.width += 20;
pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame];
pagingScrollView.pagingEnabled = YES;
pagingScrollView.backgroundColor = [UIColor blackColor];
pagingScrollView.contentSize = CGSizeMake(pagingScrollViewFrame.size.width * [imgArray count], pagingScrollViewFrame.size.height);
self.view = pagingScrollView;
for (int i=0; i < [imgArray count]; i++) {
UIImageView *page = [[UIImageView alloc] initWithImage: [imgArray objectAtIndex:i]];
page.contentMode = UIViewContentModeScaleAspectFit;
[pagingScrollView addSubview:page];
}}
As I have mentioned I am fairly new to programming for the iPhone and am taking things slowly to fully understand, eventually this program will mimic the native app with pinching and tapping for zoom.
If you're using UIImageViews, you should make sure that your view has its clipsToBounds field set to yes. Try adding:
UIImageView *page = [[UIImageView alloc]
initWithImage:[imgArray objectAtIndex:i]];
[page setContentMode:UIViewContentModeScaleAspectFit];
[page setClipsToBounds:YES];
[pagingScrollView addSubview:page];
Then, make sure you are setting your image's frame to the correct offset within the scroll view. The frame's origin.x needs to be the width of the frame times the image index. So you need something like this:
[page setFrame:CGRectMake(i*pagingScrollViewFrame.size.width, y, width, height)];
where i is your index from your for loop.
Though in the sample code from the WWDC session you're referring to, this is done in a method called -configurePage. Have you downloaded the sample code?
-[UIImageView initWithImage:] sets the frame to be the image's size. You'll need to use page.frame = [[UIScreen mainScreen] bounds] or similar to scale images to the correct size.

How do I stack images to simulate depth using Core Animation?

I have a series of UIImages with which I need to simulate depth. I can't use scaling because I need to be able to rotate the parent view, and the images should look like they're stacked visibly in front of each other, not on the same plane.
I made a new ViewController-based project and put this in the viewDidLoad (as well as attached three 120x120 pixel images named 1.png, 2.png, and 3.png):
- (void)viewDidLoad {
// display image 3
UIImageView *three = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"3.png"]];
three.center = CGPointMake(160 + 60, 240 - 60);
[self.view addSubview:three];
// rotate image 3 around the z axis
// THIS IS INCORRECT
CATransform3D theTransform = three.layer.transform;
theTransform.m34 = 1.0 / -1000;
three.layer.transform = theTransform;
// display image 2
UIImageView *two = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"2.png"]];
two.center = CGPointMake(160, 240);
[self.view addSubview:two];
// display image 1
UIImageView *one = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"1.png"]];
one.center = CGPointMake(160 - 60, 240 + 60);
[self.view addSubview:one];
// rotate image 3 around the z axis
// THIS IS INCORRECT
theTransform = one.layer.transform;
theTransform.m34 = 1.0 / 1000;
one.layer.transform = theTransform;
// release the images
[one release];
[two release];
[three release];
// rotate the parent view around the y axis
theTransform = self.view.layer.transform;
theTransform.m14 = 1.0 / -500;
self.view.layer.transform = theTransform;
[super viewDidLoad];
}
I have very specific reasons why I'm not using an EAGLView and why I'm not loading the images as CALayers (i.e. why I'm using UIImageViews for each one). This is just a quick demo that I can use to work out exactly what I need in my parent application.
Is there some matrix way to translate these 2d images along the z-axis so they will look like what I'm trying to represent? I've gone through the other StackOverflow articles as well as the Wikipedia references, and have not found what I'm looking for -- although I might not necessarily be using the right terms for what I'm trying to do.
In order to stack your views, and have them have perspective applied, you will need to first place them at different Z positions, then apply a perspective effect to the containing layer.
I believe the following code will do this, but I've not tested it (I've done something similar with pure CALayers, so the general principles are correct):
- (void)viewDidLoad {
UIImageView *three = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"3.png"]];
three.center = CGPointMake(160 + 60, 240 - 60);
[self.view addSubview:three];
three.layer.zPosition = -100;
UIImageView *two = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"2.png"]];
two.center = CGPointMake(160, 240);
[self.view addSubview:two];
two.layer.zPosition = 0;
UIImageView *one = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"1.png"]];
one.center = CGPointMake(160 - 60, 240 + 60);
[self.view addSubview:one];
one.layer.zPosition = 100;
// release the images
[one release];
[two release];
[three release];
CATransform3D theTransform = self.view.layer.sublayerTransform;
theTransform.m34 = 1.0 / -500;
self.view.layer.sublayerTransform = theTransform;
[super viewDidLoad];
}
In your code, you are only setting the perpective portion of the CATransform3D on each view's layer (that's what the m34 component of the CATransform3D matrix does). You are not actually displacing them in the Z plane. You could use a transform for this, but I find that the zPosition property of your CALayers provides a cleaner way to locate the layers in 3-D.
Once you've placed the layers relative to one another (with negative values going away from the viewpoint of the user), you need to apply a perspective effect to all layers hosted within your main view. For this, I find that setting the sublayerTransform of the hosting view's layer is necessary in order for the perspective to be applied correctly to all hosted layers.
If you wish to rotate the series of images, use CATransform3DRotate() on the sublayerTransform of the main hosting view's layer.
For an example application that does 3-D manipulation of CALayers, with perspective applied to them, check out the project I link to in the second update of my article here.
I finally solved this by using CATransform3DMakeTranslation, which seems to be the only way to move a layer up or down the z-axis:
UIImageView *three = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"3.png"]];
three.layer.transform = CATransform3DMakeTranslation(0.0f, 0.0f, 20.0f);
three.center = CGPointMake(160 + 60, 240 - 60);
[self.view addSubview:three];
(I also moved UIImageView one -20.0f pixels on the z-axis. That finally gave the effect I was looking for.)

UIScrollView starting point

I have a iPhone app with a main view that is 480 x 510. I'm a bit confused as to how the coordinate system changes when I go from portrait to landscapeRight.
Initially, I had a 480x480 content area, and wanted to add a button on the side to bring up a menu. However, the only way I could find to have the writing run down the length of the left side of the app was to change the orientation of the whole app to landscape right.
Now, with the orientation in Landscape, the scrollview is starting at the top left, when I really want it to start at the original orientation point (from when it was in portrait mode), which would be bottom left. But I can't figure out how to change the original starting point of the scrollview. I tried contentOffset, but it doesn't seem to be working.
Another way of going about this (that I might end up doing) is forget having a title on the button, and just create a graphic for the button that has text vertically oriented.
if (self = [super initWithCoder:coder]) {
// Size of the scrollview
self.contentSize = CGSizeMake(480, 510);
[self setContentOffset:CGPointMake (0, -160)];
self.showsHorizontalScrollIndicator = YES;
self.showsVerticalScrollIndicator = YES;
self.alwaysBounceVertical = NO;
self.alwaysBounceHorizontal = NO;
self.bounces = YES;
self.userInteractionEnabled = YES;
self.musicGridView = [[[MusicGridView alloc] initWithCoder:coder] autorelease];
// Rectangle where I put the music grid (origin is left aligned, and down 160 pixels to account for landscape view)
self.musicGridView.frame = CGRectMake(0, 160, 480, 480);
[self addSubview: musicGridView];
self.menuButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.menuButton.frame = CGRectMake(0, 480, 480, 32);
[menuButton setTitle: #"Tap to get Menu" forState: UIControlStateNormal];
[menuButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[menuButton addTarget:self action:#selector(showMenu) forControlEvents:UIControlEventTouchUpInside];
[self addSubview: menuButton];
simply set the points x,y in
//it goes in particular pont of view
[scrollview setContentOffset:CGPointMake(x,y) animated:YES];
//if x=0 in loop, increase y value scrollview move only vertical direction
[scrollview setContentOffset:CGPointMake(0,y) animated:YES];
//if y=0 in loop, increase x values scrollview move only horizontal direction
[scrollview setContentOffset:CGPointMake(x,0) animated:YES];
Andrey Tarantsov has done an awesome rundown of the various quirks of the UIScrollView class, including code for various workarounds to common problems. It might be worthwhile taking a look.