This article is for C++ programmers who want to port their Microsoft Win32 games to Apple’s Cocoa. This is not a comprehensive tutorial. It is more like a guided tour. However, it should give you a good idea where to start and help you avoid costly delays.
At first the task may seem daunting: the Cocoa platform is written in another language – Objective-C; the Cocoa application bundle and program flow are different; and you will be working in an unfamiliar IDE – Xcode. To be successful, we must embrace change – vive la différence. We cannot treat Cocoa like Win32. We cannot hack Cocoa to behave like Win32. We cannot even hack Cocoa to behave like a generic C++ app. If we want to use Cocoa, we need to play by its rules.
Before we continue, I would be remiss not to mention Carbon. Carbon is Apple’s older OS API. It behaves much like Win32. Carbon applications are still supported by Mac OSX. However, they are considered legacy tech. Apple discourages the development of new Carbon applications. Also, if you have any desire to port your game to the iPhone, iPad, or iPod Touch, Carbon will not work.
Overview
The first three sections – Base Requirements, Language Barrier and Entering the App – will cover high-level concepts. These provide a basis for understanding the implementation sections.
Base Requirements
For a port to be successful, our game must rely on abstracted interfaces to interact with the operating system. With these in place, the game itself can be written with little regard for platform. The OSX implementation of these interfaces will receive its information from Cocoa. For that to work, we must find a way to make C++ and Objective-C work together.
Language Barrier
Fortunately, Objective-C and C++ use the same compiler. We just need to make sure that Xcode knows which Objective-C files are using C++ code. Normally an Objective-C file has a .m extension. However, if we use C++ in the file as well, the extension needs to be .mm. In Xcode, this sets the compiler to g++ instead of gcc. Apple calls this Objective-C++.
There are a few finer issues related to mixing C++ and Objective-C, but they will not be covered here. I will simply recommend that you contain your C++ implementation in .cpp files and only use C++ functionality in .mm files by including headers.
Entering the App
When learning a new API, our first instinct may be to skim the documentation and then dive into sample code. Let’s do that!
- Open Xcode (I am currently using v3.1.4)
- Select File > New Project…
- On the New Project screen, create a Cocoa Application.

- Once the project has been created, press Build and Go.
We now see a window, labeled “Window”, and a menu bar at the top of the screen. We have our first Cocoa application without doing any work. Now, let’s check out the code that made this happen.
- First, press the Xcode button that looks like a stop sign to close the app.
- In the Xcode Groups & Files browser – at the left of the Xcode window – open the only source code file, main.m. It is in the Other Sources group.
Surprised?
The source code for application template is
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **) argv);
}
As you can see, reverse-engineering the source is impossible. The bulk of the existing code is hidden from us.
The hidden code is being generated by something called a nib file. Open MainMenu.xib under the Resources group. This will open the Interface Builder (IB) application. Much to the chagrin of non-Cocoa developers, every Cocoa project relies on a root nib file to launch and configure the application. Hacking nib files without understanding them can be a huge waste of time, as is attempting to create a Cocoa application programmatically. You will save time by first learning the fundamentals. Teaching these is beyond the scope of this tutorial. However, I will happily save you hours of Googling by pointing you to three excellent primers.
The first is the Introduction to the Objective-C Programming Language, followed by the Cocoa Fundamentals Guide, and lastly the Cocoa Application Tutorial.
Once you are familiar with Objective-C and Cocoa, continue reading this tutorial.
Customizing our Cocoa App
As I mentioned before, the target audience for this article are those attempting to port games. While porting must account for every OS interaction, we will only be discussing the game loop, drawing surface, and keyboard/mouse controls.
One of the biggest differences between Cocoa and Win32 is that Cocoa’s application loop is hidden. You can imagine the problems this causes.
Game Loop
Unlike a Win32 game loop – which is normally called by the application loop – a Cocoa game loop is based on a timer callback. This means that, during initialization, you must create a timer that will call your game loop at the appropriate interval.
Generally, you will use an NSTimer. However, for iPhone development, you may want to investigate CADisplayLink.
There is a sample near the end of the article.Drawing Surface and Events
In Win32 you render directly to the window object. In Cocoa you render to a special NSView held by the NSWindow, NSOpenGLView. An NSView subclass is essentially the view from the Model View Controller design pattern. Nearly every renderable Cocoa object is s subclass of NSView (UIView on iPhone).
The view is also the object that detects input events. However, instead of handling them in a generic event function, it is common to use built-in specialized functions like keyDown or mouseDown. You can learn more about events in the Cocoa Event-Handling Guide.
Before your custom view can start handling events, you will need to import it into Interface Builder. The following is based on the assumption that you have created a custom subclass of NSView.
- Open the nib file for your project
- In IB, select File > Read Class Files… then locate your custom view class
- Select the NSView contained within the window (we are going to change its identity)
- Select the identity tab from the inspector window and open the list of classes under Class Identity.
- If your class was imported correctly, it will be in the list.
If you are importing the class from a library you must ensure that the library is properly linked. Otherwise, the application will simply print a warning on the debug console at runtime and continue using a standard NSView instead of your custom subclass (“Unknown class <name> in Interface Builder file”). For more information about linking in Xcode, check out Linking Custom Frameworks from your Xcode Projects.
Even if your project is properly linked, you may still encounter the error mentioned above. Remember that, in most compilers, if you do not call a class function, that class will not be linked. Oddly enough, Xcode will not automatically link classes included in nib files. To overcome this, you can call a static dummy function in your class. This may sound like a messy, inelegant solution but it is preferable to the alternatives. The only other way to solve this is to add linker flags to the Other Linker Flags section of your project build properties. The flags are:
- -all_load – forces the linker to load every object file from every archive that it sees.
- -ObjC – forces the linker to load every Objective-C object from every archive that it sees. Note that this flag will not work on iPhone OS, so you must use -all_load instead.
Clearly, this is less than optimal. You can read more about these flags here.
Conclusion
I think that by now you have the right mindset and are ready start tackling the port of your game. However, there is still much more to learn. Apple has done a good job documenting the Cocoa API – much better than the Carbon documentation. Mastering Cocoa will take practice and, hopefully, this guide has accelerated that.
I would like to leave you with the Cocoa OpenGL sample project. It combines the game loop, keyboard, mouse and rendering concepts described above.
Tags: C/C++, Cocoa, cross-platform, Objective-C, Xcode




