Jack Schofield
Jack Schofield

Reputation: 302

Objective-C. How is your first SKScene initialised?

This method sets up the initial scene and is called as soon as the application opens:

 #import "GameScene.h"
    #import "WarScene.h"
    #import "Math.h"

    @implementation GameScene
    {
        SKNode *map;
        float oldY;
        float oldX;
        BOOL buttonClicked;
        int thisButton;
        float oldMapPosition;
        float midScreenX;
    float midScreenY;
    int separation;
    float sendY;
    BOOL interacting;
    CGVector speed;
    float oldPosition;
    float newPosition;
    BOOL isReleased;
    int iterations;
    float diff;
    BOOL comeToStop;
    BOOL actualStop;
    BOOL clicked;
}

int numberOfLevels = 20;

-(void)didMoveToView:(SKView *)view {

    /* Setup your scene here */
    map = [SKNode node];

    separation = [UIScreen mainScreen].bounds.size.height;

    if (UIDeviceOrientationIsLandscape((UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation]))
    {
        //landscape mode
        midScreenX = ([[UIScreen mainScreen]bounds].size.width>[[UIScreen mainScreen]bounds].size.height?[[UIScreen mainScreen]bounds].size.width:[[UIScreen mainScreen]bounds].size.height)/2;
        midScreenY = ([[UIScreen mainScreen]bounds].size.width<[[UIScreen mainScreen]bounds].size.height?[[UIScreen mainScreen]bounds].size.width:[[UIScreen mainScreen]bounds].size.height)/2;
    }
    else
    {
        //portrait mode
        midScreenX = [[UIScreen mainScreen]bounds].size.width/2;
        midScreenY = [[UIScreen mainScreen]bounds].size.height/2;
    }

    NSLog(@"Initial Width: %f Height: %f", midScreenX*2, midScreenY*2);

    map.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize: CGSizeMake([UIScreen mainScreen].bounds.size.width, separation*(numberOfLevels+1))];
    map.physicsBody.affectedByGravity = NO;
    map.physicsBody.allowsRotation = NO;

    clicked = NO;

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTap:)];
    tap.numberOfTapsRequired = 1;

    [self.view addGestureRecognizer:tap];

    self.backgroundColor = [SKColor blackColor];

    for (int i = 0; i<numberOfLevels; i += 1) {
        SKLabelNode *title;
        {
            title = [SKLabelNode labelNodeWithFontNamed:@"Cochin"];
            title.text = [NSString stringWithFormat: @"Level %d", 1+i];
            title.fontSize = 60;
            title.position = CGPointMake(CGRectGetMidX(self.frame),
                                         ((i+1)*separation));
            title.fontColor = [UIColor whiteColor];
            title.name = [NSString stringWithFormat: @"Level %d", 1+i];

            [map addChild:title];
        }
    }
    [self addChild:map];

     }

This works exactly as I intended it to, however, when I call this from another class:

-(void)continueMethod:(UIButton*)button{

    NSLog(@"InitwithSize to GameScene Width: %f Height: %f", midScreenX*2, midScreenY*2);
    GameScene *map = [[GameScene alloc] initWithSize: CGSizeMake(midScreenX*2 ,midScreenY*2)];
    SKTransition *reveal = [SKTransition revealWithDirection:SKTransitionDirectionDown duration:1.0];
    SKView * skView = (SKView *)self.view;
    UIView *viewToRemove = [self.view viewWithTag:3];
    [viewToRemove removeFromSuperview];
    [skView presentScene:map transition:reveal];
}

The scene which should be set up doesn't appear as I intended it to, or indeed how it used to look the last time that it was initialised. The separation variable appears bigger, the text appears bigger and everything is wider. I've verified that the UIScreen that I have initialised is exactly the same throughout.

This led me to question how the initial scene of a SKSprite application comes to be and whether it is different to "initWithSize:" however, looking through all the code that comes in the game template I can't ever see my first scene get called. The closest that I can find to initWithSize: is the following from the GameViewController-

GameScene *scene = [GameScene unarchiveFromFile:@"GameScene"];
    scene.scaleMode = SKSceneScaleModeAspectFill;

Firstly, is this what is initialising my initial scene? Secondly is it in anyway different to initWithSize: ? And finally if the answer to the previous tow questions is yes, should it be used instead of initWithsize: ?

Upvotes: 1

Views: 83

Answers (1)

MaxKargin
MaxKargin

Reputation: 1545

Yes, this is the initialization of the initial scene! What you are seeing in the View Controller is a slightly different initialization. You are using the sks file, first of all, and initWithCoder: is being called when the view controller unarchives it. However, this isn't very different from initWithSize if you specify all of the same dimensions and properties.

That being said, the scene's scaleMode in your initialization and the view controller's scaleMode is different. As you can see, the view controller specifies:

scene.scaleMode = SKSceneScaleModeAspectFill;

The AspectFill scale mode according to Apple:

The scaling factor of each dimension is calculated and the smaller of the two is chosen. Each axis of the scene is scaled by the same scaling factor. This guarantees that the entire scene is visible but may require letterboxing in the view.

When you initialize your scene, on the other hand, you leave the default scaleMode, which happens to be SKSceneScaleModeFill. This maps each axis of the scene to the view, so you get a distorted scene. What you need to do is simply state:

map.scaleMode = SKSceneScaleModeAspectFill;

This will use the same scale mode as in the original scene and the distortion that you see now will be gone.

Hope this helps, let me know if you have questions.

Upvotes: 2

Related Questions