iPhone Top Tips is for developers who are working on iPhone Application Development or Games Development. I post here my past experience and new techniques which will useful for you guys.
Monday, October 25, 2010
Display UITextField in Cocos2d Game
txtName = [[UITextField alloc] initWithFrame: CGRectMake(160, 240, 200, 32)];
I add it to the subview like so:
[[[CCDirector sharedDirector] openGLView] addSubview: txtName];
The problem I'm having is that, when I change the orientation to PortraitUpsideDown with this command:
[[CCDirector sharedDirector] setDeviceOrientation:CCDeviceOrientationPortraitUpsideDown];
the UITextField and the keyboard don't change with the new orientation. When I click on the text box, the keyboard appears upside down and on the top of the screen.
I know I can change the rotation of the UITextField using CGAffineTransformMakeRotation, but how do I make the keyboard appear upright and at the bottom of the screen when in PortraitUpsideDown orientation?
When I detect an orientation change, in addition to setting the Director's device orientation like so:
[[CCDirector sharedDirector] setDeviceOrientation:CCDeviceOrientationPortraitUpsideDown];
I also needed to set the UIApplication's StatusBarOrientation as well
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortraitUpsideDown];
This caused the keyboard to orient and position itself correctly.
Hope this helps someone!
Friday, October 22, 2010
Mac App Store Coming Soon - Port your cocs2d game for Mac
The Mac App Store will be similar to the App Store, but instead of distributing iOS applications, it will distribute Mac applications.
This is big news for cocos2d users, since cocos2d already supports Mac!!
The guidelines and other requirements for the Mac App Store are online:
* Mac App Store Review Guidelines
* App Store Resource Center
So, download the latest cocos2d version, and start porting your cocos2d game for Mac!
Wednesday, October 20, 2010
Cocos2d Game Development Performance Tips
When I started working on the bizarre experiment that eventually became Space Harvest, I initially used Core Animation. This is great, up to a point, but I found I soon hit a performance wall - Core Animation wasn’t flexible enough to handle the types of things I wanted to do, and doesn’t really give you a lot of control over what’s happening under the hood.
Once I switched to Cocos2d, I found that a) it was a lot easier to get something that ran relatively smoothly, and b) because it’s designed for games, it provides loads of functionality to make your life easier.
This post is about some of the things I learned about improving performance when using Cocos2d. A lot of the time, I found out about this stuff by doing it the wrong way to start with. Though I doubt they’ll be anything here for experienced game developers, I hope my tips may be useful to anyone who (like me) is quite new to OpenGL and game development.
Profiling with Instruments
As with any software, before you start doing any work to improve performance, you should first look for where the bottlenecks are.
Run your project with the CPU sampler instrument to see where your program is spending its time. Though you can sometimes get valuable results by profiling on the simulator, you should try to do as much profiling on the device as possible. You probably already know the device usually runs software much slower than the simulator, but this is even more obvious with CPU/GPU intensive software like games. The device is MUCH slower at certain things than the simulator, so the only real way of seeing where the actual performance bottlenecks lie is to run on the device.
I find the most helpful way to start looking for potential performance bottlenecks is:
* Change Sample Perspective to ‘Running sample times’
* Change Active Thread to ‘Main Thread’. 99% of the time, the performance intensive parts of your game will be single threaded (on a single core device like the iPhone / iPod touch, it wouldn’t really make sense to do it any other way)
* Turn off invert call tree, and expand the list until you find [CCDirector mainLoop]
They’ll probably be two main places where your application will be spending its time - drawing, and running your main loop for game logic.
Always look for the low hanging fruit - those parts of your code that are taking up lots of time, and can be easily optimised. If your game is spending any significant amount of time in [CCScheduler tick], you should start your optimisation work there. Optimising your game logic will usually be less painful than optimising your drawing.
Testing on different devices
For most iPhone OS applications, the differences in hardware between devices is not particularly significant. Users might notice that things are a little more snappy on newer devices like the 3GS newer iPod Touches, but generally, it isn’t a big deal.
For games, the performance gap between the older devices and the newer ones is HUGE.
In Space Harvest, each level has a loading screen because it can take a while to pre-load the textures and load the maps that make up the game world. I thought it would be nice to include tips on how to play on the loading screen so users weren’t actually staring at nothing while each level loaded.
I performed the majority of my testing on my 3G iPhone. During the last couple of weeks before I released the first version of Space Harvest, I got to test Space Harvest on a 3GS iPhone. The first thing I noticed was that I could no longer read the tips. What might have been a ten second wait for loading on the 3G became a barely noticeable blue flash on screen before the level started on the 3GS. I ended up introducing a ‘tap to continue’ message, just to let people with newer devices see the playing tips.
So, the newer devices are faster - not just a bit faster, but a lot faster. A lot faster at loading textures, a lot faster at drawing things with OpenGL, a lot faster at just about everything. If you aren’t testing on older devices, how will you know if your game is even playable on older devices?
Ignoring the iPad for now, in performance terms, there are three classes of iPhone OS device:
* Slowest devices: iPhone / iPhone 3G / 1st gen iPod Touch(i)
* 2nd gen iPod Touch, 3rd gen iPod touch 8GB
* Fastest devices: iPhone 3GS, 32GB / 64GB 3rd gen iPod Touch
A couple of other random notes about the differences between older and newer devices:
* Older devices have half the RAM of newer devices (128MB vs 256MB), which means the likelihood of low memory warnings is much greater. This makes it even more important to manage your memory carefully.
* Older devices only support textures up to a maximum of 1024x1024 pixels. You should avoid textures larger than this size if you want your game to work on older phones and iPods.
Textures and Texture Atlases
Loading textures on the device is rather slow. Because of this, you should try to load textures before the user starts playing a level that may need them, otherwise you might get hiccups in frame rate.
When you create a sprite in Cocos2d, you’ll normally pass in a reference to the texture you want it to use, eg:
CCTexture2D *texture =
[[CCTextureCache sharedTextureCache] addImage:@"mytexture.png"];
CCSprite *sprite = [CCSprite spriteWithTexture:texture];
This helps keep things nice and simple. However, if you’re loading all your textures in advance, you may notice that loading starts to slow down on older devices - the more textures you load, the slower it gets.
Speeding up loading times
At one point during the development of Space Harvest, loading textures was taking more than 20 seconds. Just for loading textures. Once textures were loaded, the user would still have to wait for the map to load. Ouch!
The reason for this was that I hadn’t paid attention to what everyone was saying, and I wasn’t using texture atlases.
A texture atlas is basically a large image that contains lots of smaller textures. On the right is an example of one of the texture atlases used in Space Harvest.
Using a texture atlas can help speed up drawing significantly (more on this below), but equally importantly, it helps speed up texture loading, and helps reduce the amount of memory your textures will use once loaded.
Space Harvest uses lots of different sprites, some with as many as 50 frames of animation. By combining 50 textures into one texture, you’ll cut loading texture loading times significantly.
The newest versions of Cocos2d make this pretty easy. Here, we’re creating a sprite using a rectangular portion (specified in pixels) of a larger texture:
CCTexture2D *texture =
[[CCTextureCache sharedTextureCache] addImage:@"myatlastexture.png"];
CCSprite *sprite =
[CCSprite spriteWithTexture:texture rect:CGRectMake(0,0,32,32)];
Reducing memory usage
I mentioned you can also save memory by using atlas textures. This is because textures in Open GL ES must have a width and height that are a power of two, eg 64x128, 256x1024, 512x512 etc.
Cocos2d is smart enough to resize your images for you when it comes to loading textures, but look at all the space we’re wasting! In the above example, our 144x93 texture became a 256x128 texture once it got loaded into memory. This means we’ve ended up with more wasted space in our texture than used space!
For a single texture, this won’t be a big deal, but what happens when we load 50 textures like this? 50 times as much waste. Again, using texture atlases is a great way to solve this problem - you can easily combine lots of textures that don’t have a power of two width and height into a single texture that does.
Flipping textures
Another tip to cut down on memory usage is to use flipped textures. If your sprite looks the same when drawn facing in the opposite direction (but just horizontally or vertically flipped), you can use the same texture, and do the flipping in code by setting the flipX / flipY properties of your sprite.
Pixel formats
Cocos2d provides several different pixel formats for loading your textures. These are quite distinct from the format you use to save your texture images.
When saving a PNG image in Photoshop, I can decide whether I want to save it as an 8-bit indexed colour image, or a 24-bit truecolor image, or a 32-bit image that includes an alpha channel. The format I choose will depend on the nature of the image. 8-bit PNG is best suited for images with few colours that don’t use partial transparency. 32-bit images can have many colours and include partial transparency, though the file size will often be significantly larger.
When loading textures, the original format of the image doesn’t really matter that much - what’s important is the pixel format we use for loading. As with saving images for the web, it’s basically a question of balancing image quality and size.
kTexture2DPixelFormat_RGBA8888 is the default pixel format for textures, and provides the best image quality. It uses 8 bits for each colour (Red, Green and Blue), plus 8 bits for the alpha channel, for a total of 32 bits per pixel.
kTexture2DPixelFormat_RGBA4444 will use only 4 bits for each colour, plus 4 bits for the alpha channel, for a total of 16 bits per pixel. A texture stored in memory in this format will use half the size of one loaded with kTexture2DPixelFormat_RGBA8888.
For larger textures like atlases, this difference is very important. A 1024x1024 texture will use 4MB of texture memory when loaded with RGBA8888, but only 2MB of texture memory when loaded with RGBA4444!
Try to avoid using RGBA8888 unless you absolutely need the best possible quality for a particular texture. A lot of the time, you won’t even notice the difference between RGBA8888 and one of the other pixel formats. Gradients are a good example of where RGBA8888 is most useful:
To cut down on the number of times you have to set the pixel format, set it to the format you’re likely to use most often when your game starts:
[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA4444];
Then, whenever you need to change the pixel format for loading a particular texture, make sure you change it back afterwards:
[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];
CCTexture2D *texture =
[[CCTextureCache sharedTextureCache] addImage:@"buttonsatlas.png"];
[texture setAliasTexParameters];
[CCTexture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA4444];
Considering the pixel format you’ll end up using is important when planning your texture atlases. As each loaded atlas can only have one pixel format, you should try to ensure that you keep textures that require RGBA8888 together the same atlases, so you only have to use that pixel format for those textures.
A guide to the different pixel formats Cocos2d uses for textures, including hints on when to use each, appears here.
PVRTC
PVRTC is a special texture format you can use on iPhone OS devices. PVRTC textures take up less texture memory than regular textures of the same size, and can be drawn faster.
You can generate PVRTC textures from regular images using the texturetool program that comes with the Developer tools.
While PVRTC textures have some advantages, they also have one big disadvantage - compression artifacts.
The above image is probably showing the worst-case scenario - the kind of images for which PVRTC is least well suited. Space Harvest is a 2D game, so you’re basically always looking at the textures head on. Additionally, because the visual style of Space Harvest relies on crisp, non-antialiased graphics, artifacts are that much more visible.
In fact, PVRTC textures can be very useful, even in 2D games. For more detailed, anti-aliased sprites, or photorealistic textures, you might not even notice the difference. Space Harvest uses PVRTC for background images. But wherever clarity is very important, you should probably avoid them.
CCSpriteSheet
CCSpriteSheet is one way to unlock big performance improvements when drawing. Each sprite sheet has a texture atlas. When we create a sprite that uses that texture atlas, we can chose to attach our sprite to the sprite sheet by adding it as a child of the sprite sheet.
Why do this? Well, our sprite sheet will take over the drawing of our sprite. Rather than drawing each sprite individually, it will draw all sprites attached to that sprite sheet at once. This matters because one of the best ways to improve performance in an Open GL application is to cut down on the number of GL calls your code makes. Cocos2d handles most of the Open GL stuff for you, but it is helpful to have an understanding of what it’s doing behind the scenes.
Here is part of the draw method for CCSprite:
BOOL newBlend = NO;
if( blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST ) {
newBlend = YES;
glBlendFunc( blendFunc_.src, blendFunc_.dst );
}
#define kQuadSize sizeof(quad_.bl)
glBindTexture(GL_TEXTURE_2D, [texture_ name]);
int offset = (int)&quad_;
// vertex
int diff = offsetof( ccV3F_C4B_T2F, vertices);
glVertexPointer(3, GL_FLOAT, kQuadSize, (void*) (offset + diff) );
// color
diff = offsetof( ccV3F_C4B_T2F, colors);
glColorPointer(4, GL_UNSIGNED_BYTE, kQuadSize, (void*)(offset + diff));
// tex coords
diff = offsetof( ccV3F_C4B_T2F, texCoords);
glTexCoordPointer(2, GL_FLOAT, kQuadSize, (void*)(offset + diff));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if( newBlend )
glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
(Emphasis mine, obviously)
Look at the number of calls to functions that begin with ‘gl’ - 7 calls in the worst case. This code will run every time we draw a sprite that isn’t attached to a sprite sheet. If we have 100 sprites, 700 calls, or 7000 gl calls for 1000 sprites.
CCSpriteSheet’s draw method is a bit more complex, and calls a separate method on it’s texture atlas to do the drawing. For brevity, I won’t repeat it here, but it looks like it makes around 10 gl calls. But crucially, it will only make those 10 calls to draw ALL of the sprites attached to our sprite sheet - 100 sprites will be 10 calls, even with 1000 sprites, it’ll still be 10 calls. In practice, this gives you a huge boost in drawing performance.
A note about depth sorting and CCSpriteSheet
If you need to depth-sort sprites from one atlas with sprites from another, things get a bit more complex.
By default, Cocos2d renders graphics using the Painter’s Algorithm. That means that objects are drawn in the order in which they appear in their parent node’s children array. The end result is that objects at the back are drawn first, objects that appear on top of everything else are drawn last.
This presents a problem if you need some objects attached to a particular sprite sheet to be drawn in front of those from another sprite sheet, but behind others from that same sprite sheet. By default, once the sprites from the first atlas have been drawn, the sprites from the second atlas will draw over the top of them, regardless of their z position relative to their siblings.
The way around this is to use CCNode’s vertexZ property. This gives you access to Open GL’s depth buffer, which allows you to draw your sprites in any order you like, and still allow them to be correctly depth sorted in relation to one another.
The biggest downside to this approach is that it can be difficult to get semi-transparent sprites to render properly, as the object directly behind them may not have been drawn when they come to be rendered. Apple’s advice is to draw semi-transparent objects last, which in practice means you’ll need to keep their sprite sheet in a higher position in its parent’s children array.
I didn't use vertexZ for depth sorting in Space Harvest - from the couple of days I spent experimenting with it, I found lots of little side effects that made it tricky to get things working the way I wanted. Regardless, try to use CCSpriteSheet as much as you can.
Pre-render programatically generated textures if you can
Some of the effects in Space Harvest are programatically generated using Core Graphics. Many objects have animations for taking damage and being destroyed - these are created by combining different images using different blending modes:
Originally, I generated textures for destroy animations for all my sprites when starting the game. However, Core Graphics is rather slow on the iPhone platform, so I eventually moved to saving the generated images out, pasting them into to my atlases in Photoshop, and loading them as regular textures in the final version. This cut around 10 seconds(!) off startup time, so if you do have any programatically generated textures that don't change, pre-rendering them is a good way to go.
Tuesday, October 19, 2010
How To Avoid Having Your App Rejected for Core Functionality Issues and Crashing
Also, make sure you thoroughly test your application on iPhone and iPod touch in addition to the iPhone Simulator. A large percentage of applications are rejected due to various types of crashes, including crashes on launch, which would have been found and dealt with if they'd been tested on an actual device. Don't skip that step in the development process.
Tutorials for iPad Development
On this page I have decided to list tutorials specifically created for the iPad along with other resources such as user interface design tips, and graphical resources such as UI prototyping tools and vector kits.
You can expect this page to update with new tutorials and resources so be sure to bookmark it.
Newer resources appear towards the top of the listing.
1. Rapid Prototyping of iPad apps using Keynote – a great guide along with many interactive elements for prototyping (key here being interactive) using Keynote.
2. How To Port An App To the iPad – Covers how to convert your app to handle the iPad screen sizes, specifically autosizing and orientation, and when to use iPad elements.
3. Custom Input View Tutorial – A tutorial on how to create great looking custom input views on the iPad.
4. iPad Multitouch – A great example with code showing how to utilize all 11 available touches on the iPad.
5. UIPopoverController Tutorial - A tutorial on how to use the iPad UIPopoverController element.
6. iPhone To Hybrid – A guide to making apps that work on the different iOS platforms simultaneously with minimal work.
7. UISplitview Tutorial – A tutorial on how to use the specific iPad only UISplitview interface element.
8. Designing For iPad Reality Check – Brilliant in depth to guide to into how the interface of an iPad app should be developed.
9. iPad Application Design – A detailed look at some of the finer details of how to deisgn an iPad user interface.
10. iPad UI Graphic Kits - Several graphic kits for use in tools such as Photoshop and Omnigraffle.
11. Testing Out iPad Code With An iPhone or iPod Touch – Article about testing an iPad interface using the iSimulate iPhone app.
Tutorials for iPad Development
On this page I have decided to list tutorials specifically created for the iPad along with other resources such as user interface design tips, and graphical resources such as UI prototyping tools and vector kits.
You can expect this page to update with new tutorials and resources so be sure to bookmark it.
Newer resources appear towards the top of the listing.
1. Rapid Prototyping of iPad apps using Keynote – a great guide along with many interactive elements for prototyping (key here being interactive) using Keynote.
2. How To Port An App To the iPad – Covers how to convert your app to handle the iPad screen sizes, specifically autosizing and orientation, and when to use iPad elements.
3. Custom Input View Tutorial – A tutorial on how to create great looking custom input views on the iPad.
4. iPad Multitouch – A great example with code showing how to utilize all 11 available touches on the iPad.
5. UIPopoverController Tutorial - A tutorial on how to use the iPad UIPopoverController element.
6. iPhone To Hybrid – A guide to making apps that work on the different iOS platforms simultaneously with minimal work.
7. UISplitview Tutorial – A tutorial on how to use the specific iPad only UISplitview interface element.
8. Designing For iPad Reality Check – Brilliant in depth to guide to into how the interface of an iPad app should be developed.
9. iPad Application Design – A detailed look at some of the finer details of how to deisgn an iPad user interface.
10. iPad UI Graphic Kits - Several graphic kits for use in tools such as Photoshop and Omnigraffle.
11. Testing Out iPad Code With An iPhone or iPod Touch – Article about testing an iPad interface using the iSimulate iPhone app.
Open Source Game Engine Comparison for iPhone
Choosing Your Open Source iPhone Game Engine
Sparrow Framework
The Sparrow Framework is a very lightweight 2D game engine created in Objective-C. In a very short amount of time I was able to understand the framework, and I find it to be very intuitive.
If you’d like to take a look at some actual coding with the Sparrow Framework be sure to check out the Beginners iPhone Action Game Programming Tutorial.
While I have not done much Flash game programming the developers state that the game engine was created with Flash game developers in mind.
The game framework includes all the necessary features you’d require for creating a basic 2D game such as easy animation, and a sound engine.
Cocos2D IPhone
The Cocos2D iPhone game engine is a port of a game engine originally created in Python and converted to iPhone Objective-C. As you can tell from the name, Cocos2D is designed for 2D games, that being said, although the engine is in a 2D world, the engine includes a growing collection of high quality 3D special effects.
Cocos2D has been used in many games on the iPhone app store, you can visit the official site here, where many are listed.
Cocos2D is the first engine to check out, while many may be turned off by the engine not supporting a 3d world, if you look at most of the top iPhone games the gameplay is 2D, in fact the iPhone’s touch screen controls can make it difficult to operate in a 3D world.
Also included is support for the in-game Chipmunk engine, and the latest version of Cocos also includes an OpenAL based sound engine.
The engine provides more examples than any of the other engines out there because of the large community. Overall I’d say the engine is as easy to use as any engine that does not have an environment editor.
Uses the LGPL license.
Sio2Engine
The SIO2 game engine is an excellent 3D game engine written in C. There is a free oepn source version, and a an indie version for $49. The free eidtion requires you to show a splash screen at the start of your game illustrating your use of the engine. This in my opinion is extremely fair considering the quality of the engine.
The game engine uses blender in it’s toolchain for scene and model creation. If you haven’t used Blender, it is a sophisticated open source 3D modeling program. In my opinion this is the only thing I don’t really like about sio2, while some love it, I can’t stand using blender as I’ve found it can’t compare to the top commercial modeling programs. Fortunately there are many blender plugins that allow you to import a wide variety of modeling formats.
SIO2 comes with an excellent set of tutorials, and provides support for sophisticated features such as skeletal animation, and soft-body physics which are explained in the tutorials.
I’ve found the performance of the latest version of the SIO2 game engine, version 1.4 to provide significantly better performance than previous versions. If you haven’t checked out SIO2 in awhile then I suggest you check it out again.
I recommend SIO2 to those who insist on a 3D world and thus can’t use Cocos.
Oolong Engine
The Oolong game engine is a 3D engine written in C++, and provides excellent performance. The downside of the Oolong engine is that it is difficult to use for those that are not familiar with OpenGL ES.
Oolong provides support for a wide variety of features, and very good performance, as I said my only problem with Oolong is that it is difficult to use. This is a low-level engine designed for programmers so if you’re just getting into game development I would stay away.
You will find the latest version on google code, there is very little documentation for Oolong, but the community is very active, and you can get answers to many of your questions there.
I would recommend Oolong to those looking to create their own game engine looking for something to start with.
Uses the MIT license.
Irrlicht Engine
I mention Irrlicht here only because I received a message from someone stating that it was available on the iPhone. I know that it has been used in the creation of apps already available on the iPhone.
The Irrlicht game engine is a 3D game engine written in C++.
While there is no official port available on the Irrlicht website for the iPhone with some tinkering I was able to get the OpenGL ES version running on the iPhone — somewhat. You will find the OpenGL ES version hidden away in the repository.
Irrlicht is an excellent open source engine that has support for an extremely wide variety of file formats, and has the best support for the “classic” BSP format that I’ve seen in an open source game engine. There are also numerous other tools that have been created for the engine.
All this being said, I can’t recommend Irrlicht because there is no official port, and if you check out the forums there really is no one willing to provide help to those looking to get it running on the iPhone although some have created apps running on the iPhone.
The Irrlicht engine uses the Zlib license.
Summary
The Sparrow Framework makes an excellent first choice for those developing a 2D iPhone game. Cocos2D is the most popular, and has the most support but is less intuitive. You will learn Objective-C while using the engine, and the engine has been proven in a wide variety of games.
For 3D games my choice is SIO2, although I’m not a fan of blender this does make it more accessible than the other proven 3D iPhone game engines.
Sunday, October 17, 2010
Integrating AdMob with Cocos2D-iPhone Applications
AdMob is a mobile advertising network that serves ads to be displayed on mobile devices. Ads can be served via native applications or within a browser and are not limited to just smart phones. AdMob offers plenty of metrics to track the quantity of served ads, geographic region, which cellphone operator, and device type. This tutorial will provide the guidance needed to include AdMob served ads within your Cocos2D-iPhone application. This example is based upon v.82 of the Cocos2D-iPhone framework.
Your first step is to register with AdMob to get a publisher ID and input information regarding your application. Registration and eventual access to the SDK is free.
Once registered and logged in, you’re presented with a dashboard where you can track your applications. As shown in the following, I already have MyGame.
Let’s add a new site by selecting the +Add Site/App button. As shown in the following image, there are various choices available from which to publish ads. Go ahead and select iPhone App to add the application details.
Now Enter the fields in your application from admob panel. Don’t worry about the iTunes link as you can come back to add it later if the application hasn’t been published yet. You can also change the theme color, but this too can be changed later by entering your own color code values.
After selecting continue at the bottom, we can then download the SDK. Interestingly, the SDK’s sample files will come pre-populated with a newly created publisher ID for your specific application. We’ll get to that in a moment, but for now keep in mind that this ID will be unique for your application. It can also be a source of frustration as I’ve seen with other users who forget to input their ID and wonder why their application isn’t serving ads.
After selecting the download SDK button and when returning to the Sites & Apps page we see the new application has been added.
Select the setup link for your application to then view the application’s details. Again we see the particular publisher ID as well as some other features that we can control such as the types of ads we can serve. There are many ad categories, and you could find some surprising content offered up by your site.
Selecting the Category/Type Settings tab shows the various ad categories available as well as presents an ability to turn them off. Keep in mind that with so many devices offering up ads and a limited inventory of available ads, it’s not likely that you’ll consistently have a 100% fill rate. Meaning, there may be just some times that an ad may not be presented due to the lack of inventory. As a result, turning off ad categories will most likely reduce your fill rate.
Now that we have a feel for the AdMob dashboard and the various configuration capabilities, it’s time to start integrating their SDK with our application. Let’s untar the downloaded file and review the files. The following image shows the provided files and sample XCode project. Open the XCode project and take a look at the AdViewController.m file.
Upon closer inspection, we’ll see that our previously assigned Publisher ID, done at the time of the application’s creation, is pre-populated in the publisher ID string:
We’ll use this same value in a bit within our application. The AdMob ads are displayed in 320×48 UIViews and can essentially be placed anywhere. There are choices for other sizes, especially for the iPad, but for this exercise we’re going to stick with the smaller ads.
The AdMob provided README within the SDK provides the necessary details for project integration. Specifically, we start by adding the AdMob library code and headers to the XCode project. These files are contained in the AdMob subdirectory and consist of the following:
* AdMobDelegateProtocol.h
* AdMobView.h
* libAdMob.a
Quite frankly, I just dragged and dropped the AdMob folder from the sample projects into my project.
We also need to ensure the following frameworks have been added to the project.
* CoreLocation
* CoreGraphics
* QuartzCore
* AddressBook
* AudioToolbox
* MediaPlayer
Now we’re going to add the code within the class that will display the ad. For my particular case, I’m displaying ads in the main menu of Balloon-Boy as shown in the earlier image.
Add the following statements to the class header file that will display the ads. In my case I added them to my MenuScene.h.
view source
print?
1 #import "AdMobDelegateProtocol.h"
2 #import "AdMobInterstitialDelegateProtocol.h"
3 #import "AdMobInterstitialAd.h"
4 #define AD_REFRESH_PERIOD 60.0 // display fresh ads once per minute
Then we declare the following variables within the MenuScene.h.
view source
print?
1 AdMobView *adMobAd;
2 NSTimer *refreshTimer; // timer to get fresh ads
3 UIViewController *viewController;
We’ll now turn our attention to the main class file (MenuScene.m). Include the following methods within this file where the ad will be displayed. The provided comments are fairly self explanatory, and should give you an idea of what’s going on.
view source
print?
01 - (void)didReceiveAd:(AdMobView *)adView {
02 // put the ad at the top middle of the screen in landscape mode
03 adMobAd.frame = CGRectMake(0, 432, 320, 48);
04 CGAffineTransform makeLandscape = CGAffineTransformMakeRotation(M_PI * 0.5f);
05 makeLandscape = CGAffineTransformTranslate(makeLandscape, -216, -134);//centers the ad in landscape mode
06 adMobAd.transform = makeLandscape;
07 [viewController.view addSubview:adMobAd];
08 }
09
10 // Sent when an ad request failed to load an ad
11 - (void)didFailToReceiveAd:(AdMobView *)adView {
12 NSLog(@"AdMob: Did fail to receive ad in AdViewController");
13 [adMobAd release];
14 adMobAd = nil;
15 }
16
17 - (void)onEnter {
18 viewController = [[UIViewController alloc] init];
19 viewController.view = [[CCDirector sharedDirector] openGLView];
20 adMobAd = [AdMobView requestAdOfSize:ADMOB_SIZE_320x48 withDelegate:self];
21 [adMobAd retain]; // this will be released when it loads (or fails to load)
22 [super onEnter];
23 }
24
25 - (void)onExit {
26 [adMobAd removeFromSuperview];
27 [adMobAd release];
28 [super onExit];
29 }
30
31 // Request a new ad. If a new ad is successfully loaded, it will be animated into location.
32 - (void)refreshAd:(NSTimer *)timer {
33 [adMobAd requestFreshAd];
34 }
35
36 // AdMobDelegate methods
37 - (NSString *)publisherIdForAd: (AdmobView *)adView {
38 return @"a14b19f75680944"; // this is your publisher ID
39 }
40
41 - (UIViewController *)currentViewControllerForAd:(AdMobView *)adView {
42 return viewController;
43 }
44
45 - (UIColor *)adBackgroundColor {
46 return [UIColor colorWithRed:0 green:0.749 blue:1 alpha:1]; // this should be prefilled; if not, provide a UIColor
47 }
48
49 - (UIColor *)primaryTextColor {
50 return [UIColor colorWithRed:0 green:0 blue:0 alpha:1]; // this should be prefilled; if not, provide a UIColor
51 }
52
53 - (UIColor *)secondaryTextColor {
54 return [UIColor colorWithRed:0 green:0 blue:0 alpha:1]; // this should be prefilled; if not, provide a UIColor
55 }
56
57 - (BOOL)mayAskForLocation {
58 return NO; // this should be prefilled; if not, see AdMobProtocolDelegate.h for instructions
59 }
If all went as planned, this newly added code should now display a rotated ad at the top middle of your view in landscape mode.
As an aside, some people have experienced an error when attempting to integrate the AdMob code within their project. The error message speaks to a duplication issue and is as follows:
ld: duplicate symbol .objc_category_name_NSCharacterSet_NSCharacterSet_Extensions in /Users/Home/Documents/Xcode/MyCrazyProject/AdMob/libAdMobDeviceNoThumb.a(NSCharacterSet_Extensions.o) and /Users/Home/Documents/Xcode/MyCrazyProject/build/Distribution-iphoneos/libcocos2d libraries.a(NSCharacterSet_Extensions.o)
Online discussion has attributed this error to both AdMob and Cocos2D referencing the same library, which in this case is TouchJSON. As a result, some people have indicated that simply deleting TouchJSON directory from the Cocos2D package has solved the problem. I have not experienced this error while running under v.82 of Cocos2D so can not definitively say why it shows up every once in a while.
Additionally, other users have also experienced problems when using CocosLive. Since now they needed the TouchJSON library, they were forced to rename all of the classes in it so as to avoid conflict with AdMob.
AdMob Metrics
Now’s probably a good time to also explain some of the metrics and terms regarding online advertising. The following image shows an example report for what was my newly released Balloon-Boy application. Upon close inspection, you can see it shows the break down for activity by country. As discussed earlier about available ad inventory, we can see that the application had made nearly 2,900 ad requests. But it was fulfilled for about 2700 of them (impressions). Out of all of those impressions there were 41 clicks. Interestingly, the Asian market had a much higher click through rate as well as provided a much higher payout as measured by the eCPM. The CPM acronym is derived from the latin version of the phrase “cost per mille” where “mille” in English means “thousand.”
The eCPM value is calculated by the following:
Total Earnings/Impressions * 1,000 = eCPM
The idea is to easily allow for comparison of values to see how effective a campaign is. For us on the receiving end, it’s easy to see that the payout in Asia was much higher. The advertisers looked to be more willing to pay more per click as well as the ads were well targeted given the high click through rate.
This concludes the Integrating AdMob with Cocos2D-iPhone Applications tutorial. I hope that the knowledge will be useful.
Friday, October 15, 2010
OpenFeint Integration with cocos2d
OpenFeint is a service that enables your iPhone/iPod Touch application the ability to provide online score tracking. The service is free and can easily be incorporated into your applications. This tutorial will cover the integration of OpenFeint 2.4.3 with the Cocos2D-iPhone framework. Before getting started, it is assumed that you already have familiarity with:
* Objective-C
* XCode
* Cocos2D-iPhone framework
The expectation is that you already have a working Cocos2D based application to which you’d like to enable leaderboard functionality. If you’re new to Cocos2D-iPhone, then you should visit http://www.cocos2d-iphone.org to review the available documentation and download the latest framework. You do not have to be a seasoned veteran to use Cocos2D, and the framework makes it very easy to create high quality games. At the time of this writing, version 8.2 of the Cocos2D-iPhone framework was the most stable version, and hence it provides the basis for this tutorial.
There are several features available within OpenFeint in terms of score and event management. Beyond just tracking high scores, the developer can establish goals such that the player can earn achievements or even initiate online challenges. For this tutorial, the focus will be to simply enable an online leaderboard. The player will be able to track their own progress as well as compare their scores against other players via a global leaderboard.
There is also the ability to enable a chat function between players. While I have not tried it, I have been told by other developers that by enabling this feature you’re required to assign a mature rating. The mentality is that unrestricted chat within a game could expose minors to unscrupulous users and content.
Access to the OpenFeint code is done through the OpenFeint developer portal, and there is no charge to enroll in the developer program. Visit http://www.openfeint.com/ to sign-up for access.
Once authenticated with the portal, you’ll have access to the developer home page and will be able to download the OpenFeint SDK.
When enabling an application to use the OpenFeint service, you register it within the developer portal. Selecting the green plus button at the top of the page allows you to start this process. In this example we’ll add a test application, My Crazy App, so that you can see the various screens. Yet, the specific code examples shown later on will reflect the integration process with one of my OpenFeint enabled games.
After selecting submit, the application is given a Client Application ID, Product Key, and Product Secret. As we’ll later see, these values are needed when initializing OpenFeint within our application. Keep them handy as we’ll need them when it comes time to add the respective OpenFeint code to the application.
Create your leaderboards from Leaderboard link in OpenFeint Left side menu.
Now that we’ve enrolled in the OpenFeint program, downloaded the SDK, and created an entry for our application, it is time to start the integrating process within our Cocos2D-iPhone application.
There are some preliminary steps before inclusion of code within your class files. If you’re upgrading from a prior version, the process is relatively straight forward. You simply delete the old OpenFeint folder from your XCode project and need to ensure that you add some additional frameworks, which will be detailed in the following section. Note: it is also important that you go into your project’s directory and also delete both the OpenFeint and build directories.
Let’s review the the OpenFeint README.txt for information on integration of the application.
If you’ve downloaded and extracted the OpenFeint SDK, you’re ready to begin the process. For step 4 of the README file, we’re to drop the unzipped OpenFeint folder into our XCode project. And since the game is landscape only, we’ll remove the Portrait folder found under the Resources directory as suggested for step 5. The following shows the inclusion of the OpenFeint folder within our XCode project.
Continuing on with Step 6, we right click on our project icon within XCode and select Get Info. In looking at the build tab, we added the Linker Flags the value -ObjC as well as selected ‘Call C++ Default Ctors/Dtors in Objective-C’. These are shown in the following screen capture.
For step 7, the README.txt notes the following frameworks that must be included within the project. And if you’re like me, I can never remember the all too convenient path so here it is for reference. Right click on frameworks and add existing framework. Navigate to:
/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulatorx.y.z.sdk/System/Library/Frameworks/
Here are the frameworks you’ll need to ensure you’ve included in your XCode project.
* Foundation
* UIKit
* CoreGraphics
* QuartzCore
* Security
* SystemConfiguration
* libsql3.0.dylib (located in (iPhoneSDK Folder)/usr/lib/)
* CFNetwork
* CoreLocation
* MapKit (if building with SDK 3.0 or newer)
And here we see the frameworks that have been added to the XCode project.
For the latest release of OpenFeint, if you have set your ‘iPhoneOS Deployment Target’ to any version before 3.0 you must weak link some libraries. Select ‘Targets’ in the Groups & Files pane.
* Right click your target and select Get Info.
* Select the ‘General’ tab.
* Under ‘Linked Libraries’ change the following libraries from ‘Required’ to ‘Weak’
* UIKit
* MapKit
For my project I’m not building for lesser versions, which from what I’ve heard though does exclude a sizable base of users.
Finally, in step 9 of the README.txt, we need to add the following line to our prefix header:
#import "OpenFeintPrefix.pch"
At this point we now have the SDK integrated within our XCode project along with some necessary support requirements. Again, this tutorial covers the specific integration of OpenFeint with a Cocs2D-iPhone v8.2 based application. As with most application architectures, there will be various class files such as the application delegate, game scene, and menu scene.
Let’s now add the required OpenFeint code to our project’s AppDelegate.
Within the AppDelegate’s main file we’ll add various code elements ranging from importing other class headers to specific code needed within existing methods. For example, there’s specific OpenFeint code that should be added to applicationWillResignActive, applicationDidBecomeActive, and applicationWillTerminate. These methods can already be found in your Cocos2D application delegate, and we’ll be adding a line here or there to support integration with OpenFeint. The OpenFeint developer documentation details these requirements as it’s expected that you’re taking action based upon the application’s state, such as it shutting down.
Add the following import statements to your AppDelegate’s main file:
#import "OpenFeint.h"
#import "MyOFDelegate.h"
Now locate the respective methods within your AppDelegate’s main file, and add the lines identified for OpenFeint.
- (void)applicationWillResignActive:(UIApplication *)application {
[[SimpleAudioEngine sharedEngine] stopBackgroundMusic];
[[Director sharedDirector] pause];
[OpenFeint applicationWillResignActive]; // Add for OpenFeint
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[[Director sharedDirector] resume];
[OpenFeint applicationDidBecomeActive]; // Add for OpenFeint
}
- (void)applicationWillTerminate:(UIApplication *)application {
[[SimpleAudioEngine sharedEngine] stopBackgroundMusic];
[[Director sharedDirector] end];
[[NSUserDefaults standardUserDefaults] synchronize]; // Add for OpenFeint
}
Next we’ll create a class that will handle some crucial tasks whenever we call the OpenFeint leaderboard. At the time, I had based this on the included MyOFDelegate files. Pay particular attention to the dashboardDidAppear and dashboardDidDisappear methods. You’ll see that we’re momentarily pausing the Cocos2D director and then re-enabling it once the dashboard disappears. This is a critical step cause otherwise it’s possible that input will be inconsistent or even not captured when the dashboard is displayed. But by pausing the director, we’re ensured that all user input is captured by the dashboard.
Create the following files within your XCode project.
MyOFDelegate.h
//
// MyOFDelegate.h
// MyGame
//
#import "OpenFeintDelegate.h"
@interface MyOFDelegate : NSObject<>
- (void)dashboardWillAppear;
- (void)dashboardDidAppear;
- (void)dashboardWillDisappear;
- (void)dashboardDidDisappear;
- (void)userLoggedIn:(NSString*)userId;
- (BOOL)showCustomOpenFeintApprovalScreen;
@end
MyOFDelegate.m
// MyOFDelegate.m
#import "OpenFeint.h"
#import "MyOFDelegate.h"
#import "cocos2d.h"
@implementation MyOFDelegate
- (void)dashboardWillAppear
{
}
- (void)dashboardDidAppear
{
[[Director sharedDirector] pause];
[[Director sharedDirector] stopAnimation];
}
- (void)dashboardWillDisappear
{
}
- (void)dashboardDidDisappear
{
[[Director sharedDirector] resume];
[[Director sharedDirector] startAnimation];
}
- (void)userLoggedIn:(NSString*)userId
{
OFLog(@"New user logged in! Hello %@", [OpenFeint lastLoggedInUserName]);
}
- (BOOL)showCustomOpenFeintApprovalScreen
{
return NO;
}
@end
For my particular Cocos2D application, I have a splash scene that quickly shows the company logo, the Cocos2D logo, and then transitions to the game’s main menu. I initialize OpenFeint during this process just before loading the main menu. With that said, the header file for the splash scene class has the following code. We’re including the MyOFDelegate class as well as declaring the ofDelegate variable. I’ve streamlined the content to only include the references to the OpenFeint code. I’ve left the reference to the menuScene method though as that’s where I perform the initialization.
// SplashScene.h
// Balloon-Boy
//
// Created by Tim Sills on 12/1/09.
//
#import
#import "cocos2d.h"
@class MyOFDelegate; // Add for OpenFeint
@interface SplashScene : Scene {
MyOFDelegate *ofDelegate; // Add for OpenFeint
}
-(void)menuScene;
@end
For the main file of the splash scene class, we import the following header files:
#import "OpenFeint.h"
#import "MyOFDelegate.h"
For the initialization process, we declare a dictionary that will include the details specific to our application. Where ever it is you want to perform the initialization within your application, add the following code.
NSDictionary* settings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight], OpenFeintSettingDashboardOrientation, [NSNumber numberWithBool:YES],
OpenFeintSettingDisableUserGeneratedContent, nil];
ofDelegate = [MyOFDelegate new];
OFDelegatesContainer* delegates = [OFDelegatesContainer containerWithOpenFeintDelegate:ofDelegate];
[OpenFeint initializeWithProductKey:@"aMMPDEYldUia4j86uV1mK"
andSecret:@"PMjb1n9dV4MVO09U05R56MUCeJf7VZHnKlQIvRKtn"
andDisplayName:@"My Game"
andSettings:settings // see OpenFeintSettings.h
andDelegates:delegates]; // see OFDelegatesContainer.h
For my particular application, once the initialization has been done, it then transitions to the main menu. If you’re already a registered user you’ll get the welcome back screen or if you’re a new user (or perhaps using a new device), you’ll have the opportunity to either login or register for a new account.
When a user selects the Scores option at the main menu, the following line of of code is executed within the called method. Take note of the text passed text value. This is the lD for our leaderboard that was assigned at the time of creation, which in this case is reflecting the value for the test application registered for this tutorial.
[OpenFeint launchDashboardWithHighscorePage:(NSString*)@"124567"];
The code is pretty self explanatory and launches the high score dashboard for our application. You also have the option of defaulting to other screens when initially launching the OpenFeint dashboard, so be sure to check the SDK for such details.
This all sounds great, but the next question is how do we post these scores to OpenFeint? The process is incredibly simple. For my Balloon-Boy game, after the user’s piloted balloon has had three impacts, the game is over. At this point I give the player the opportunity to play again, but when this method is initially called, I execute the following bit of code to post the user’s score. In particular, I have a variable named currentScore that contains the user’s accumulated score. The currentScore’s value is posted to the OpenFeint leaderboard. It is also important to note the leaderboard ID again. This is the same value given to us when we first created the leaderboard in the developer portal. The leaderboard details are provided again for reference in the following screen capture.
The leaderboard ID is used to identify the specific board for the application that’ll receive the value. The following shows the single line of code used to post the current score to the appropriate leaderboard for our application.
[OFHighScoreService setHighScore:currentScore forLeaderboard:@"124567 " onSuccess:OFDelegate() onFailure:OFDelegate()];The following screen capture shows in my application where the user is presented with the opportunity to either play again or return to the main menu. When this overlay is initially shown, there is a brief confirmation message shown at the bottom of the screen as the score is posted to the OpenFeint leaderboard.
The integration process is nearly complete with only some minor additional changes required. In order to compile the OpenFeint C code, we have to change the extension all of our main class files from .m to .mm. Meaning, gameScene.m now becomes gameScene.mm. There’s no impact to the existing Objetive-C code, but if not done then there will be a lot of problems when attempting to compile the code otherwise.
If you like this article please bookmark us. We will come soon with new article which helps you to develop your games in iPhone.
What's new in iPhone 4.0
This article summarizes the developer-related features introduced in iPhone OS 4.0. This version of the operating system runs on iPhone and iPod touch only and does not run on iPad. In addition to describing the new features, this article lists the documents that describe those features in more detail.
Note: iPhone OS 4.0 does not support iPad. It runs only on iPhone and iPod touch devices.
For the latest updates and information, you should also see iPhone OS 4.0 Release Notes. For the list of API differences between the iPhone OS 4.0 and earlier versions of iPhone OS, see iPhone OS 4.0 API Diffs.
Here are some new feature which added in iPhone 4.0
1. Multitasking
2. Integration Technology
2.1 Local Notification
2.2 Event Kit
2.3 Core Motion
2.4 Data Protection
2.5 Core Telephony
2.6 iAd
3. Graphics and Multimedia
3.1 High Resolution Screen Support
3.2 Quick Look Framework
3.3 AV Foundation
3.4 Asset Library
3.5 Image I/O
3.6 Core Media
3.7 Core Video
4. Core Services
4.1 Block Objects
4.2 Grand Central Dispatch
4.3 Accelerate Framework
5. XCode Tools
5.1 XCode Improvements
5.2 UI Automation API
6. Framework Enhancements
6.1 UIKit Framework Enhancement
6.2 Found Framework Enhancement
6.3 Game Kit Enhancement
6.4 Core Location Enhancement
6.5 Map Kit Enhancement
6.6 Message UI Enhancement
6.7 Core Graphics Enhancement
6.8 ICU Enhancement
7. Inherited Improvement
We can discuss this features in detail later.