Frame size iOS8 Sprite Kit - objective-c

I am a SpriteKit beginner and did some tutorials under iOS7 and xcode5. The frame size is now, after the update to xcode6 and iOS8, fix for every device (1024,768). My questions is now how can I actually figure our what is shown in the Scene and in which range the nodes are presented in the scene. (the actual size and range of the scene)
Example: node.position = CGPointMake(0, 768); //cannot be seen in the scene whereas
node.position = CGPointMake(300, 768); //can be slightly seen in the scene
Thank you very much and kind regards,
SirSandmann

If you are using SKSceneScaleModeAspectFill as the scaleMode for the scene it will scale proportionally until it fills the whole screen, so you will lose a bit from top and bottom of that size (1024,768) on 16:9 devices. The usable size of the scene for that aspect ratio (iPhone 5 and up) should be (1024,575) so that should be the area where important game elements should be placed.
If you want to support 3:2 devices (iPhone 4S and down) usable area should be (862,575) if I'm correct.

Related

Scaling for Different iPhone Screens in Sprite Kit

I am creating an iPhone game in sprite kit. After weeks of research, I am still having trouble understanding how to properly size and implement sprites for each screen size.
I understand that these suffixes determine which image to use (depending on the aspect ratio of the screen)
#2x - 4s,5,6
#3x - 6+
I have read and tooled with different scaling modes in my view controller but had no luck and difficulty understanding them.
If I provide a background of 750x1136 (pixels) as the #2x, it will perfectly fit the iphone 6 but will be too big for the iphone 5. If scaling is the answer, how would "sprite kit" know I provided an image for the iphone 5 that I want scaled up for the 6, or vice versa? Is this a build setting? Same for characters, I need iphone 6 sprites to be proportionally bigger than the iphone 5 sprites.
How would I most appropriately size and scale sprites for the different devices? (easier to discuss in terms of the backgrounds that should be the exact size of the screen)
I am expecting to create one set of sprites for each aspect ratio using the resolution of the biggest screen size. Ex. #2x designed for iPhone 6 and scaled down for the 5 and 4s.
The 3x, 2x and normal images are not really intended to be manipulated that way. The three images should be essentially the same image with the 3x having exactly 3 times the pixel dimensions of the normal, the 2x having double dimensions etc.
If you need to scale the scene to better fit the format of a particular device, you may need to scale that when you create the scene, the way Apple sample code does:
var viewSize = self.view.bounds.size
// On iPhone/iPod touch we want to see a similar amount of the scene as on iPad.
// So, we set the size of the scene to be double the size of the view, which is
// the whole screen, 3.5- or 4- inch. This effectively scales the scene to 50%.
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
viewSize.height *= 2
viewSize.width *= 2
}

What's the best way to convert iPad app to handle both view modes?

I have an existing iPad app (XCode 4.6, iOS 6.2, ARC and Storyboards). It is currently in the App Store in Portrait mode only; I have had several requests for landscape mode. Unfortunately, all of the lines, etc are drawn using CG methods, controlled mathematically. This is what it looks like in portrait mode:
and this is what it looks like in landscape mode:
My question is: where can I find some good docs that will give me the basic steps I need to convert this app for both modes, knowing that the drawing is controlled mathematically?
If it is controlled mathematically, the best way is to refer all coordinates to the dimensions of the parent view, specifically to the property self.view.bounds that changes with the rotation of the device.
Then you have to redraw the interface when the orientation has been changed. A good way to do it is inside the method:
-(void)viewWillLayoutSubviews
If did some custom views in the past with CG methods and the best way is to refer everything to the bounds. In that way when you change the screen size, either by rotating or by using it on the iPhone it works without modifications.
update
Imagine that you have a point at (76.8, 512.0) this is precisely in an iPad and portrait orientation, a 10% of the width and a 50% of the height.
So for every pair of coordinates instead of using them with absolute numbers you have to replace them by fractions of the dimensions of the parent view:
// old drawing method
CGPoint oldPoint = CGPointMake(76.8, 512.0);
// new drawing method
CGFloat W = self.view.bounds.size.width;
CGFloat H = self.view.bounds.size.height;
CGPoint newPoint = CGPointMake(0.1 * W, 0.5 * H) // 76.8 = 0.1 * 768; 512 = 0.5 * 1024
In this second case; when you change the orientation so will the bounds change and the coordinate will get new values, but the proprotion will be the same as in the other orientation, 10% in horizontal and 50% in vertical.
You get the idea.

Optimize QuartzCore Animation with Shadows and Rasterization

Within my iOS app, I have a uiview that needs to be animated, transformed with gestures, shaded (using quartzcore shadows), and edited. When I perform animations and gestures on this UIView it is extremely "laggy". The animations aren't very "laggy" on the iPhone, however when using the iPad the animations become almost unresponsive (to the point where it seems like my app is crashing). I've tested my app using Instruments, and the app isn't taking up much memory / CPU / power until the animations begin. I have tested both on the device and on my Intel i7 8GB iMac and the animations are "laggy" on both.
The animation I am performing is nothing complex, it is simply a translation across the X Axis. After looking through every line of code related to the animation, I found that these lines are the issue(s):
viewer.layer.masksToBounds = NO;
viewer.layer.shadowOffset = CGSizeMake(-1, 1);
viewer.layer.shadowRadius = 3;
viewer.layer.shadowOpacity = 0.3;
The above code adds a shadow to the view that lags whenever I animate it (viewer). If I use the above code, but I add the following line animations work nicely:
viewer.layer.shouldRasterize = YES;
The problem with this code is that is seriously decreases the quality of the content displayed inside of the UIView (viewer). Here's an image with shouldRasterize set to YES:
Then the UIView without shouldRasterize:
Those screenshots are both from the same Retina iPad.
The ultimate question: How can I smoothly perform animations on a UIView with shadows (preferably using QuartzCore)? Is there a way to rasterize the content without degrading its quality?
The shadow properties on CALayer can be very inefficient while animating because it requires recalculating the shadow on every frame based on the contents of the layer. Luckily, the expensive part is the shadow path calculation, so if you just create a CGPath representing the shape of your content and assign it to layer.shadowPath then performance will skyrocket.
Since your layer seems to be completely filled with opaque data, the shadowPath is pretty simple:
layer.shadowPath = [UIBezierPath bezierPathWithRect:(CGRect){CGPointZero, layer.bounds.size}].CGPath;
The only downside is you'll need to edit this whenever the size of the layer changes.

How do I override the Points to Pixels iOS specificity and have my image drawn at the right size?

I have a 64px by 64px redSquare.png file at a 326ppi resolution. I'm drawing it at the top left corner of my View Controller's window as follows:
myImage = [UIImage imageNamed:#"redSquare.png"];
myImageView = [[UIImageView alloc] initWithImage:myImage];
[self.view addSubview:myImageView];
Given that the iPhone 4S has a screen resolution of 960x640 (326ppi) there should be enough room for 9 more squares to fit next to the first one. However there's only room for 4 more. i.e. the square is drawn larger than what it should given my measurements.
// even tried resizing UIImageView in case it was
// resizing my image to a different size, by adding
// this next line, but no success there either :
myImageView.frame = CGRectMake(0, 0, 64, 64);
I believe it has to do with the way the device is "translating" my pixels. I read about the distinction between Points Versus Pixels in Apple's documentation but it doesn't mention how one can work around this problem. I know I'm measuring in pixels. Should I be measuring in points? And how could I do that? How exactly am I to resize my image so that it can hold 9 more same-sized squares next to it (i.e. on the same horizontal..) ?
Thank you
To display an image at full resolution on a Retina display, it needs to have #2x appended to the end of its name. In practice, this means you should save the image you're currently using as redSquare#2x.png and a version of that image in 32x32 pixels as redSquare.png.
Once you have done this, there is no need to change your code. The appropriate image will be displayed depending on the device's capabilities. This will allow your app to render correctly on both Retina and non-Retina devices.

View behaviour differences between IOS 5.x and IOS 4.x

I've been trying to animate an image view to slide upwards on the screen. The views height is also increased whilst the position is moved upwards.
On my iPhone 4S (5.x) the image view behaves as expected, the view only moves upwards as its height is increased, however on my iPhone 3G (4.1), the view moves down a little bit during this animation.
Such a level of accuracy is needed as the image view is used to create a non expensive shadow effect. Its alignment is important for the effect. The image is a resizable graphic.
This is how I change the position and size of the view
CGRect oldShadow = self.shaddowView.frame;
oldShadow.size.height = oldShadow.size.height+200;
oldShadow.origin.y = oldShadow.origin.y - 200;
self.shaddowView.frame =oldShadow;
This is how the image for the view is set up as resizable:
UIImage* shadow = [[UIImage imageNamed:#"shadow.png"] stretchableImageWithLeftCapWidth:20 topCapHeight:20];
self.shaddowView.image = shadow;
Thanks.
I used the following animation, with a border around not only the starting position but also the intended final position, so that I could confirm whether any undesired shifting of the view (other than the obvious upward expansion) took place, but it worked fine on iOS 4.2.1:
[UIView animateWithDuration:2.0
animations:^{
CGRect newImageFrame = imageView.frame;
newImageFrame.origin.y -= stretchBy;
newImageFrame.size.height += stretchBy;
imageView.frame = newImageFrame;
}];
I don't have iOS 4.1 device sitting around (my old 3G test phone is running iOS 4.2.1, the latest supported iOS version for that device), so I can't speak to that, but it's fine with iOS 4.2.1.
I have to confess, though, that I find it very unlikely that when you animate the changing of a frame, that the final frame would not be precisely what you specified it to be. If you NSLog the frame when you're done, it is not the correct value? Or are you saying that it momentarily moves during the animation but then ends up in the correct location? Or that it shifts down during animation and ends up in the wrong position even when the animation is done?
I wonder if there's something else going on (e.g. is your animated view a subview of a scroll view, which itself might be shifting? or is there some code not shown here that is accidentally further adjusting the frame after the animation? etc.). Seems like a little debugging should confirm whether the frame is actually not what you intended, or whether there is some other issue going on.
I originally answered suggesting shouldRasterize option, but if you're trying to support old iPhone 3G devices, then maybe that's not good enough. Definitely stutters a little on these old phones. Anyway, this was my original answer:
I assume you're doing this because the layer shadow feature is a little CPU intensive. But I've heard (but can't speak to it) that if you use the shouldRasterize option, it's a little better:
viewThatNeedsShadow.layer.shadowColor = [UIColor blackColor].CGColor;
viewThatNeedsShadow.layer.shadowOffset = CGSizeMake(3.0, 3.0);
viewThatNeedsShadow.layer.shadowOpacity = 0.5;
viewThatNeedsShadow.layer.shouldRasterize = YES;
viewThatNeedsShadow.clipsToBounds = NO;