Pong game with Objective-C++

My weekend project was to write a Pong game in C++ and make it portable enough to work with different UI toolkits. The first incarnation is called XPong and uses Cocoa to provide native UI for the game. It is published on Github and could be compiled and launched on OS X.

The natural way to integrate C++ and Objective-C code is to use Objective-C++ which is basically a mix of the two without any new features. Naturally you either declare C++ class which makes use of Objective-C objects or otherwise define an Objective-C class which makes use of C++ code. On the project level if you have a portable C++ module you typically have to use this module from Objective-C application and instrument the module to call back the Objective-C frameworks.

Using Objective-C in C++ classes

Let’s look at example: objects in the Pong game have to draw themselves, and to do so they should call Cocoa APIs. In particular they have to use NSBezierPath to fill rectangles and ovals. To localize dependency on particular drawing methods Pong game introduces abstract class DrawingContext:

class DrawingContext {

public:
    DrawingContext() : _fillColor(RGBColor(1)) {}
    virtual ~DrawingContext() {}
    RGBColor fillColor() const { return _fillColor; }
    virtual void setFillColor(RGBColor const &color) { _fillColor = color; }
    virtual void fillRectangle(Rectangle bounds) = 0;
    virtual void fillOval(Rectangle bounds) = 0;

private:
    RGBColor _fillColor;
};

Note that it is a proper C++ class which requires subclasses to implement actual painting functions using appropriate system APIs. In the XPong project we define XDrawingContext class which extends DrawingContext and implements these methods. Note that implementation file should be called XDrawingContext.mm so Xcode will know that it is an Objective-C++ code. Here is a header file for XDrawingContext:

class XDrawingContext : public Pong::DrawingContext {

public:
    XDrawingContext(NSGraphicsContext *xcontext);
    virtual ~XDrawingContext();
    virtual void setFillColor(Pong::RGBColor const &color);
    virtual void fillRectangle(Pong::Rectangle bounds);
    virtual void fillOval(Pong::Rectangle bounds);

private:
    NSGraphicsContext *_xcontext;
};

And its implementation:

XDrawingContext::XDrawingContext(NSGraphicsContext *xcontext) {
    _xcontext = [xcontext retain];
}

XDrawingContext::~XDrawingContext() {
    [_xcontext release];
}

void XDrawingContext::setFillColor(Pong::RGBColor const &color) {
    DrawingContext::setFillColor(color);
    NSColor *xcolor = [NSColor colorWithDeviceRed:color.red
                                            green:color.green
                                             blue:color.blue
                                            alpha:1];
    [xcolor setFill];
}

void XDrawingContext::fillRectangle(Pong::Rectangle bounds) {
    NSBezierPath *path =
        [NSBezierPath bezierPathWithRect:NSRectFromRectangle(bounds)];
    [path fill];
}

void XDrawingContext::fillOval(Pong::Rectangle bounds) {
    NSBezierPath *path =
        [NSBezierPath bezierPathWithOvalInRect:NSRectFromRectangle(bounds)];
    [path fill];
}

So that’s how you call Objective-C from C++: just implement C++ class and use Objective-C calls within method implementations.

Using C++ in Objective-C classes

The next example is GameView class. It is a custom Cocoa view which will draw Pong game objects in itself and will forward user input to it. Here is its header file:

@interface GameView : NSView

@property(assign) Pong::Drawable *gameContent;
@property(assign) Pong::InputHandler *gameResponder;

@end

And here is the implementation:

@implementation GameView

@synthesize gameContent = _gameContent;
@synthesize gameResponder = _gameResponder;

- (void)drawRect:(NSRect)rect {
    [[NSColor grayColor] set];
    NSRectFill(rect);
    NSGraphicsContext *xcontext = [NSGraphicsContext currentContext];
    XDrawingContext context(xcontext);
    if (self.gameContent) {
        self.gameContent->draw(context);
    }
}

- (void)keyDown:(NSEvent *)theEvent {
    if ([theEvent.characters length] > 0) {
        const char c = [theEvent.characters characterAtIndex:0];
        if (self.gameResponder) {
            self.gameResponder->handleKey(c);
        }
    }
}

@end

I omitted some irrelevant details to show only what is important. GameView has two properties which are pointers to C++ classes. We can’t release and retain C++ objects so I declare properties with ‘assign’ so the caller will manage their life span. Implementation of GameView methods simply invoke methods of C++ objects and that’s how it works.

Objective-C++ provides an easy way to integrate C++ and Objective-C code. You literally use ‘mm’ extension for the files, mix the code and it works.

Leave a comment