I've recently started learning programming to make my own 3D OpenGL game on the iPhone and have made reasonably decent progress so far. I started off using the basic OpenGL example that is provided with the iPhone SDK which helped me get off to a good start. However, as I'm starting to get the hang of things, it has occurred to me that I'm unnecessarily programming in Objective C which will make it harder to port the game to other platforms in the future. So I figured that it would be best to make it properly C++ now to avoid lots of extra work later.
To clarify: I'm not actually using any calls to Apple (Objective C) functions or anything, its just that I've based all my clases on the Objective C-style init/dealloc/etc, so that my engine looks like Objective C classes when used. My aim is to replace all the objective C stuff with the C++ equivalents... the trouble is that, being pretty new to C++, I'm not sure what corresponds with what!
Here's a simple example of one of my classes (myLight), in its current Objective C incarnation:
// myLight.h
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#im开发者_如何学Cport <OpenGLES/ES1/glext.h>
@interface myLight : NSObject {
char *name;
GLfloat *ambient, *diffuse, *specular, *position, *spotDirection;
GLfloat spotRadius;
GLfloat *matAmbient, *matDiffuse, *matSpecular;
GLfloat shininess;
Byte lightType;
}
@property (readonly) char *name;
@property (assign) GLfloat *position;
@property (assign) GLfloat *spotDirection;
@property (assign) GLfloat *ambient;
@property (assign) GLfloat *diffuse;
@property (assign) GLfloat *specular;
- (id)initWithContentsFromDatastream:(NSData *)fileData;
- (void)set;
@end
And the corresponding .mm file:
// myLight.m
#import "myLight.h"
@implementation myLight
@synthesize name, ambient, diffuse, specular, position, spotDirection;
- (id)initWithContentsFromDatastream:(NSData *)fileData {
self = [super init];
NSData *fileContents = fileData;
uint ptr = 0;
Byte nameLength;
[fileContents getBytes:&nameLength range: NSMakeRange(ptr, sizeof(Byte))];
ptr++;
name = new char[nameLength];
[fileContents getBytes:name range: NSMakeRange(ptr, (nameLength * sizeof(char)) )];
ptr = ptr + (nameLength * sizeof(char) );
[fileContents getBytes:&lightType range: NSMakeRange(ptr, sizeof(Byte))];
ptr++;
position = new GLfloat[4];
for(int j = 0; j < (4); j++)
[fileContents getBytes:&position[j] range: NSMakeRange( (j* sizeof(float) ) + ptr, sizeof(float))];
ptr = ptr + (4 * sizeof(float));
if(lightType==2){
spotDirection = new GLfloat[3];
for(int j = 0; j < (3); j++)
[fileContents getBytes:&spotDirection[j] range: NSMakeRange( (j* sizeof(float) ) + ptr, sizeof(float))];
ptr = ptr + (3 * sizeof(float));
[fileContents getBytes:&spotRadius range: NSMakeRange(ptr, sizeof(float))];
ptr = ptr + sizeof(float);
} else
spotDirection = NULL;
diffuse = new GLfloat[4];
for(int j = 0; j < (4); j++)
[fileContents getBytes:&diffuse[j] range: NSMakeRange( (j* sizeof(float) ) + ptr, sizeof(float))];
ptr = ptr + (4 * sizeof(float));
ambient = new GLfloat[4];
for(int j = 0; j < (4); j++)
[fileContents getBytes:&ambient[j] range: NSMakeRange( (j* sizeof(float) ) + ptr, sizeof(float))];
ptr = ptr + (4 * sizeof(float));
specular = new GLfloat[4];
for(int j = 0; j < (4); j++)
[fileContents getBytes:&specular[j] range: NSMakeRange( (j* sizeof(float) ) + ptr, sizeof(float))];
ptr = ptr + (4 * sizeof(float));
[self set];
return self;
}
- (void)set{
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glLightfv(GL_LIGHT0, GL_POSITION, position);
if(lightType==2)
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spotDirection);
}
- (void)dealloc {
delete[] specular;
delete[] ambient;
delete[] diffuse;
if (spotDirection)
delete[] spotDirection;
delete[] position;
delete[] name;
[super dealloc];
}
@end
If someone could point out which lines need to be changed and, more importantly, what they should be changed to to make it compile as pure C++, I'd really appreciate it.
Many Thanks!
First of all, please keep in mind that Objective-C is not just a "different format" of C, it's a separate language and more important, in the case of Cocoa, a separate framework. Therefore if you want to be able to port your project to other platforms in the future, you not only have to get rid of Objective-C but also of the Cocoa framework.
To map the classes from Objective-C to C++ you would have to do the following:
- create a new C++ class to replace the old class
- create constructors for the
-init...
methods - create a destructor for the
-dealloc
method - create other methods which duplicate the functionality
- for properties you would probably create getters and setters instead
- replace the
#import
with#include
directives, as this directive only exists in Objective-C (make sure that the headers you include are protected against multiple includes) - get rid of usages of NS... classes and methods, as those are part of the Cocoa framework and most probably cannot be ported
You should take some time to consider how you will use the code you're writing. Porting 1:1 is probably not such a great idea as there are many differences in idioms between coding in Cocoa and C++ (or any other language/framework).
Most of the applications logic may be translatable to C++, but there are going to be things that have no straightforward equivalent in C++. For example:
- There is no
@encode()
compiler directive (which is used for NSValue and a few other classes). - There is no straightforward equivalent to
doesNotRecognizeSelector:
,respondsToSelector:
,conformsToProtocol:
orperformSelector:
(and other methods of similar nature). - In Objective-C it is fine to send a message to
nil
, but in C++ it is not OK to call a member function on a null pointer. - Objective-C allows extending existing classes using class categories, for example, you can add a method to
NSString
which counts the number of spaces, callednumberOfSpaces
and it will be available for allNSString
instances in your application. - C++ does not have a
finally
block fortry
/catch
, but Objective-C has@finally
for@try
/@catch
.
If you plan on releasing your application to multiple platforms, what you could do is try to abstract as much as you can into a separate library. Your iPhone application can be written in Objective-C and use functions from your library, and if you plan on porting it to another system whose frameworks require C++, then you can write a C++ application and use the same functions from the same library. I imagine your library would basically consist of [at least] your drawing routines and core game engine logic.
精彩评论