Introducing New Cocos2D Sample Game: Tom the Turret

Ray Wenderlich
This turret has gained self awareness!

This turret has gained self awareness!

This is just a quite note to let you guys know about a new Cocos2D sample game out there for you guys to check out – and it comes with the latest beta version of Cocos2D!

The game is called Tom the Turret and is about a turret who gains self-awareness in an apocolyptic future. It’s a shooter in the style of the How To Make A Simple iPhone Game With Cocos2D Tutorial, and features multiple levels and endings!

Steve Oldmeadow and I wrote this project to demonstrate how to use the CocosDenshion sound library, and to give an example of how to put together some of the concepts from the tutorials on this site into a complete game. The art was made by my lovely wife, as usual!

What Does it Include?

Tom the Turret demonstrates how to do the following in a simple game with Cocos2D:

  • How to use the CocosDenshion sound engine effectively
  • How to have multiple scenes (loading scene, main menu, story scene, action scene)
  • How to have multiple levels and monsters
  • How to shoot in 360°
  • How to draw health bars
  • How to use Spritesheets and animations (I’ll be posting a tutorial on this soon btw!)
  • And much more!

So be sure to check it out – and choose your favorite ending!

Tom the Turret Screenshot: Level 2

How Do I Get It?

Simply download a copy of Cocos2D 0.99.4-beta that was recently released by riq.

Open up the cocos2d-iphone.xcodeproj, set your Active Target and Active Executable to “CocosDenshion – Tom the Turret”, compile, run, and enjoy!

Questions, Comments?

After you check out the project, if you have any questions or would like anything explained, feel free to post below!

Steve Oldmeadow may be writing some notes about the audio implementation in this game on the Cocos2D forums and the Cocos2D wiki, so stay tuned there as well!

Ray Wenderlich

Ray is an indie software developer currently focusing on iPhone and iPad development, and the administrator of this site. He’s the founder of a small iPhone development studio called Razeware, and is passionate both about making apps and teaching others the techniques to make them.

When Ray’s not programming, he’s probably playing video games, role playing games, or board games.

User Comments

5 Comments

  • Hi Ray,

    Great game, thanks. I'm using your source code combined with a bunch of your tutorials as a guide to build my own game. I'm looking at the LoadingScene class. I want to load PVR files as the batchNodes/spritesheets, I've got it working like this...
    Code: Select all

    //
    [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA4444];
    [CCTexture2D PVRImagesHavePremultipliedAlpha:YES];
    [[CCTextureCache sharedTextureCache] addImageAsync:@"level1objects.pvr.ccz" target:self selector:@selector(onTextureLoaded:)];

    //then on the selector method
    -(void) onTextureLoaded: (CCTexture2D*) texture {
       
        // Store sprite texture in cache and initialize sprite frames
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"level1objects.plist"];
       
        // Add a sprite sheet based on the loaded texture and add it to the scene
        self.batchNode = [CCSpriteBatchNode batchNodeWithTexture:texture];
        [self addChild:batchNode];
       
        self.imagesLoaded = YES;
       
    }



    ..but have noticed there is an 'addPVRImage' method in CCTextureCache. So my question/s are..
    1. Does using the 'addImageAsync' method with a PVR file negate any compression/performance benefits of using PVRs (or cause any other known issues)?
    2. If so, how do I get a selector to trigger on the completion of files loaded via the addPVRImage method?
    3. Also, I'd like to include an extra argument with the selector (for addImageAsync or addPVRImage if possible), so I can pass the plist filename string (eg. @"level1objects.plist") with the selector (along with the texture)...I want to do this so i can iterate through an array of multiple PVRs and Plists). How would you go about this?

    Thanks for all the help so far (tutorials and sourcecode), any further help on the above would be amazing, thanks!
    staticfiction
  • @staticfriction: I just looked through the Cocos2D source to answer your question. Here's what I found:

    1) When you call addImageAsync on CCTextureCache, it schedules the addImageWithAsyncObject selector to be run on another thread.
    2) The addImageWithAsyncObject method calls addImage (still in CCTextureCache)
    3) addImage switches to do different things based on whether it's a pvr (addPVRImage) or not

    So you should be able to use the addImageAsync with PVRs, no problem.

    I'm not sure what you mean by your last question. If you wanted to iterate through an array of images, why not just create a for loop and call addImageAsync multiple times, generating each image name inside the for loop?
    rwenderlich
  • Thanks Ray, that's cleared things up :)

    In a related issue, I've been trying to get a better understanding of memory allocation when working with cocos2D spritesheets. I was hoping you could please confirm/correct me on my findings.

    (sorry about the length of my post but I've spent a substantial amount of time testing this (and variations of) and it's still not making sense)

    I've setup a basic testing class (CCLayer) that looks like this...
    Code: Select all

    -(id) init
    {
       if( (self=[super init])) {
           
          self.isTouchEnabled = YES;
                    [[CCTextureCache sharedTextureCache] addImageAsync:@"welderSpriteSheet.pvr.ccz" target:self selector:@selector(onSpritesLoaded:)];
           
       }
       return self;
    }

    -(void) onSpritesLoaded: (CCTexture2D*) texture {
       
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"welderSpriteSheet.plist"];
       
        // Add a sprite sheet based on the loaded texture and add it to the scene
        self.batchNode = [CCSpriteBatchNode batchNodeWithTexture:texture];
        [self addChild:batchNode];
       
        // Add "tap to continue" sprite...
        CGSize winSize = [CCDirector sharedDirector].winSize;
        //welder.png is a spriteFrame in welderSpriteSheet.plist
        self.tapToCont = [CCSprite spriteWithSpriteFrameName:@"welder.png"];
        tapToCont.position = ccp((winSize.width/2), (winSize.height/2));
        [batchNode addChild:tapToCont];
       
       
    }
    -(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
       
        [batchNode removeChild:tapToCont cleanup:YES];
        self.tapToCont = nil;

        //Check to be sure caches contain textures/sprites
        NSLog(@"TOUCH pre cleanup - textureForKey: %@", [[CCTextureCache sharedTextureCache] textureForKey:@"welderSpriteSheet.pvr.ccz"]);
        //logs (<CCTexture2D = 00227FD0 | Name = 2 | Dimensions = 1024x1024 | Coordinates = (1.00, 1.00)>)
        NSLog(@"TOUCH pre cleanup - spriteFrameByName: %@", [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"welder.png"]);   
        //logs (<CCSpriteFrame = 0021FA80 | TextureName=2, Rect = (0.00,0.00,1024.00,1024.00)> rotated:0)

        [[CCSpriteFrameCache sharedSpriteFrameCache] removeSpriteFramesFromFile:@"welderSpriteSheet.plist"];
        [[CCTextureCache sharedTextureCache] removeTextureForKey:@"welderSpriteSheet.pvr.ccz"];
       
        //check to be sure textures/sprites have been removed
        NSLog(@"TOUCH post cleanup - textureForKey: %@", [[CCTextureCache sharedTextureCache] textureForKey:@"welderSpriteSheet.pvr.ccz"]); //logs (null)
        NSLog(@"TOUCH post cleanup - spriteFrameByName: %@", [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"welder.png"]); //logs (null)
    }

    In ref. the above code:
    'welderSpriteSheet.pvr.ccz' is a 1024x1024px, 3.2MB file and it contains 1 single image 'welder.png' (which is also 1024x1024px) created with Texture Packer.

    So basically, it loads a texture, adds the batchnode and sprite frame. Then on the touch, removes all and attempts to clean up any memory left behind.

    I've profiled this using Instruments>Allocations, this is what It reports (when looking at the visual graph and the 'Live bytes' column)...
    There's a spike of around 8mb at the start then it quickly drops to around 825kb.
    It remains at 825kb until you touch, at which time it drops to 824kb (only 1kb drop!)

    So what I make of this is the 8mb spike is cocos2D importing/converting the texture and storing it in it's cache (along with any standard cocos2d startup/init processes)
    The drop to 825kb is cocos2D discarding the memory used for the above processes (texture importing/startup etc).
    The 1kb drop (when touched) is the CCTextureCache and CCSpriteFrameCache emptying.

    Now the fact that it's only dropping 1kb when emptying a cache that should contain a (converted) 3.2mb texture is a little confusing. This would suggest that cocos2D is converting a compressed 3.2mb pvr file into 1kb of cached memory...surely not! What am I missing here?

    please note: have also tried methods such as purgeCachedData, purgeSharedSpriteFrameCache, removeUnusedSpriteFrames, removeUnusedTextures. All give very similar results.

    Sorry again for the length of this post and thanks in advance for any light you (or anyone else) can shed on this.
    staticfiction
  • @staticfriction: Here's how I remove the textures after using them in Wild Fables:

    Code: Select all
    CCTexture2D *texture = batchNode.textureAtlas.texture;
    [[CCSpriteFrameCache sharedSpriteFrameCache] removeSpriteFramesFromTexture:texture];
    [[CCTextureCache sharedTextureCache] removeTexture:texture];


    I remember profiling this while I was developing Wild Fables to make sure it was actually being released, and it was. Try this and let me know if it works out for you.

    Also, you might find Cocos2D's new texture cache debugging feature useful (look here for Texture Cache):

    http://www.cocos2d-iphone.org/wiki/doku ... otes:1_0_0
    rwenderlich
  • Thanks Ray, I tried your approach + latest cocos2D, it appears to produce the same results. I've gone ahead with development of my game using the same approach anyway. Have profiled in Instruments. In particular to this issue, I've been taking heapshots via Allocations to view heaped growth of the app. All appears to be performing as intended (no unwanted growth) so that's awesome. For Anyone with a similar issue, I'd recommend watching the 'Advanced Memory Analysis with Instruments' Video on Apple's WWDC 2010 archive - http://developer.apple.com/videos/wwdc/2010/ (you'll need to be registered with apple dev program to access). I found this video, combined with Ray's memory debug tut, to be very helpful with this issue. Cheers.
    staticfiction

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in July: Facebook Pop Tech Talk!

Sign Up - July

RWDevCon Conference?

We are considering having an official raywenderlich.com conference called RWDevCon in DC in early 2015.

The conference would be focused on high quality Swift/iOS 8 technical content, and connecting as a community.

Would this be something you'd be interested in?

    Loading ... Loading ...

Our Books

Our Team

Tutorial Team

  • Matt Galloway

... 50 total!

Update Team

  • Riccardo D'Antoni
  • Andy Pereira

Editorial Team

... 23 total!

Code Team

  • Orta Therox

... 1 total!

Translation Team

  • Heejun Han
  • Team Tyran

... 33 total!

Subject Matter Experts

... 4 total!