How To Integrate Cocos2D and UIKit

Cocos2D is a great framework, but sometimes it’s handy to implement some of your game with UIKit. For example, it’s often useful to design your main menu, settings pages, and the like with UIKit and just use Cocos2D for your main game logic. You also might find it handy to use UIKit controls on top […] By Ray Wenderlich.

Leave a rating/review
Save for later
Share

Build an app that is part Cocos2D, part UIKit!

Build an app that is part Cocos2D, part UIKit!

Cocos2D is a great framework, but sometimes it’s handy to implement some of your game with UIKit.

For example, it’s often useful to design your main menu, settings pages, and the like with UIKit and just use Cocos2D for your main game logic.

You also might find it handy to use UIKit controls on top of a Cocos2D scene – such as text fields, buttons, tab bars, or ad views.

In this tutorial, you’ll learn how to do exactly like this! We’ll take a simple Cocos2D app and modify it to use UIKit for the main menu and an about page, and overlay some UIKit controls on top.

This tutorial assumes you have some basic familiarity with Cocos2D and UIKit development. If you are new to Cocos2D or UIKit, check out some of the other tutorials on this site first.

Getting Started

Start by downloading the starter project we’ll be using for this tutorial.

Go ahead and run the project and you should see the following:

Start of Masked Calendar project

This project is a simple Cocos2D app that displays a set of calendars made by my lovely wife Vicki.

If you’re curious how to make this app, we went through this step by step in the How To Mask a Sprite with Cocos2D 1.0 tutorial. However, I made a few slight modifications since that tutorial:

  • Added some new wallpapers Vicki made
  • Added some new art you’ll need for this tutorial
  • Enabled retina display support
  • Made the wallpapers advance in order rather than randomly
  • Modified the scene transition

So take a look through the code, get your bearings, and make sure you understand how everything is working. Because we’re about to UIKit-it-up!

Adding a MainWindow.xib

By default, the Cocos2D template doesn’t use a MainWindow.xib. Instead, in Supporting Files\main.m, it passes the name of the AppDelegate class to UIApplicationMain:

int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate");

This tells UIKit to create an instance of the AppDelegate class on startup. The AppDelegate then creates the main window at the start of applicationDidFinishLaunching:

window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

This is a fine way of doing things, but if we continued down this path, if we wanted to start with a different view controller for the main menu on startup, we’d have to create it programatically.

Personally, I prefer using Interface Builder whenever possible since it’s faster and less lines of code means less maintenance, so let’s modify the project to start by loading a XIB first – called MainWindow.xib.

Start by opening Supporting Files\main.m, and replace the line that calls UIApplicationMain with the following:

int retVal = UIApplicationMain(argc, argv, nil, nil);

When you pass nil in as the last parameter, it instructs UIKit to load whatever XIB is specified in Info.plist under the NSMainNibFile key. So let’s add that next!

Open your Info.plist, right click in the empty area, and select Add Row from the popuo menu. You can select “Main nib file base name” from the dropdown (or type in the raw key NSMainNibFile).

Then double click in the Value column for this new key, and enter in MainWindow. Your screen should look like the following:

Setting Main NIB Base Name in Xcode

Next step is to create MainWindow.xib! Control-click on your MaskedCal group and select New File. Select iOS\User Interface\Empty, and click Next. Select iPhone for the Device Family, click Next, name the file MainWindow.xib, and click Save.

Click on the new MainWindow.xib file, and you’ll see it load into Interface Builder – mostly blank!

An empty XIB created with Xcode

Let’s set this up. First, we need to set the File’s Owner to UIApplication. This is because we’ve told UIApplication to XIB for us on startup, and it passes us a reference to itself.

So click on File’s Owner, and in the Identity Inspector in the sidebar, set the Class to UIApplication.

Setting File's Owner to UIApplication

Next, we need to configure the XIB to create an instance of our Application Delegate on startup. So in the Object library, drag an Object over to the Objects panel:

Dragging an Object into the Objects pane in Xcode

Then, select the new Object, go to the Identity Inspector, and set the Class to AppDelegate.

Setting the Application Delegate

One last thing – we have to tell the UIApplication that this new AppDelegate class is its delegate! Do this by control-clicking File’s Owner, and control-dragging the dot next to the delegate onto the App Delegate Object:

Connecting the Application Delegate

w00t! We’ve just set up the following start-up sequence:

  1. In main, UIApplicationMain runs, with the last parameter set to nil.
  2. UIKit then loads the XIB we specified in Info.plist – MainWindow.xib.
  3. When the XIB is loaded, it creates an instance of each object we set up in the XIB. Right now, we have the AppDelegate class in there, so it creates a new AppDelegate class.
  4. Loading the XIB also wires the AppDelegate instance as the delegate of UIApplication.
  5. So now UIApplication will call methods such as applicationDidFinishLaunching on the AppDelegate class!

OK, now let’s finish setting up this XIB. Let’s create the main window in the XIB rather than creating it programatically. Open up AppDelegate.h and modify the UIWindow property to mark it as an IBOutlet:

@property (nonatomic, retain) IBOutlet UIWindow *window;

Also go to AppDelegate.m and comment out the line that was creating it programatically:

//window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

Go back to MainWindow.xib and drag a Window from the Object library into the Objects panel. Then control-drag on the App Delegate object, and drag a line from the window outlet to the new Window object:

Connecting the main Window to an outlet

Compile and run your project, and everything should work just as before, except now you’re using a MainWindow.xib, which will make our next step a bit easier.

Adding a Main Menu View Controller

Instead of starting out with our Cocos2D scene right away, let’s modify this project to start with a different View Controller instead – one we’ll set up as a main menu.

Let’s create the new view controller first. Control-click on the MaskedCal group and select New File. Select iOS\Cocoa Touch\UIViewController subclass, and click Next. Enter UIViewController for Subclass of, make sure Taregeted for iPad is NOT selected, With XIB for user interface IS selected, and click Next. Name the new class MainMenuViewController.m, and click Save.

Click MainMenuViewController.xib, and click on the View under Objects. In the Attributes Inspector, set the Orientation to Landscape.

Setting the orientation of a UIView to Landscape in Interface Builder

Next drag an Image View into the view, and make it fill the entire area. Set the Image to Title_bg.png.

Next drag a Round Rect Button into the view. Select the Size Inspector and set X=173, Y=143, Width=135, and Height=62:

Adding a UIButton with Xcode

Select the Attributes Inspector, set the Type to Custom, and for the Default state set the Image to button_view_uns.png. Then change the State Config to Highlighted, and set the Image to button_view_sel.png.

Repeat this for a second button with the following info:

  • X=173, Y=213, Width=135, Height=62
  • Custom type
  • Default state image: button_about_uns.png
  • Highlighted state image: button_about_sel.png

One slight code mod we need to make. Open up MainMenuViewController.m and make the following changes:

// Replace this method
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}

// Add new method
- (void) viewWillAppear:(BOOL)animated
{
    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];
}

This will make sure our view controller only rotates to landscape orientation, and that it hides the navigation bar when it starts up.

This is good for now, we’ll finish hooking up the buttons later. Let’s just get this to show up on startup now.

Select MainWindow.xib, and drag a Navigation Controller into the Objects panel. Control-click on the Window, and drag a line from the rootViewControlelr to the new Navigation Controller:

Setting the Window's rootViewController in Xcode

This is setting the first view controller that shows up to be this navigation controller. We’re using a navigation controller to make managing the view controller stack a bit easier.

Next, click the arrow next to the Navigation Controller so it faces down and select the View Controller inside. In the Attributes Inspector, set the NIB Name to MainMenuViewController, and in the Identity Inspector set the Class to MainMenuViewController.

This makes the first item in the Navigation Controller the new Main Menu View Controller we just made!

Almost done – we just need to comment out some old code the Cocos2D template set up for us.

Open up AppDelegate.m and comment out the following sections:

/* 
#import "HelloWorldLayer.h"
#import "RootViewController.h"
*/

/* 
// Init the View Controller
viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
viewController.wantsFullScreenLayout = YES;

//
// Create the EAGLView manually
//  1. Create a RGB565 format. Alternative: RGBA8
//	2. depth format of 0 bit. Use 16 or 24 bit for 3d effects, like CCPageTurnTransition
//
//
EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
pixelFormat:kEAGLColorFormatRGB565	// kEAGLColorFormatRGBA8
depthFormat:0						// GL_DEPTH_COMPONENT16_OES
];

// attach the openglView to the director
[director setOpenGLView:glView];
*/

/* 
// make the OpenGLView a child of the view controller
[viewController setView:glView];

// make the View Controller a child of the main window
[window addSubview: viewController.view];
*/

/* 
[[CCDirector sharedDirector] runWithScene: [HelloWorldLayer sceneWithLastCalendar:0]]; 
*/

OK that’s it for now! Compile and run, and you’ll see the new main menu view controller on startup:

The main menu view controller displayed

Next, let’s get that View button working!

Contributors

Over 300 content creators. Join our team.