12
votes

So, I've begun working on a project in SpriteKit, and I'm hoping to be able to implement a "main menu" scene with a few buttons. One would go to a level select screen, one would be options, etc. Then from the level select screen, there would be several other buttons that when selected would start the game and load the selected level.

My question is this: how should the project be set up? Should each screen (level select, main menu, options) be its own scene and have one main view controller? Or should I have multiple view controllers for everything? Or maybe a view controller for every level (although that doesn't make too much sense) that's governed by a NavigationController in the storyboard?

After playing around with it a bit and reading online, I noticed that I can use the view controller to have UIButtons for my main menu. However, they persist through sprite kit scene changes, which is not something I would want. That would mean that I would have to set buttons to be hidden on every new scene displayed, which worries me because I'm unsure as to what exactly happens to the buttons. I know it is possible to create buttons out of SKSpriteNodes (similar to the class that Graf has posted and many people have used). Is that the better option? Instead of using UIButtons on the VC, I'd be checking whether a touch was made to that button node in the touchedBegan method and touchesEnded method, something like this:

UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];

if ([node.name isEqualToString:@"scene button"])
{
    LevelScene *scene = [LevelScene sceneWithSize:self.view.bounds.size];
    scene.scaleMode = SKSceneScaleModeAspectFill;
    [self.view presentScene:scene];
}

Is this the correct way to handle it?

Eventually I will want to be able to add pause screens, game over screens, etc, and unsure if just swapping scenes will be sufficient. Furthermore, instead of having a separate implementation for each level, I could load them from a .plist file

I'm also considering the fact of whether or not I will be able to animate the buttons. I suppose I'd want them to float around or get bigger when selected (when the user has touched it but not let go), and I believe that a UIButton would not allow it since it isn't an SKSpriteNode.

Sorry for such a long post, but hopefully that gives enough information to help me out and get me on the right track! Thanks!

3

3 Answers

7
votes

if you want a simple menu you can create it with SpriteKit but if you want a complex menu you should use UIKit.

Let's say that you want to create a level selection menu with CoverFlow effect, that will be hard to implement from scratch on SpriteKit but for UIKit you can find libraries like iCarousel that implements stunning CoverFlow and scroll effects with ease.

SKLabelNode by the moment only supports one text line so if you want to add a really long message in your game that will be difficult but if you use UIKit instead you can use a UITextView to display your long message.

a detailed In App Purchases menu will be easier to create with UIKit.

UIKit will avoid you a lot of headache, i really encourage you to use it.

how should the project be set up?

You only need 1 Scene

MenuviewController->( Push Segue )->LevelSelectionController->( Push Segue )->GameScene

I suppose I'd want them to float around or get bigger when selected (when the user has touched it but not let go), and I believe that a UIButton would not allow it since it isn't an SKSpriteNode.

you can add animations to a UIButton with UIView animateWithDuration or CABasicAnimation

That would mean that I would have to set buttons to be hidden on every new scene displayed

Solve it with a function

- (void)setHidden:(BOOL)hide {
    UIButton *tmpButton = (UIButton *)[self.view viewWithTag:100];
    tmpButton.hidden = hide ? YES : NO;
}

Hide it like this

[self setHidden:YES];

Hope it helps

Good Luck!

2
votes

Although @Albert's answer is a good one, i have always just used SKLabelNode. It is a class that is already inside of the SpriteKit framework, and doesn't require the use of gestures.

This makes you wonder, how does it react to actions? Well, that is actually quite simple.

I just use touchesBegan:withEvent: method, and I check if the label node is being pressed upon. Here is an example.

// in .m file
@interface ClassName () {
   SKLabelNode *menuItem1;
   SKLabelNode *menuItem2;
}

@implementation

- (id) initWithSize:(CGSize)size // can't fully remember this one...
{
     if(self = [super initWithSize:size]) {
        // here you create your labels
        menuItem1 = [SKLabelNode labelNodeWithFontNamed:@"Your font."];

        // this will position this at the center, top 1/3 of the screen
        menuItem1.position = CGPointMake(self.frame.size.width/2, self.frame.size.height * .3); 
        menuItem1.text = @"Menu 1";
        [self addChild:menuItem1]; // takes care of the first

        menuItem2 = [SKLabelNode labelNodeWithFontNamed:@"Your font."];

        // place at center, lower 1/3 of screen
        menuItem2.position = CGPointMake(self.frame.size.width/2, self.frame.size.height * .6); 
        menuItem2.text = @"Menu 2";
        [self addChild:menuItem2];
    }
    return self;
}

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
     UITouch *t = [touches anyObject];
     CGPoint touchLocation = [t locationInNode:self.scene];

      if(CGRectContainsPoint(menuItem1.frame, touchLocation)) {
          // do whatever for first menu
      }

      if(CGRectContainsPoint(menuItem2.frame, touchLocation)) {
          // do whatever for second menu
      }
}

hope this helps!

0
votes

I encountered this problem a few month ago when I started building my game with spriteKit.

And my answer is not really definite but here is my advice: For the in-game I would set up the UI programmatically - seems like a lot of work but for a video game it is actually not that bad. But some menu could be in a storyboard setup or xib file - like the main menu, and the different submenu outside the game.

For the touch add that function to your scene.m

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{

    CGPoint location = [[touches anyObject] locationInNode:self];
}

And then you can use CGRectContainsPoint();

Or you can add a UITapGestureRecognizer to you view controller.

UITapGestureRecognizer * recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];

recognizer.delegate = self;

[view addGestureRecognizer:recognizer];

Setting up buttons in SKScene