Create a scene helper class for iOS / Mac cross platform SpriteKit games

There was a lot of interest in my post giving a few vague suggestions for converting a sprite kit game from iOS to Mac. Since then I've refined my methods a bit and now work with a project which is targeted for both iOS and Mac to make it even easier to implement and test.

Even if you never plan to release your game on Mac OS X, the below is still useful. The iOS simulator is painful at times however running SpriteKit natively on the Mac is simply beautiful, it makes testing a lot more fun.

Getting Started

The first thing you need to do is make a project containing both a target for iOS and for Mac OS.

  1. Create a new Xcode project
  2. Select "Sprite Kit Game" from the iOS templates
  3. Give it a name
  4. Go to "File", "New", "Target..."
  5. Select "Sprite Kit Game" from the Mac templates

You now have a template containing both two targets. If you are familiar with both Mac and iOS development it shouldn't take you too long to work out what is going on here. Have a look at your schemes and project settings.

I like to arrange my folders so that my Mac only code is in a "Mac" folder, the iOS only code is in a "iOS" folder and the shared game is in a "Shared" folder.

You can control which target has access to which game files via the "Target Membership" settings in the file inspector on the right.

Platform specific code

In iOS you are probably familiar with performing different code specific you wether you are running the application on an iPhone or iPad. You will run in to the same problems when coding for both Mac and iOS.

There are a lot of differences in the way you code between both platforms, even which classes you are using, so in most cases a standard IF statement won't be enough and you will need pre-processor #IF statements.

Example:

#if TARGET_OS_IPHONE
#endif

There is also a TARGET_OS_MAC but you will probably find that iOS devices respond to this as well, so it is a lot easier to just check !TARGET_OS_IPHONE.

It's a different world

Before going any further it is worth noting that you are working in two different worlds governed by two different HIG documents. What you know in iOS may not apply to Mac development. 

You are also working with a touch screen device without keyboard and a mouse and keyboard operated device. This is a simple fact but it will show in your game if you don't pay attention to it. I had an app rejected at review once for the reason my start screen said "Tap anywhere to begin" instead of "Click", a rather embarrassing mistake but one I make sure to prepare better for now.

Ok, enough of the lecture, you all want the helper class right?

A scene helper class to get you started

This is a very simple class but I want you guys to take it and add your own code to it. If your game uses a onscreen DPAD on iOS then it makes no sense do the same on Mac, you would need to monitor key presses instead.

This class helps for all other cases, it allows you to single methods for handling both screen clicks and screen taps. Great for games where screen presses translate easily in to screen clicks.

Create a class called SKMScene that inherits from SKScene.

Put the below in SKMScene.h:

// Created by Neil North on 6/02/2014.
// Copyright (c) 2014 Neil North. All rights reserved.
//

#import

@interface SKMScene : SKScene


//Screen Interactions
-(void)screenInteractionStartedAtLocation:(CGPoint)location;
-(void)screenInteractionEndedAtLocation:(CGPoint)location;

@end

And the below in the SKMScene.m file:

// Created by Neil North on 6/02/2014.
// Copyright (c) 2014 Neil North. All rights reserved.
//

#import “SKMScene.h”

@implementation SKMScene

-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
/* Overridden by Subclass */

}
return self;
}

#if TARGET_OS_IPHONE
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
[self screenInteractionStartedAtLocation:positionInScene];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
[self screenInteractionEndedAtLocation:positionInScene];
}

- (void)touchesCancelled:(NSSet *)touches
withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
[self screenInteractionEndedAtLocation:positionInScene];
}
#else
-(void)mouseDown:(NSEvent *)theEvent {
CGPoint positionInScene = [theEvent locationInNode:self];
[self screenInteractionStartedAtLocation:positionInScene];
}

- (void)mouseUp:(NSEvent *)theEvent
{
CGPoint positionInScene = [theEvent locationInNode:self];
[self screenInteractionEndedAtLocation:positionInScene];
}

- (void)mouseExited:(NSEvent *)theEvent
{
CGPoint positionInScene = [theEvent locationInNode:self];
[self screenInteractionEndedAtLocation:positionInScene];
}
#endif

-(void)screenInteractionStartedAtLocation:(CGPoint)location {
/* Overridden by Subclass */
}

-(void)screenInteractionEndedAtLocation:(CGPoint)location {
/* Overridden by Subclass */
}

@end

That's it, now all you have to do is make sure all your scenes inherit from SKMScene instead of SKScene and implement the two screenIntereaction methods.

There's a lot more to this process and I'm only just starting to learn to make cross platform games myself but I hope the above tips have helped you on your journey. Give it a go and see what you think.

You can also download a sample project on GitHub.

Converted a SpriteKit game from iOS to OS X

My February game for my one game a month challenge is now complete and in apple's hands for approval. In designing this game I always intended it to be available for both iOS and OS X even though I knew nothing about OS X development. I expected the conversion to be a complete disaster but everything actually went better than expected...

My preparations were actually quite simple:

  • Minimised usage of UIKit until it was nearly completely unused.
  • Made sure to use % of self.size coordinates instead of hard coded coordinates where possible.
  • Made sure that any variables or defined code that relied on device type or screen size to be stored in my constants.h file so it could be easily modified.

As you can see, my preparations were rather minimal. We are talking about a very small time investment in order to get my game on another platform.

The conversion itself was rather painless:

  • I created a new Mac OS X Sprite Kit project and dumped my game in to it.
  • Setup the appDelegate to point to my first game scene.
  • Went through each scene replacing Touch events with Mouse click events.
  • Fixed links to plists, the way I referenced them in iOS didn't work for Mac OS, I believe using the code I changed it to in iOS as well will resolve this issue in the future.
  • Fixed some game center differences.
  • New Icons, profiles, settings, etc

The process took less than 4 hours and in the future I expect it to be a lot quicker now that I have learnt a few things. I plan to make all future SpriteKit games completely cross platform (assuming Mac OS X sales will be reasonable).

I know this post was vague, drop me a line if you want a tutorial.

Some great SpriteKit resources

In order to start getting some games on the store quickly with my challenge I'm having to cram a lot of SpriteKit knowledge.

It seems everyone has a different idea of how things are done and surprisingly some of the most experienced iOS developers I've seen are still using old methods of doing things, possibly because they are coming fresh from Cocos2D.

Right now I have 5 different sample projects open with different implementations of an entity class, as I observe each of them I have been using ideas I've liked and trying to write the code as robust as possible, at times it sort of feels like music, like a different person would have a completely different interpretation of what is good or bad but neither are technically wrong.

It's an interesting world of 2D development to be working in, here are a few tools I've found along the way which have been useful:

  • SKPhysicsBody Generator  - This website is great, you can drag in an image then draw a polygon and get the code straight away to put it in your app. I even took this a little further by making a simple spreadsheet tool which prepares the results for a plist and method to loop through creating the physics body from a plist file.
  • Kobold Kit - I haven't used it myself by this looks promising and I will probably be implementing in at least some of my apps when it reaches version 1.0.
  • iOS Games by Tutorials - This book has been a fantastic learning reference, I've picked up a lot of useful information and their additional tools are great. Easily worth the price. (Disclaimer: I am affiliated with the Ray Wenderlich Team).
  • Cartoon Smart on Udemy - I love the work these guys do, while their Obj-C is still back in Cocos2D land, their examples are fairly top notch and its really good to learn something from a different perspective than just RW.
  • Apportable -  While I am yet to try it, Apportable sounds like a high quality and reliable way to convert your Sprite Kit projects in to a format usable on the android platform. If it works then you have just increased your market size with minimal effort.

What does the introduction of MFi game controllers mean for developers?

Another WWDC and another swag of great feature and framework updates for iOS and Mac OSX. The introduction of Sprite Kit and update of Game Center is a much needed step in the right direction for producing more and better games on iOS but one feature that really interests me is the introduction of MFi game controllers. 

In the past if developers wanted to be able to support controllers on their iOS games they would have had to use 3rd party bluetooth controller which pretty much just emulated a keyboard being attached. This wasn't bad but it also wasn't overly popular and had limited use. The iCade was a popular devices along with the iControlPad, there was even an app so you could use a second iOS device as a controller called Joypad. All of these systems were fairly easy to implement, the problem is though not many developers did, instead opting to focus on the built in tools like accelerometer and on screen controls. 

So the introduction of controllers that are easy to implement to a consistant standard is a pretty cool thing. What do developers have to think about though?

Opportunity

Very soon when kids go to their apple stores or local electronics store they will start seeing some very interesting controllers on display, there might even be demo units out for kids to have a play on. They will probably sell reasonably well and in the short term if there are only a handful of games which support these controllers then you have a huge opportunity to boost sales of your apps. 

It's also an opportunity to do things differently, there has always been a gap between games based on consoles and those based on touch devices due to the difference in controls. This is no longer such an issue. 

People don't remember all the products that do great things, only the ones that do them first. 

Balance

Gameloft also released a controller once for use with their games, it's sales were pitiful but that may just be because it only worked on a very small selection of their games. One thing that really stood out on their first person shooters though was that it was much easier to aim at something with a controller than with the touch screen, just like it is easier to drive a car with a controller than an accelerometer. 

There is a huge balance risk here as the control scheme could potentially change the difficulty of the game quite heavily and reaching a mid point is hard work. In a first person shooter you may have to have higher aiming assists and racing games may need more powerful driving assists, etc. You also run in to the problem that the Wii had with Mario Cart by designing it to work with those annoying plastic wheels, the game became so simplified that it just wasn't fun to play with a controller, there was no depth and nothing exciting about driving.

Reaching a midpoint where both playing with the device or with a controller feels equal will be the hardest thing developers need to deal with.

Hybrid Controls

One idea Apple seemed keen to push was using the controller for some things but then using the screen or accelerometer when it makes sense to. The case controllers that keep the device in the centre could make use of this fairly well. 

To me, it seems like something worth exploring. That same theory is what made the Nintendo DS a very popular console before the rise of iOS gaming, so it is definitely an area worth exploring. I'm sure finding a new and exciting hybrid control scheme would be a great way to get featured by Apple. 

The challenge here is supporting gameplay when a controller isn't actually connected, you need to be able to design it in a way so that the two control elements don't get too jumbled when you are just playing on the single screen. 

Don't forget the screen!

While controllers are cool, not everyone will use one and not everyone who uses one will take a controller everywhere they go. You should still offer the alternative of onscreen controls or similar and unless you specify your app is controller only fairly clearly and have good reason for it, your app would probably be rejected. 

Airplay

Imagine you have a computer or iDevice with an Apple TV and controller in the house, you can pretty much emulate a console experience! Playing the game live on TV with your controller while the computer or iDevice handles the game like a console.

Optimising your game to run over airplay could extend sessions of play quite significantly, don't believe me? Try comparing the average play time of a kid sitting in front of a TV playing a game to that of a kid sitting in their bedroom on an iDevice. More play time means more iADs presented, more in-app purchases bought and more feedback on your product.

Cool! So how do I get started? 

If you are a registered developer you can get started right now, the only issue you will have is that you will have a small testing window to see if it is all working. The first controllers come out in fall around the same time as iOS7. 

One final thought... 

If you can now share the same achievements and leader boards over both OSX and iOS and share game data and state information via iCloud between OSX and iOS AND use the same controller for both OSX and iOS AND use Sprite Kit to developer games that will work with the same code on both OSX and iOS.... doesn't it seem like the era of true mobile gaming has begun where you can start, stop and pick up your game / match from where ever you are and whatever device you are on? The first game to take TRUE advantage of the opportunities Apple have provided, will be pretty damn awesome!