iOS SpriteKit node position - ios

I an new at Sprite kit and I want to add some node to scene.
My problem is positions :
If I put :
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:#"Poligon"];
sprite.xScale = 0.5;
sprite.yScale = 0.5;
sprite.position = CGPointMake(40, 400);
it looks right when iPhone is in landscape mode, but when it is in portrait it disappear from the screen.
My guess is that it take coordinate from landscape and put it at right side of the screen. This would explain why node is not visible in portrait mode.
My question is how to set that iPhone would take portrait mode by default?

Apparently sprite kid start in landscape mode and take start viewDidLoad before it take rotation in account. Because of this the coordinate system in portrait mode is shifted, even if you set orientation to portrait.
The solution according to :
http://www.ymc.ch/en/ios-7-sprite-kit-setting-up-correct-scene-dimensions
is to set your scene not on viewDidLoad but on
- (void)viewWillLayoutSubviews
This is run after orientation is set and it works.

Related

Adding a background image to a SpriteKit project

The iPhone 6 and 6s are supposed to have a 750 x 1334 resolution [1], and the screen ratio for every iPhone since the iPhone 5 is 16:9 [2]. So in order to have a background image for an app that fits perfectly, it must have a 16:9 ratio. I'm working on a project using SpriteKit and I want the game to have a wallpaper that covers the back from edge to edge. However, when I run the app on the simulator the background image always gets cropped on the right and left. I've even tried with all sorts of ratios and resolutions. The code for this background on the project is:
let background = SKSpriteNode(imageNamed: "backtImage")
background.size = self.size
background.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
background.zPosition = 0
self.addChild(background)
What am I doing wrong?
This could happened because your SKView don't match with your SKScene dimensions.
The sources:
#available(iOS 7.0, *)
public enum SKSceneScaleMode : Int {
case Fill /* Scale the SKScene to fill the entire SKView. */
case AspectFill /* Scale the SKScene to fill the SKView while preserving the scene's aspect ratio. Some cropping may occur if the view has a different aspect ratio. */
case AspectFit /* Scale the SKScene to fit within the SKView while preserving the scene's aspect ratio. Some letterboxing may occur if the view has a different aspect ratio. */
case ResizeFill /* Modify the SKScene's actual size to exactly match the SKView. */
}
You can change your code as below:
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = self.view as! SKView
...
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .ResizeFill // <- this is an example
skView.presentScene(scene)
}
}
If your image is getting cropped on the left and right side (in Portrait) Then we are dealing with an .AspectFill scale mode, and your aspect for your scene is shorter than the screen resolution. This is probably happening because the default scene size provided in the template build is a square. Go into your .sks file, and change the scene size to something in a 9x16 ratio, and your problem should be solved

SpriteKit layout issues (Swift)

I'm new to SpriteKit and Swift (done a lot in Obj-C in the past for iOS) but I'm struggling on something that should be very basic.. positioning sprites on the screen!
Centering a label on the screens seems easy enough:
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
But when I try to put in the Bottom-left or top-right of the screen it isn't visible:
//Bottom-left label
myLabel.horizontalAlignmentMode = .Left
myLabel.position = CGPoint(x: 0.0, y: self.size.height)
or
//Top-right label
myLabel.horizontalAlignmentMode = .Right
myLabel.position = CGPoint(x: self.size.width, y: self.size.height)
This is with a new project, no other code. What am I doing wrong, please?
What you have to keep in mind is that a SpriteKit scene by default takes up far more than the screen. Its default size is 1024 by 768 and everything is scaled for universality unless you tell it otherwise. In your view controller you could see how the scene is initialized. You will see that it probably has a statement that says something like
scene.scaleMode = .AspectFill
This is the source of this. Apple in the documentation explains this in a straightforward manner what happens when you use AspectFill scaleMode:
The scaling factor of each dimension is calculated and the larger of the two is chosen. Each axis of the scene is scaled by the same scaling factor. This guarantees that the entire area of the view is filled but may cause parts of the scene to be cropped.
There are other scale Modes to explore, which you can try but Aspect Fill has a large advantage with its universality.
You can specify the size of an SKScene when you create it. Typically you pass the size of the containing SKView so it covers the entire view. If the device rotates, your view is resized (if your app allows the new orientation). I'm not sure if the SKScene if resized. But either way, you need to update the position of your scene contents so that for example the label is in the top-right with the new dimensions.
The view controller whose view presents the scene receives the message viewWillTransitionToSize(_ size:,withTransitionCoordinator coordinator:). You can subclass this method to send a message to a custom method of the presenting SKScene that the size is changing. Then, you can simply reposition the node using the new size since self.frame will update.
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
Back to the core of the question! How to position a label in the top-right of the scene? Take into account that the scene origin is bottom-left. For SKLabelNode, the center is really in the center. So, offset by half of the label's dimensions.
myLabel.position = CGPoint(x: self.size.width - myLabel.size.width /2,
y: self.size.height - myLabel.size.height/2)
By the way, I have never seen an iOS game which uses a sprite based engine (such as Sprite Kit or Cocos2d) which supports device rotation/multiple screen sizes when running on the same device (iPhone/iPad).

SpriteKit screen size--how to get the correct size of images on a real phone?

Why does my app look different from the simulator when I run it on my real phone?
I am making a game using spritekit. When I test it in the iPhone 5 simulator, the size of the screen and the size of the images are exactly as I want them, but then when I run the program on my actual iPhone 5, the images show up too big, parts of the top and bottom of the screen are cut off, and the left and right of the screen don't extend all the way to the sides of the phone--there's a letterboxing effect from left to right on the screen.
All my images are named with #2x, so they should work fine with retina screens. Here's the code relating to screen size that I use when I initialize my SKScene:
GameScene *scene = [GameScene unarchiveFromFile:#"GameScene"];
scene.size = self.view.frame.size;
scene.scaleMode = SKSceneScaleModeAspectFill;
I've tried each of the available SKSceneScaleModes and none of them help--they each just give a different outcome that doesn't look right. I'm using AspectFill simply because that mode does work correctly in the simulator.
I've also tried sizing the screen like this, just as something to try, but that didn't help either:
GameScene *scene = [GameScene unarchiveFromFile:#"GameScene"];
CGRect screenRect = [[UIScreen mainScreen] bounds];
scene.size = screenRect.size;
Thanks in advance.
It was indeed due to the fact that the simulator was simulating ios 8 while my device was on ios 7. ios 8 automatically changes the coordinate system when you go into landscape mode (the native mode of my game) while ios 7 does not. The fix was simple once I figured that out--just detect which os the device is running, and, if it's lower than ios 8, swap the height and width dimensions of the screen:
if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) {
CGSize fixedSize = CGSizeMake(screenRect.size.height, screenRect.size.width);
scene.size = fixedSize;
}
else
scene.size = self.view.frame.size;

Place a sprite at the bottom of the screen independently from resolution

I need to place a sprite at the bottom of the screen independently from resolution using cocos2d for iPhone, so that if a sprite is at the bottom on iPhone 5/5s, it will be at the bottom even on iPhone 4/4s.
The following code works on iPhone5/5s resolution, but not on the previous iPhone model:
ground1 = [CCSprite spriteWithImageNamed:#"ground1.png"];
ground1.position = ccp(self.contentSize.width/2,self.contentSize.height/2-259);
[self addChild:ground1];
What can I do?
CGSize size = [[CCDirector sharedDirector]viewSize];
ground1 = [CCSprite spriteWithImageNamed:#"ground1.png"];
ground1.position = ccp(size.width/2,[ground1 boundingBox].size.height/2);
[self addChild:ground1];
First of all you need the size of the view. In Cocos2D you get that value calling the CCDirector and getting its viewSize.
After that, you create the sprite as you did.
Now the important step is to position the sprite. Now you have your viewSize stored in 'size' so you get the X value by doing: size.width/2.
Now you have your sprite centered on X. Now let's position it over Y.
You want your sprite to be at the bottom. So you need to calculate the point as I show you in this picture:
So the Y value is exactly height/2 of the sprite's size. We can get this value by calling the method:[sprite boundingBox] that returns the size of the sprite.
In conclusion, we have our sprite centered on X (size.width/2) and at the bottom ([sprite boundingBox].size.height/2)

SpriteKit Horizontal Tile Map

I am trying to put together a tile-map for a game background. The tiling works in portrait mode but when I switch to landscape, I get a blank screen.
The code is listed below:
-(SKNode *)createBackgroundNode
{
SKNode *backgroundNode = [SKNode node];
for (int nodeCount = 0; nodeCount < 20; nodeCount++) {
NSString *backgroundImageName = [NSString stringWithFormat: #"Background%02d", nodeCount+1];
SKSpriteNode *node = [SKSpriteNode spriteNodeWithImageNamed: backgroundImageName];
node.anchorPoint = CGPointMake(0.0f, 0.0f);
node.position = CGPointMake(nodeCount * 320.0f, 0.0f);
//node.position = CGPointMake(160.0f, nodeCount * 64.0f);
[backgroundNode addChild: node];
}
return backgroundNode;
}
Basically it is a game that is only played in landscape mode, and I need the tiles to be placed horizontally one after the other to create the map.
Any help with this is appreciated! Thanks in advance!
Edit: Sorry if I wasn't clear, my game only supports landscape orientation. When my iPhone is in landscape orientation, I am unable to see my map. If I play with the settings in XCode and allow the app to be in portrait orientation, I am able to see the tile map going across the screen; however, this is NOT what I want and I only did that to see if it works.
Switching screen orientation while using tile maps is not advisable. Once you have loaded your tile map, you would be better off staying in the selected orientation mode. AT least that has been my own experience using the Tiled app.

Resources